Add webhook show, return info and some fixes

* Added a webhook show command. This gives us info about the webhook and
    if it is installed.
  * Return webhook info when installing the webhook
  * Small typo fixes.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
Gabriel Adrian Samfira 2023-08-16 09:11:45 +00:00
parent 6051fa016c
commit 779afe980e
No known key found for this signature in database
GPG key ID: 7D073DCC2C074CB5
27 changed files with 1253 additions and 66 deletions

View file

@ -43,21 +43,21 @@ import (
func (a *APIController) CreateOrgHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var repoData runnerParams.CreateOrgParams
if err := json.NewDecoder(r.Body).Decode(&repoData); err != nil {
var orgData runnerParams.CreateOrgParams
if err := json.NewDecoder(r.Body).Decode(&orgData); err != nil {
handleError(w, gErrors.ErrBadRequest)
return
}
repo, err := a.r.CreateOrganization(ctx, repoData)
org, err := a.r.CreateOrganization(ctx, orgData)
if err != nil {
log.Printf("error creating repository: %+v", err)
log.Printf("error creating organization: %+v", err)
handleError(w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(repo); err != nil {
if err := json.NewEncoder(w).Encode(org); err != nil {
log.Printf("failed to encode response: %q", err)
}
}
@ -344,9 +344,9 @@ func (a *APIController) ListOrgPoolsHandler(w http.ResponseWriter, r *http.Reque
func (a *APIController) GetOrgPoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
orgID, repoOk := vars["orgID"]
orgID, orgOk := vars["orgID"]
poolID, poolOk := vars["poolID"]
if !repoOk || !poolOk {
if !orgOk || !poolOk {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
@ -499,7 +499,7 @@ func (a *APIController) UpdateOrgPoolHandler(w http.ResponseWriter, r *http.Requ
// required: true
//
// Responses:
// 200:
// 200: HookInfo
// default: APIErrorResponse
func (a *APIController) InstallOrgWebhookHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
@ -524,14 +524,17 @@ func (a *APIController) InstallOrgWebhookHandler(w http.ResponseWriter, r *http.
return
}
if err := a.r.InstallOrgWebhook(ctx, orgID, hookParam); err != nil {
info, err := a.r.InstallOrgWebhook(ctx, orgID, hookParam)
if err != nil {
log.Printf("installing webhook: %s", err)
handleError(w, err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(info); err != nil {
log.Printf("failed to encode response: %q", err)
}
}
// swagger:route DELETE /organizations/{orgID}/webhook organizations hooks UninstallOrgWebhook
@ -572,3 +575,46 @@ func (a *APIController) UninstallOrgWebhookHandler(w http.ResponseWriter, r *htt
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route GET /organizations/{orgID}/webhook organizations hooks GetOrgWebhookInfo
//
// Get information about the GARM installed webhook on an organization.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: HookInfo
// default: APIErrorResponse
func (a *APIController) GetOrgWebhookInfoHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
orgID, orgOk := vars["orgID"]
if !orgOk {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No org ID specified",
}); err != nil {
log.Printf("failed to encode response: %q", err)
}
return
}
info, err := a.r.GetOrgWebhookInfo(ctx, orgID)
if err != nil {
log.Printf("getting webhook info: %s", err)
handleError(w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(info); err != nil {
log.Printf("failed to encode response: %q", err)
}
}

View file

@ -499,7 +499,7 @@ func (a *APIController) UpdateRepoPoolHandler(w http.ResponseWriter, r *http.Req
// required: true
//
// Responses:
// 200:
// 200: HookInfo
// default: APIErrorResponse
func (a *APIController) InstallRepoWebhookHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
@ -524,14 +524,17 @@ func (a *APIController) InstallRepoWebhookHandler(w http.ResponseWriter, r *http
return
}
if err := a.r.InstallRepoWebhook(ctx, repoID, hookParam); err != nil {
info, err := a.r.InstallRepoWebhook(ctx, repoID, hookParam)
if err != nil {
log.Printf("installing webhook: %s", err)
handleError(w, err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(info); err != nil {
log.Printf("failed to encode response: %q", err)
}
}
// swagger:route DELETE /repositories/{repoID}/webhook repositories hooks UninstallRepoWebhook
@ -572,3 +575,46 @@ func (a *APIController) UninstallRepoWebhookHandler(w http.ResponseWriter, r *ht
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route GET /repositories/{repoID}/webhook repositories hooks GetRepoWebhookInfo
//
// Get information about the GARM installed webhook on a repository.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: HookInfo
// default: APIErrorResponse
func (a *APIController) GetRepoWebhookInfoHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
repoID, orgOk := vars["repoID"]
if !orgOk {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No repository ID specified",
}); err != nil {
log.Printf("failed to encode response: %q", err)
}
return
}
info, err := a.r.GetRepoWebhookInfo(ctx, repoID)
if err != nil {
log.Printf("getting webhook info: %s", err)
handleError(w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(info); err != nil {
log.Printf("failed to encode response: %q", err)
}
}

View file

@ -210,6 +210,9 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
// Uninstall Webhook
apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.UninstallRepoWebhookHandler)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.UninstallRepoWebhookHandler)).Methods("DELETE", "OPTIONS")
// Get webhook info
apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.GetRepoWebhookInfoHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.GetRepoWebhookInfoHandler)).Methods("GET", "OPTIONS")
/////////////////////////////
// Organizations and pools //
@ -256,6 +259,9 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
// Uninstall Webhook
apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.UninstallOrgWebhookHandler)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.UninstallOrgWebhookHandler)).Methods("DELETE", "OPTIONS")
// Get webhook info
apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.GetOrgWebhookInfoHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.GetOrgWebhookInfoHandler)).Methods("GET", "OPTIONS")
/////////////////////////////
// Enterprises and pools //

View file

@ -8,6 +8,13 @@ definitions:
import:
package: github.com/cloudbase/garm/params
alias: garm_params
HookInfo:
type: object
x-go-type:
type: HookInfo
import:
package: github.com/cloudbase/garm/params
alias: garm_params
ControllerInfo:
type: object
x-go-type:

View file

@ -76,6 +76,13 @@ definitions:
alias: garm_params
package: github.com/cloudbase/garm/params
type: GithubCredentials
HookInfo:
type: object
x-go-type:
import:
alias: garm_params
package: github.com/cloudbase/garm/params
type: HookInfo
InstallWebhookParams:
type: object
x-go-type:
@ -925,6 +932,27 @@ paths:
tags:
- organizations
- hooks
get:
operationId: GetOrgWebhookInfo
parameters:
- description: Organization ID.
in: path
name: orgID
required: true
type: string
responses:
"200":
description: HookInfo
schema:
$ref: '#/definitions/HookInfo'
default:
description: APIErrorResponse
schema:
$ref: '#/definitions/APIErrorResponse'
summary: Get information about the GARM installed webhook on an organization.
tags:
- organizations
- hooks
post:
description: |-
Install the GARM webhook for an organization. The secret configured on the organization will
@ -946,7 +974,9 @@ paths:
type: object
responses:
"200":
description: ""
description: HookInfo
schema:
$ref: '#/definitions/HookInfo'
default:
description: APIErrorResponse
schema:
@ -1347,6 +1377,27 @@ paths:
tags:
- repositories
- hooks
get:
operationId: GetRepoWebhookInfo
parameters:
- description: Repository ID.
in: path
name: repoID
required: true
type: string
responses:
"200":
description: HookInfo
schema:
$ref: '#/definitions/HookInfo'
default:
description: APIErrorResponse
schema:
$ref: '#/definitions/APIErrorResponse'
summary: Get information about the GARM installed webhook on a repository.
tags:
- repositories
- hooks
post:
description: |-
Install the GARM webhook for an organization. The secret configured on the organization will
@ -1368,7 +1419,9 @@ paths:
type: object
responses:
"200":
description: ""
description: HookInfo
schema:
$ref: '#/definitions/HookInfo'
default:
description: APIErrorResponse
schema:

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package organizations
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewGetOrgWebhookInfoParams creates a new GetOrgWebhookInfoParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewGetOrgWebhookInfoParams() *GetOrgWebhookInfoParams {
return &GetOrgWebhookInfoParams{
timeout: cr.DefaultTimeout,
}
}
// NewGetOrgWebhookInfoParamsWithTimeout creates a new GetOrgWebhookInfoParams object
// with the ability to set a timeout on a request.
func NewGetOrgWebhookInfoParamsWithTimeout(timeout time.Duration) *GetOrgWebhookInfoParams {
return &GetOrgWebhookInfoParams{
timeout: timeout,
}
}
// NewGetOrgWebhookInfoParamsWithContext creates a new GetOrgWebhookInfoParams object
// with the ability to set a context for a request.
func NewGetOrgWebhookInfoParamsWithContext(ctx context.Context) *GetOrgWebhookInfoParams {
return &GetOrgWebhookInfoParams{
Context: ctx,
}
}
// NewGetOrgWebhookInfoParamsWithHTTPClient creates a new GetOrgWebhookInfoParams object
// with the ability to set a custom HTTPClient for a request.
func NewGetOrgWebhookInfoParamsWithHTTPClient(client *http.Client) *GetOrgWebhookInfoParams {
return &GetOrgWebhookInfoParams{
HTTPClient: client,
}
}
/*
GetOrgWebhookInfoParams contains all the parameters to send to the API endpoint
for the get org webhook info operation.
Typically these are written to a http.Request.
*/
type GetOrgWebhookInfoParams struct {
/* OrgID.
Organization ID.
*/
OrgID string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the get org webhook info params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetOrgWebhookInfoParams) WithDefaults() *GetOrgWebhookInfoParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the get org webhook info params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetOrgWebhookInfoParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the get org webhook info params
func (o *GetOrgWebhookInfoParams) WithTimeout(timeout time.Duration) *GetOrgWebhookInfoParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the get org webhook info params
func (o *GetOrgWebhookInfoParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the get org webhook info params
func (o *GetOrgWebhookInfoParams) WithContext(ctx context.Context) *GetOrgWebhookInfoParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the get org webhook info params
func (o *GetOrgWebhookInfoParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the get org webhook info params
func (o *GetOrgWebhookInfoParams) WithHTTPClient(client *http.Client) *GetOrgWebhookInfoParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the get org webhook info params
func (o *GetOrgWebhookInfoParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithOrgID adds the orgID to the get org webhook info params
func (o *GetOrgWebhookInfoParams) WithOrgID(orgID string) *GetOrgWebhookInfoParams {
o.SetOrgID(orgID)
return o
}
// SetOrgID adds the orgId to the get org webhook info params
func (o *GetOrgWebhookInfoParams) SetOrgID(orgID string) {
o.OrgID = orgID
}
// WriteToRequest writes these params to a swagger request
func (o *GetOrgWebhookInfoParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param orgID
if err := r.SetPathParam("orgID", o.OrgID); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package organizations
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// GetOrgWebhookInfoReader is a Reader for the GetOrgWebhookInfo structure.
type GetOrgWebhookInfoReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *GetOrgWebhookInfoReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewGetOrgWebhookInfoOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewGetOrgWebhookInfoDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewGetOrgWebhookInfoOK creates a GetOrgWebhookInfoOK with default headers values
func NewGetOrgWebhookInfoOK() *GetOrgWebhookInfoOK {
return &GetOrgWebhookInfoOK{}
}
/*
GetOrgWebhookInfoOK describes a response with status code 200, with default header values.
HookInfo
*/
type GetOrgWebhookInfoOK struct {
Payload garm_params.HookInfo
}
// IsSuccess returns true when this get org webhook info o k response has a 2xx status code
func (o *GetOrgWebhookInfoOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this get org webhook info o k response has a 3xx status code
func (o *GetOrgWebhookInfoOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this get org webhook info o k response has a 4xx status code
func (o *GetOrgWebhookInfoOK) IsClientError() bool {
return false
}
// IsServerError returns true when this get org webhook info o k response has a 5xx status code
func (o *GetOrgWebhookInfoOK) IsServerError() bool {
return false
}
// IsCode returns true when this get org webhook info o k response a status code equal to that given
func (o *GetOrgWebhookInfoOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the get org webhook info o k response
func (o *GetOrgWebhookInfoOK) Code() int {
return 200
}
func (o *GetOrgWebhookInfoOK) Error() string {
return fmt.Sprintf("[GET /organizations/{orgID}/webhook][%d] getOrgWebhookInfoOK %+v", 200, o.Payload)
}
func (o *GetOrgWebhookInfoOK) String() string {
return fmt.Sprintf("[GET /organizations/{orgID}/webhook][%d] getOrgWebhookInfoOK %+v", 200, o.Payload)
}
func (o *GetOrgWebhookInfoOK) GetPayload() garm_params.HookInfo {
return o.Payload
}
func (o *GetOrgWebhookInfoOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewGetOrgWebhookInfoDefault creates a GetOrgWebhookInfoDefault with default headers values
func NewGetOrgWebhookInfoDefault(code int) *GetOrgWebhookInfoDefault {
return &GetOrgWebhookInfoDefault{
_statusCode: code,
}
}
/*
GetOrgWebhookInfoDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type GetOrgWebhookInfoDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this get org webhook info default response has a 2xx status code
func (o *GetOrgWebhookInfoDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this get org webhook info default response has a 3xx status code
func (o *GetOrgWebhookInfoDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this get org webhook info default response has a 4xx status code
func (o *GetOrgWebhookInfoDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this get org webhook info default response has a 5xx status code
func (o *GetOrgWebhookInfoDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this get org webhook info default response a status code equal to that given
func (o *GetOrgWebhookInfoDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the get org webhook info default response
func (o *GetOrgWebhookInfoDefault) Code() int {
return o._statusCode
}
func (o *GetOrgWebhookInfoDefault) Error() string {
return fmt.Sprintf("[GET /organizations/{orgID}/webhook][%d] GetOrgWebhookInfo default %+v", o._statusCode, o.Payload)
}
func (o *GetOrgWebhookInfoDefault) String() string {
return fmt.Sprintf("[GET /organizations/{orgID}/webhook][%d] GetOrgWebhookInfo default %+v", o._statusCode, o.Payload)
}
func (o *GetOrgWebhookInfoDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *GetOrgWebhookInfoDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -13,6 +13,7 @@ import (
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// InstallOrgWebhookReader is a Reader for the InstallOrgWebhook structure.
@ -49,9 +50,10 @@ func NewInstallOrgWebhookOK() *InstallOrgWebhookOK {
/*
InstallOrgWebhookOK describes a response with status code 200, with default header values.
InstallOrgWebhookOK install org webhook o k
HookInfo
*/
type InstallOrgWebhookOK struct {
Payload garm_params.HookInfo
}
// IsSuccess returns true when this install org webhook o k response has a 2xx status code
@ -85,15 +87,24 @@ func (o *InstallOrgWebhookOK) Code() int {
}
func (o *InstallOrgWebhookOK) Error() string {
return fmt.Sprintf("[POST /organizations/{orgID}/webhook][%d] installOrgWebhookOK ", 200)
return fmt.Sprintf("[POST /organizations/{orgID}/webhook][%d] installOrgWebhookOK %+v", 200, o.Payload)
}
func (o *InstallOrgWebhookOK) String() string {
return fmt.Sprintf("[POST /organizations/{orgID}/webhook][%d] installOrgWebhookOK ", 200)
return fmt.Sprintf("[POST /organizations/{orgID}/webhook][%d] installOrgWebhookOK %+v", 200, o.Payload)
}
func (o *InstallOrgWebhookOK) GetPayload() garm_params.HookInfo {
return o.Payload
}
func (o *InstallOrgWebhookOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -40,6 +40,8 @@ type ClientService interface {
GetOrgPool(params *GetOrgPoolParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetOrgPoolOK, error)
GetOrgWebhookInfo(params *GetOrgWebhookInfoParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetOrgWebhookInfoOK, error)
InstallOrgWebhook(params *InstallOrgWebhookParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*InstallOrgWebhookOK, error)
ListOrgInstances(params *ListOrgInstancesParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListOrgInstancesOK, error)
@ -273,6 +275,44 @@ func (a *Client) GetOrgPool(params *GetOrgPoolParams, authInfo runtime.ClientAut
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
GetOrgWebhookInfo gets information about the g a r m installed webhook on an organization
*/
func (a *Client) GetOrgWebhookInfo(params *GetOrgWebhookInfoParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetOrgWebhookInfoOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewGetOrgWebhookInfoParams()
}
op := &runtime.ClientOperation{
ID: "GetOrgWebhookInfo",
Method: "GET",
PathPattern: "/organizations/{orgID}/webhook",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &GetOrgWebhookInfoReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*GetOrgWebhookInfoOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*GetOrgWebhookInfoDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
InstallOrgWebhook Install the GARM webhook for an organization. The secret configured on the organization will

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package repositories
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewGetRepoWebhookInfoParams creates a new GetRepoWebhookInfoParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewGetRepoWebhookInfoParams() *GetRepoWebhookInfoParams {
return &GetRepoWebhookInfoParams{
timeout: cr.DefaultTimeout,
}
}
// NewGetRepoWebhookInfoParamsWithTimeout creates a new GetRepoWebhookInfoParams object
// with the ability to set a timeout on a request.
func NewGetRepoWebhookInfoParamsWithTimeout(timeout time.Duration) *GetRepoWebhookInfoParams {
return &GetRepoWebhookInfoParams{
timeout: timeout,
}
}
// NewGetRepoWebhookInfoParamsWithContext creates a new GetRepoWebhookInfoParams object
// with the ability to set a context for a request.
func NewGetRepoWebhookInfoParamsWithContext(ctx context.Context) *GetRepoWebhookInfoParams {
return &GetRepoWebhookInfoParams{
Context: ctx,
}
}
// NewGetRepoWebhookInfoParamsWithHTTPClient creates a new GetRepoWebhookInfoParams object
// with the ability to set a custom HTTPClient for a request.
func NewGetRepoWebhookInfoParamsWithHTTPClient(client *http.Client) *GetRepoWebhookInfoParams {
return &GetRepoWebhookInfoParams{
HTTPClient: client,
}
}
/*
GetRepoWebhookInfoParams contains all the parameters to send to the API endpoint
for the get repo webhook info operation.
Typically these are written to a http.Request.
*/
type GetRepoWebhookInfoParams struct {
/* RepoID.
Repository ID.
*/
RepoID string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the get repo webhook info params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetRepoWebhookInfoParams) WithDefaults() *GetRepoWebhookInfoParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the get repo webhook info params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetRepoWebhookInfoParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the get repo webhook info params
func (o *GetRepoWebhookInfoParams) WithTimeout(timeout time.Duration) *GetRepoWebhookInfoParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the get repo webhook info params
func (o *GetRepoWebhookInfoParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the get repo webhook info params
func (o *GetRepoWebhookInfoParams) WithContext(ctx context.Context) *GetRepoWebhookInfoParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the get repo webhook info params
func (o *GetRepoWebhookInfoParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the get repo webhook info params
func (o *GetRepoWebhookInfoParams) WithHTTPClient(client *http.Client) *GetRepoWebhookInfoParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the get repo webhook info params
func (o *GetRepoWebhookInfoParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithRepoID adds the repoID to the get repo webhook info params
func (o *GetRepoWebhookInfoParams) WithRepoID(repoID string) *GetRepoWebhookInfoParams {
o.SetRepoID(repoID)
return o
}
// SetRepoID adds the repoId to the get repo webhook info params
func (o *GetRepoWebhookInfoParams) SetRepoID(repoID string) {
o.RepoID = repoID
}
// WriteToRequest writes these params to a swagger request
func (o *GetRepoWebhookInfoParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param repoID
if err := r.SetPathParam("repoID", o.RepoID); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package repositories
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// GetRepoWebhookInfoReader is a Reader for the GetRepoWebhookInfo structure.
type GetRepoWebhookInfoReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *GetRepoWebhookInfoReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewGetRepoWebhookInfoOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewGetRepoWebhookInfoDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewGetRepoWebhookInfoOK creates a GetRepoWebhookInfoOK with default headers values
func NewGetRepoWebhookInfoOK() *GetRepoWebhookInfoOK {
return &GetRepoWebhookInfoOK{}
}
/*
GetRepoWebhookInfoOK describes a response with status code 200, with default header values.
HookInfo
*/
type GetRepoWebhookInfoOK struct {
Payload garm_params.HookInfo
}
// IsSuccess returns true when this get repo webhook info o k response has a 2xx status code
func (o *GetRepoWebhookInfoOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this get repo webhook info o k response has a 3xx status code
func (o *GetRepoWebhookInfoOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this get repo webhook info o k response has a 4xx status code
func (o *GetRepoWebhookInfoOK) IsClientError() bool {
return false
}
// IsServerError returns true when this get repo webhook info o k response has a 5xx status code
func (o *GetRepoWebhookInfoOK) IsServerError() bool {
return false
}
// IsCode returns true when this get repo webhook info o k response a status code equal to that given
func (o *GetRepoWebhookInfoOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the get repo webhook info o k response
func (o *GetRepoWebhookInfoOK) Code() int {
return 200
}
func (o *GetRepoWebhookInfoOK) Error() string {
return fmt.Sprintf("[GET /repositories/{repoID}/webhook][%d] getRepoWebhookInfoOK %+v", 200, o.Payload)
}
func (o *GetRepoWebhookInfoOK) String() string {
return fmt.Sprintf("[GET /repositories/{repoID}/webhook][%d] getRepoWebhookInfoOK %+v", 200, o.Payload)
}
func (o *GetRepoWebhookInfoOK) GetPayload() garm_params.HookInfo {
return o.Payload
}
func (o *GetRepoWebhookInfoOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewGetRepoWebhookInfoDefault creates a GetRepoWebhookInfoDefault with default headers values
func NewGetRepoWebhookInfoDefault(code int) *GetRepoWebhookInfoDefault {
return &GetRepoWebhookInfoDefault{
_statusCode: code,
}
}
/*
GetRepoWebhookInfoDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type GetRepoWebhookInfoDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this get repo webhook info default response has a 2xx status code
func (o *GetRepoWebhookInfoDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this get repo webhook info default response has a 3xx status code
func (o *GetRepoWebhookInfoDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this get repo webhook info default response has a 4xx status code
func (o *GetRepoWebhookInfoDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this get repo webhook info default response has a 5xx status code
func (o *GetRepoWebhookInfoDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this get repo webhook info default response a status code equal to that given
func (o *GetRepoWebhookInfoDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the get repo webhook info default response
func (o *GetRepoWebhookInfoDefault) Code() int {
return o._statusCode
}
func (o *GetRepoWebhookInfoDefault) Error() string {
return fmt.Sprintf("[GET /repositories/{repoID}/webhook][%d] GetRepoWebhookInfo default %+v", o._statusCode, o.Payload)
}
func (o *GetRepoWebhookInfoDefault) String() string {
return fmt.Sprintf("[GET /repositories/{repoID}/webhook][%d] GetRepoWebhookInfo default %+v", o._statusCode, o.Payload)
}
func (o *GetRepoWebhookInfoDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *GetRepoWebhookInfoDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -13,6 +13,7 @@ import (
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// InstallRepoWebhookReader is a Reader for the InstallRepoWebhook structure.
@ -49,9 +50,10 @@ func NewInstallRepoWebhookOK() *InstallRepoWebhookOK {
/*
InstallRepoWebhookOK describes a response with status code 200, with default header values.
InstallRepoWebhookOK install repo webhook o k
HookInfo
*/
type InstallRepoWebhookOK struct {
Payload garm_params.HookInfo
}
// IsSuccess returns true when this install repo webhook o k response has a 2xx status code
@ -85,15 +87,24 @@ func (o *InstallRepoWebhookOK) Code() int {
}
func (o *InstallRepoWebhookOK) Error() string {
return fmt.Sprintf("[POST /repositories/{repoID}/webhook][%d] installRepoWebhookOK ", 200)
return fmt.Sprintf("[POST /repositories/{repoID}/webhook][%d] installRepoWebhookOK %+v", 200, o.Payload)
}
func (o *InstallRepoWebhookOK) String() string {
return fmt.Sprintf("[POST /repositories/{repoID}/webhook][%d] installRepoWebhookOK ", 200)
return fmt.Sprintf("[POST /repositories/{repoID}/webhook][%d] installRepoWebhookOK %+v", 200, o.Payload)
}
func (o *InstallRepoWebhookOK) GetPayload() garm_params.HookInfo {
return o.Payload
}
func (o *InstallRepoWebhookOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -40,6 +40,8 @@ type ClientService interface {
GetRepoPool(params *GetRepoPoolParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetRepoPoolOK, error)
GetRepoWebhookInfo(params *GetRepoWebhookInfoParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetRepoWebhookInfoOK, error)
InstallRepoWebhook(params *InstallRepoWebhookParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*InstallRepoWebhookOK, error)
ListRepoInstances(params *ListRepoInstancesParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListRepoInstancesOK, error)
@ -273,6 +275,44 @@ func (a *Client) GetRepoPool(params *GetRepoPoolParams, authInfo runtime.ClientA
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
GetRepoWebhookInfo gets information about the g a r m installed webhook on a repository
*/
func (a *Client) GetRepoWebhookInfo(params *GetRepoWebhookInfoParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetRepoWebhookInfoOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewGetRepoWebhookInfoParams()
}
op := &runtime.ClientOperation{
ID: "GetRepoWebhookInfo",
Method: "GET",
PathPattern: "/repositories/{repoID}/webhook",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &GetRepoWebhookInfoReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*GetRepoWebhookInfoOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*GetRepoWebhookInfoDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
InstallRepoWebhook Install the GARM webhook for an organization. The secret configured on the organization will

View file

@ -76,10 +76,39 @@ var orgWebhookInstallCmd = &cobra.Command{
installWebhookReq.Body.InsecureSSL = insecureOrgWebhook
installWebhookReq.Body.WebhookEndpointType = params.WebhookEndpointDirect
_, err := apiCli.Organizations.InstallOrgWebhook(installWebhookReq, authToken)
response, err := apiCli.Organizations.InstallOrgWebhook(installWebhookReq, authToken)
if err != nil {
return err
}
formatOneHookInfo(response.Payload)
return nil
},
}
var orgHookInfoShowCmd = &cobra.Command{
Use: "show",
Short: "Show webhook info",
Long: `Show webhook info for an organization.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
if len(args) == 0 {
return fmt.Errorf("requires an organization ID")
}
if len(args) > 1 {
return fmt.Errorf("too many arguments")
}
showWebhookInfoReq := apiClientOrgs.NewGetOrgWebhookInfoParams()
showWebhookInfoReq.OrgID = args[0]
response, err := apiCli.Organizations.GetOrgWebhookInfo(showWebhookInfoReq, authToken)
if err != nil {
return err
}
formatOneHookInfo(response.Payload)
return nil
},
}
@ -266,6 +295,7 @@ func init() {
orgWebhookCmd.AddCommand(
orgWebhookInstallCmd,
orgWebhookUninstallCmd,
orgHookInfoShowCmd,
)
organizationCmd.AddCommand(

View file

@ -77,10 +77,39 @@ var repoWebhookInstallCmd = &cobra.Command{
installWebhookReq.Body.InsecureSSL = insecureRepoWebhook
installWebhookReq.Body.WebhookEndpointType = params.WebhookEndpointDirect
_, err := apiCli.Repositories.InstallRepoWebhook(installWebhookReq, authToken)
response, err := apiCli.Repositories.InstallRepoWebhook(installWebhookReq, authToken)
if err != nil {
return err
}
formatOneHookInfo(response.Payload)
return nil
},
}
var repoHookInfoShowCmd = &cobra.Command{
Use: "show",
Short: "Show webhook info",
Long: `Show webhook info for a repository.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
if len(args) == 0 {
return fmt.Errorf("requires a repository ID")
}
if len(args) > 1 {
return fmt.Errorf("too many arguments")
}
showWebhookInfoReq := apiClientRepos.NewGetRepoWebhookInfoParams()
showWebhookInfoReq.RepoID = args[0]
response, err := apiCli.Repositories.GetRepoWebhookInfo(showWebhookInfoReq, authToken)
if err != nil {
return err
}
formatOneHookInfo(response.Payload)
return nil
},
}
@ -271,6 +300,7 @@ func init() {
repoWebhookCmd.AddCommand(
repoWebhookInstallCmd,
repoWebhookUninstallCmd,
repoHookInfoShowCmd,
)
repositoryCmd.AddCommand(

View file

@ -21,7 +21,9 @@ import (
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"
@ -98,3 +100,17 @@ func initConfig() {
}
initApiClient(mgr.BaseURL, mgr.Token)
}
func formatOneHookInfo(hook params.HookInfo) {
t := table.NewWriter()
header := table.Row{"Field", "Value"}
t.AppendHeader(header)
t.AppendRows([]table.Row{
{"ID", hook.ID},
{"URL", hook.URL},
{"Events", hook.Events},
{"Active", hook.Active},
{"Insecure SSL", hook.InsecureSSL},
})
fmt.Println(t.Render())
}

View file

@ -505,3 +505,11 @@ type InstallWebhookParams struct {
WebhookEndpointType WebhookEndpointType `json:"webhook_endpoint_type"`
InsecureSSL bool `json:"insecure_ssl"`
}
type HookInfo struct {
ID int64 `json:"id"`
URL string `json:"url"`
Events []string `json:"events"`
Active bool `json:"active"`
InsecureSSL bool `json:"insecure_ssl"`
}

View file

@ -28,6 +28,30 @@ func (_m *PoolManager) ForceDeleteRunner(runner params.Instance) error {
return r0
}
// GetWebhookInfo provides a mock function with given fields: ctx
func (_m *PoolManager) GetWebhookInfo(ctx context.Context) (params.HookInfo, error) {
ret := _m.Called(ctx)
var r0 params.HookInfo
var r1 error
if rf, ok := ret.Get(0).(func(context.Context) (params.HookInfo, error)); ok {
return rf(ctx)
}
if rf, ok := ret.Get(0).(func(context.Context) params.HookInfo); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(params.HookInfo)
}
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GithubRunnerRegistrationToken provides a mock function with given fields:
func (_m *PoolManager) GithubRunnerRegistrationToken() (string, error) {
ret := _m.Called()
@ -81,17 +105,27 @@ func (_m *PoolManager) ID() string {
}
// InstallWebhook provides a mock function with given fields: ctx, param
func (_m *PoolManager) InstallWebhook(ctx context.Context, param params.InstallWebhookParams) error {
func (_m *PoolManager) InstallWebhook(ctx context.Context, param params.InstallWebhookParams) (params.HookInfo, error) {
ret := _m.Called(ctx, param)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, params.InstallWebhookParams) error); ok {
var r0 params.HookInfo
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, params.InstallWebhookParams) (params.HookInfo, error)); ok {
return rf(ctx, param)
}
if rf, ok := ret.Get(0).(func(context.Context, params.InstallWebhookParams) params.HookInfo); ok {
r0 = rf(ctx, param)
} else {
r0 = ret.Error(0)
r0 = ret.Get(0).(params.HookInfo)
}
return r0
if rf, ok := ret.Get(1).(func(context.Context, params.InstallWebhookParams) error); ok {
r1 = rf(ctx, param)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// RefreshState provides a mock function with given fields: param

View file

@ -44,7 +44,9 @@ type PoolManager interface {
HandleWorkflowJob(job params.WorkflowJob) error
RefreshState(param params.UpdatePoolStateParams) error
ForceDeleteRunner(runner params.Instance) error
InstallWebhook(ctx context.Context, param params.InstallWebhookParams) error
InstallWebhook(ctx context.Context, param params.InstallWebhookParams) (params.HookInfo, error)
GetWebhookInfo(ctx context.Context) (params.HookInfo, error)
UninstallWebhook(ctx context.Context) error
// PoolManager lifecycle functions. Start/stop pool.

View file

@ -340,25 +340,26 @@ func (r *Runner) findOrgPoolManager(name string) (common.PoolManager, error) {
return poolManager, nil
}
func (r *Runner) InstallOrgWebhook(ctx context.Context, orgID string, param params.InstallWebhookParams) error {
func (r *Runner) InstallOrgWebhook(ctx context.Context, orgID string, param params.InstallWebhookParams) (params.HookInfo, error) {
if !auth.IsAdmin(ctx) {
return runnerErrors.ErrUnauthorized
return params.HookInfo{}, runnerErrors.ErrUnauthorized
}
org, err := r.store.GetOrganizationByID(ctx, orgID)
if err != nil {
return errors.Wrap(err, "fetching org")
return params.HookInfo{}, errors.Wrap(err, "fetching org")
}
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
if err != nil {
return errors.Wrap(err, "fetching pool manager for org")
return params.HookInfo{}, errors.Wrap(err, "fetching pool manager for org")
}
if err := poolMgr.InstallWebhook(ctx, param); err != nil {
return errors.Wrap(err, "installing webhook")
info, err := poolMgr.InstallWebhook(ctx, param)
if err != nil {
return params.HookInfo{}, errors.Wrap(err, "installing webhook")
}
return nil
return info, nil
}
func (r *Runner) UninstallOrgWebhook(ctx context.Context, orgID string) error {
@ -381,3 +382,25 @@ func (r *Runner) UninstallOrgWebhook(ctx context.Context, orgID string) error {
}
return nil
}
func (r *Runner) GetOrgWebhookInfo(ctx context.Context, orgID string) (params.HookInfo, error) {
if !auth.IsAdmin(ctx) {
return params.HookInfo{}, runnerErrors.ErrUnauthorized
}
org, err := r.store.GetOrganizationByID(ctx, orgID)
if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching org")
}
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching pool manager for org")
}
info, err := poolMgr.GetWebhookInfo(ctx)
if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching webhook info")
}
return info, nil
}

63
runner/pool/common.go Normal file
View file

@ -0,0 +1,63 @@
package pool
import (
"net/url"
"strings"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
"github.com/google/go-github/v53/github"
"github.com/pkg/errors"
)
func validateHookRequest(controllerID, baseURL string, allHooks []*github.Hook, req *github.Hook) error {
parsed, err := url.Parse(baseURL)
if err != nil {
return errors.Wrap(err, "parsing webhook url")
}
partialMatches := []string{}
for _, hook := range allHooks {
hookURL, ok := hook.Config["url"].(string)
if !ok {
continue
}
hookURL = strings.ToLower(hookURL)
if hook.Config["url"] == req.Config["url"] {
return runnerErrors.NewConflictError("hook already installed")
} else if strings.Contains(hookURL, controllerID) || strings.Contains(hookURL, parsed.Hostname()) {
partialMatches = append(partialMatches, hook.Config["url"].(string))
}
}
if len(partialMatches) > 0 {
return runnerErrors.NewConflictError("a webhook containing the controller ID or hostname of this contreoller is already installed on this repository")
}
return nil
}
func hookToParamsHookInfo(hook *github.Hook) params.HookInfo {
var hookURL string
url, ok := hook.Config["url"]
if ok {
hookURL = url.(string)
}
var insecureSSL bool
insecureSSLConfig, ok := hook.Config["insecure_ssl"]
if ok {
if insecureSSLConfig.(string) == "1" {
insecureSSL = true
}
}
return params.HookInfo{
ID: *hook.ID,
URL: hookURL,
Events: hook.Events,
Active: *hook.Active,
InsecureSSL: insecureSSL,
}
}

View file

@ -224,10 +224,14 @@ func (r *enterprise) ID() string {
return r.id
}
func (r *enterprise) InstallHook(ctx context.Context, req *github.Hook) error {
return fmt.Errorf("not implemented")
func (r *enterprise) InstallHook(ctx context.Context, req *github.Hook) (params.HookInfo, error) {
return params.HookInfo{}, fmt.Errorf("not implemented")
}
func (r *enterprise) UninstallHook(ctx context.Context, url string) error {
return fmt.Errorf("not implemented")
}
func (r *enterprise) GetHookInfo(ctx context.Context) (params.HookInfo, error) {
return params.HookInfo{}, fmt.Errorf("not implemented")
}

View file

@ -31,8 +31,9 @@ type poolHelper interface {
RemoveGithubRunner(runnerID int64) (*github.Response, error)
FetchTools() ([]*github.RunnerApplicationDownload, error)
InstallHook(ctx context.Context, req *github.Hook) error
InstallHook(ctx context.Context, req *github.Hook) (params.HookInfo, error)
UninstallHook(ctx context.Context, url string) error
GetHookInfo(ctx context.Context) (params.HookInfo, error)
GithubCLI() common.GithubClient

View file

@ -265,23 +265,22 @@ func (r *organization) listHooks(ctx context.Context) ([]*github.Hook, error) {
return allHooks, nil
}
func (r *organization) InstallHook(ctx context.Context, req *github.Hook) error {
func (r *organization) InstallHook(ctx context.Context, req *github.Hook) (params.HookInfo, error) {
allHooks, err := r.listHooks(ctx)
if err != nil {
return errors.Wrap(err, "listing hooks")
return params.HookInfo{}, errors.Wrap(err, "listing hooks")
}
for _, hook := range allHooks {
if hook.Config["url"] == req.Config["url"] {
return runnerErrors.NewBadRequestError("hook already installed")
}
if err := validateHookRequest(r.cfgInternal.ControllerID, r.cfgInternal.BaseWebhookURL, allHooks, req); err != nil {
return params.HookInfo{}, errors.Wrap(err, "validating hook request")
}
_, _, err = r.ghcli.CreateOrgHook(ctx, r.cfg.Name, req)
hook, _, err := r.ghcli.CreateOrgHook(ctx, r.cfg.Name, req)
if err != nil {
return errors.Wrap(err, "creating organization hook")
return params.HookInfo{}, errors.Wrap(err, "creating organization hook")
}
return nil
return hookToParamsHookInfo(hook), nil
}
func (r *organization) UninstallHook(ctx context.Context, url string) error {
@ -301,3 +300,19 @@ 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)
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) {
return hookInfo, nil
}
}
return params.HookInfo{}, runnerErrors.NewNotFoundError("hook not found")
}

View file

@ -1607,9 +1607,9 @@ func (r *basePoolManager) consumeQueuedJobs() error {
return nil
}
func (r *basePoolManager) InstallWebhook(ctx context.Context, param params.InstallWebhookParams) error {
func (r *basePoolManager) InstallWebhook(ctx context.Context, param params.InstallWebhookParams) (params.HookInfo, error) {
if r.urls.controllerWebhookURL == "" {
return errors.Wrap(runnerErrors.ErrBadRequest, "controller webhook url is empty")
return params.HookInfo{}, errors.Wrap(runnerErrors.ErrBadRequest, "controller webhook url is empty")
}
insecureSSL := "0"
@ -1639,3 +1639,7 @@ func (r *basePoolManager) UninstallWebhook(ctx context.Context) error {
return r.helper.UninstallHook(ctx, r.urls.controllerWebhookURL)
}
func (r *basePoolManager) GetWebhookInfo(ctx context.Context) (params.HookInfo, error) {
return r.helper.GetHookInfo(ctx)
}

View file

@ -266,23 +266,22 @@ func (r *repository) listHooks(ctx context.Context) ([]*github.Hook, error) {
return allHooks, nil
}
func (r *repository) InstallHook(ctx context.Context, req *github.Hook) error {
func (r *repository) InstallHook(ctx context.Context, req *github.Hook) (params.HookInfo, error) {
allHooks, err := r.listHooks(ctx)
if err != nil {
return errors.Wrap(err, "listing hooks")
return params.HookInfo{}, errors.Wrap(err, "listing hooks")
}
for _, hook := range allHooks {
if hook.Config["url"] == req.Config["url"] {
return runnerErrors.NewBadRequestError("hook already installed")
}
if err := validateHookRequest(r.cfgInternal.ControllerID, r.cfgInternal.BaseWebhookURL, allHooks, req); err != nil {
return params.HookInfo{}, errors.Wrap(err, "validating hook request")
}
_, _, err = r.ghcli.CreateRepoHook(ctx, r.cfg.Owner, r.cfg.Name, req)
hook, _, err := r.ghcli.CreateRepoHook(ctx, r.cfg.Owner, r.cfg.Name, req)
if err != nil {
return errors.Wrap(err, "creating repository hook")
return params.HookInfo{}, errors.Wrap(err, "creating repository hook")
}
return nil
return hookToParamsHookInfo(hook), nil
}
func (r *repository) UninstallHook(ctx context.Context, url string) error {
@ -302,3 +301,18 @@ func (r *repository) UninstallHook(ctx context.Context, url string) error {
}
return nil
}
func (r *repository) GetHookInfo(ctx context.Context) (params.HookInfo, error) {
allHooks, err := r.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) {
return hookInfo, nil
}
}
return params.HookInfo{}, runnerErrors.NewNotFoundError("hook not found")
}

View file

@ -350,25 +350,26 @@ func (r *Runner) findRepoPoolManager(owner, name string) (common.PoolManager, er
return poolManager, nil
}
func (r *Runner) InstallRepoWebhook(ctx context.Context, repoID string, param params.InstallWebhookParams) error {
func (r *Runner) InstallRepoWebhook(ctx context.Context, repoID string, param params.InstallWebhookParams) (params.HookInfo, error) {
if !auth.IsAdmin(ctx) {
return runnerErrors.ErrUnauthorized
return params.HookInfo{}, runnerErrors.ErrUnauthorized
}
repo, err := r.store.GetRepositoryByID(ctx, repoID)
if err != nil {
return errors.Wrap(err, "fetching repo")
return params.HookInfo{}, errors.Wrap(err, "fetching repo")
}
poolManager, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
if err != nil {
return errors.Wrap(err, "fetching pool manager for repo")
return params.HookInfo{}, errors.Wrap(err, "fetching pool manager for repo")
}
if err := poolManager.InstallWebhook(ctx, param); err != nil {
return errors.Wrap(err, "installing webhook")
info, err := poolManager.InstallWebhook(ctx, param)
if err != nil {
return params.HookInfo{}, errors.Wrap(err, "installing webhook")
}
return nil
return info, nil
}
func (r *Runner) UninstallRepoWebhook(ctx context.Context, repoID string) error {
@ -391,3 +392,25 @@ func (r *Runner) UninstallRepoWebhook(ctx context.Context, repoID string) error
}
return nil
}
func (r *Runner) GetRepoWebhookInfo(ctx context.Context, repoID string) (params.HookInfo, error) {
if !auth.IsAdmin(ctx) {
return params.HookInfo{}, runnerErrors.ErrUnauthorized
}
repo, err := r.store.GetRepositoryByID(ctx, repoID)
if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching repo")
}
poolManager, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching pool manager for repo")
}
info, err := poolManager.GetWebhookInfo(ctx)
if err != nil {
return params.HookInfo{}, errors.Wrap(err, "getting webhook info")
}
return info, nil
}