Runners now send status messages
This commit is contained in:
parent
6bdb8cd78b
commit
2bd128af13
22 changed files with 741 additions and 105 deletions
|
|
@ -449,3 +449,96 @@ func (a *APIController) UpdateRepoPoolHandler(w http.ResponseWriter, r *http.Req
|
|||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(pool)
|
||||
}
|
||||
|
||||
func (a *APIController) ListRepoInstancesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vars := mux.Vars(r)
|
||||
repoID, ok := vars["repoID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No repo ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
instances, err := a.r.ListRepoInstances(ctx, repoID)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %+v", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(instances)
|
||||
}
|
||||
|
||||
func (a *APIController) ListPoolInstancesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vars := mux.Vars(r)
|
||||
poolID, ok := vars["poolID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No repo ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
instances, err := a.r.ListPoolInstances(ctx, poolID)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %+v", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(instances)
|
||||
}
|
||||
|
||||
func (a *APIController) GetInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vars := mux.Vars(r)
|
||||
instanceName, ok := vars["instanceName"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No repo ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
instance, err := a.r.GetInstance(ctx, instanceName)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %+v", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(instance)
|
||||
}
|
||||
|
||||
func (a *APIController) InstanceStatusMessageHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var updateMessage runnerParams.InstanceUpdateMessage
|
||||
if err := json.NewDecoder(r.Body).Decode(&updateMessage); err != nil {
|
||||
log.Printf("failed to decode: %+v", err)
|
||||
handleError(w, gErrors.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Update body is: %v", updateMessage)
|
||||
if err := a.r.AddInstanceStatusMessage(ctx, updateMessage); err != nil {
|
||||
log.Printf("error saving status message: %+v", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"runner-manager/auth"
|
||||
)
|
||||
|
||||
func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddleware, initMiddleware auth.Middleware) *mux.Router {
|
||||
func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddleware, initMiddleware, instanceMiddleware auth.Middleware) *mux.Router {
|
||||
router := mux.NewRouter()
|
||||
log := gorillaHandlers.CombinedLoggingHandler
|
||||
|
||||
|
|
@ -28,6 +28,11 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
|
|||
firstRunRouter := apiSubRouter.PathPrefix("/first-run").Subrouter()
|
||||
firstRunRouter.Handle("/", log(os.Stdout, http.HandlerFunc(han.FirstRunHandler))).Methods("POST", "OPTIONS")
|
||||
|
||||
// Instance callback
|
||||
callbackRouter := apiSubRouter.PathPrefix("/callbacks").Subrouter()
|
||||
callbackRouter.Handle("/status/", log(os.Stdout, http.HandlerFunc(han.InstanceStatusMessageHandler))).Methods("POST", "OPTIONS")
|
||||
callbackRouter.Handle("/status", log(os.Stdout, http.HandlerFunc(han.InstanceStatusMessageHandler))).Methods("POST", "OPTIONS")
|
||||
callbackRouter.Use(instanceMiddleware.Middleware)
|
||||
// Login
|
||||
authRouter := apiSubRouter.PathPrefix("/auth").Subrouter()
|
||||
authRouter.Handle("/{login:login\\/?}", log(os.Stdout, http.HandlerFunc(han.LoginHandler))).Methods("POST", "OPTIONS")
|
||||
|
|
@ -37,6 +42,17 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
|
|||
apiRouter.Use(initMiddleware.Middleware)
|
||||
apiRouter.Use(authMiddleware.Middleware)
|
||||
|
||||
// Runners (instances)
|
||||
// List pool instances
|
||||
apiRouter.Handle("/pools/instances/{poolID}/", log(os.Stdout, http.HandlerFunc(han.ListPoolInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/pools/instances/{poolID}", log(os.Stdout, http.HandlerFunc(han.ListPoolInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
// Get instance
|
||||
apiRouter.Handle("/instances/{instanceName}/", log(os.Stdout, http.HandlerFunc(han.GetInstanceHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/instances/{instanceName}", log(os.Stdout, http.HandlerFunc(han.GetInstanceHandler))).Methods("GET", "OPTIONS")
|
||||
// Delete instance
|
||||
// apiRouter.Handle("/instances/{instanceName}/", log(os.Stdout, http.HandlerFunc(han.CatchAll))).Methods("DELETE", "OPTIONS")
|
||||
// apiRouter.Handle("/instances/{instanceName}", log(os.Stdout, http.HandlerFunc(han.CatchAll))).Methods("DELETE", "OPTIONS")
|
||||
|
||||
/////////////////////
|
||||
// Repos and pools //
|
||||
/////////////////////
|
||||
|
|
@ -56,6 +72,10 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
|
|||
apiRouter.Handle("/repositories/{repoID}/pools/", log(os.Stdout, http.HandlerFunc(han.CreateRepoPoolHandler))).Methods("POST", "OPTIONS")
|
||||
apiRouter.Handle("/repositories/{repoID}/pools", log(os.Stdout, http.HandlerFunc(han.CreateRepoPoolHandler))).Methods("POST", "OPTIONS")
|
||||
|
||||
// Repo instances list
|
||||
apiRouter.Handle("/repositories/{repoID}/instances/", log(os.Stdout, http.HandlerFunc(han.ListRepoInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/repositories/{repoID}/instances", log(os.Stdout, http.HandlerFunc(han.ListRepoInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
|
||||
// Get repo
|
||||
apiRouter.Handle("/repositories/{repoID}/", log(os.Stdout, http.HandlerFunc(han.GetRepoByIDHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/repositories/{repoID}", log(os.Stdout, http.HandlerFunc(han.GetRepoByIDHandler))).Methods("GET", "OPTIONS")
|
||||
|
|
|
|||
|
|
@ -8,6 +8,21 @@ import (
|
|||
|
||||
type contextFlags string
|
||||
|
||||
/*
|
||||
// InstanceJWTClaims holds JWT claims
|
||||
type InstanceJWTClaims struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PoolID string `json:"provider_id"`
|
||||
// Scope is either repository or organization
|
||||
Scope common.PoolType `json:"scope"`
|
||||
// Entity is the repo or org name
|
||||
Entity string `json:"entity"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
const (
|
||||
isAdminKey contextFlags = "is_admin"
|
||||
fullNameKey contextFlags = "full_name"
|
||||
|
|
@ -15,8 +30,81 @@ const (
|
|||
UserIDFlag contextFlags = "user_id"
|
||||
isEnabledFlag contextFlags = "is_enabled"
|
||||
jwtTokenFlag contextFlags = "jwt_token"
|
||||
|
||||
instanceIDKey contextFlags = "id"
|
||||
instanceNameKey contextFlags = "name"
|
||||
instancePoolIDKey contextFlags = "pool_id"
|
||||
instancePoolTypeKey contextFlags = "scope"
|
||||
instanceEntityKey contextFlags = "entity"
|
||||
)
|
||||
|
||||
func SetInstanceID(ctx context.Context, id string) context.Context {
|
||||
return context.WithValue(ctx, instanceIDKey, id)
|
||||
}
|
||||
|
||||
func InstanceID(ctx context.Context) string {
|
||||
elem := ctx.Value(instanceIDKey)
|
||||
if elem == nil {
|
||||
return ""
|
||||
}
|
||||
return elem.(string)
|
||||
}
|
||||
|
||||
func SetInstanceName(ctx context.Context, val string) context.Context {
|
||||
return context.WithValue(ctx, instanceNameKey, val)
|
||||
}
|
||||
|
||||
func InstanceName(ctx context.Context) string {
|
||||
elem := ctx.Value(instanceNameKey)
|
||||
if elem == nil {
|
||||
return ""
|
||||
}
|
||||
return elem.(string)
|
||||
}
|
||||
|
||||
func SetInstancePoolID(ctx context.Context, val string) context.Context {
|
||||
return context.WithValue(ctx, instancePoolIDKey, val)
|
||||
}
|
||||
|
||||
func InstancePoolID(ctx context.Context) string {
|
||||
elem := ctx.Value(instancePoolIDKey)
|
||||
if elem == nil {
|
||||
return ""
|
||||
}
|
||||
return elem.(string)
|
||||
}
|
||||
|
||||
func SetInstancePoolType(ctx context.Context, val string) context.Context {
|
||||
return context.WithValue(ctx, instancePoolTypeKey, val)
|
||||
}
|
||||
|
||||
func InstancePoolType(ctx context.Context) string {
|
||||
elem := ctx.Value(instancePoolTypeKey)
|
||||
if elem == nil {
|
||||
return ""
|
||||
}
|
||||
return elem.(string)
|
||||
}
|
||||
|
||||
func SetInstanceEntity(ctx context.Context, val string) context.Context {
|
||||
return context.WithValue(ctx, instanceEntityKey, val)
|
||||
}
|
||||
|
||||
func InstanceEntity(ctx context.Context) string {
|
||||
elem := ctx.Value(instanceEntityKey)
|
||||
if elem == nil {
|
||||
return ""
|
||||
}
|
||||
return elem.(string)
|
||||
}
|
||||
|
||||
func PopulateInstanceContext(ctx context.Context, instance params.Instance) context.Context {
|
||||
ctx = SetInstanceID(ctx, instance.ID)
|
||||
ctx = SetInstanceName(ctx, instance.Name)
|
||||
ctx = SetInstancePoolID(ctx, instance.PoolID)
|
||||
return ctx
|
||||
}
|
||||
|
||||
// PopulateContext sets the appropriate fields in the context, based on
|
||||
// the user object
|
||||
func PopulateContext(ctx context.Context, user params.User) context.Context {
|
||||
|
|
|
|||
132
auth/instance_middleware.go
Normal file
132
auth/instance_middleware.go
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runner-manager/config"
|
||||
dbCommon "runner-manager/database/common"
|
||||
runnerErrors "runner-manager/errors"
|
||||
"runner-manager/params"
|
||||
"runner-manager/runner/common"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// InstanceJWTClaims holds JWT claims
|
||||
type InstanceJWTClaims struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PoolID string `json:"provider_id"`
|
||||
// Scope is either repository or organization
|
||||
Scope common.PoolType `json:"scope"`
|
||||
// Entity is the repo or org name
|
||||
Entity string `json:"entity"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
func NewInstanceJWTToken(instance params.Instance, secret, entity string, poolType common.PoolType) (string, error) {
|
||||
// make TTL configurable?
|
||||
expireToken := time.Now().Add(3 * time.Hour).Unix()
|
||||
claims := InstanceJWTClaims{
|
||||
StandardClaims: jwt.StandardClaims{
|
||||
ExpiresAt: expireToken,
|
||||
Issuer: "runner-manager",
|
||||
},
|
||||
ID: instance.ID,
|
||||
Name: instance.Name,
|
||||
PoolID: instance.PoolID,
|
||||
Scope: poolType,
|
||||
Entity: entity,
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
tokenString, err := token.SignedString([]byte(secret))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "signing token")
|
||||
}
|
||||
|
||||
return tokenString, nil
|
||||
}
|
||||
|
||||
// instanceMiddleware is the authentication middleware
|
||||
// used with gorilla
|
||||
type instanceMiddleware struct {
|
||||
store dbCommon.Store
|
||||
auth *Authenticator
|
||||
cfg config.JWTAuth
|
||||
}
|
||||
|
||||
// NewjwtMiddleware returns a populated jwtMiddleware
|
||||
func NewInstanceMiddleware(store dbCommon.Store, cfg config.JWTAuth) (Middleware, error) {
|
||||
return &instanceMiddleware{
|
||||
store: store,
|
||||
cfg: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (amw *instanceMiddleware) claimsToContext(ctx context.Context, claims *InstanceJWTClaims) (context.Context, error) {
|
||||
if claims == nil {
|
||||
return ctx, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
if claims.Name == "" {
|
||||
return nil, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
instanceInfo, err := amw.store.GetInstanceByName(ctx, claims.Name)
|
||||
if err != nil {
|
||||
return ctx, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
ctx = PopulateInstanceContext(ctx, instanceInfo)
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// Middleware implements the middleware interface
|
||||
func (amw *instanceMiddleware) Middleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO: Log error details when authentication fails
|
||||
ctx := r.Context()
|
||||
authorizationHeader := r.Header.Get("authorization")
|
||||
if authorizationHeader == "" {
|
||||
invalidAuthResponse(w)
|
||||
return
|
||||
}
|
||||
|
||||
bearerToken := strings.Split(authorizationHeader, " ")
|
||||
if len(bearerToken) != 2 {
|
||||
invalidAuthResponse(w)
|
||||
return
|
||||
}
|
||||
|
||||
claims := &InstanceJWTClaims{}
|
||||
token, err := jwt.ParseWithClaims(bearerToken[1], claims, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("invalid signing method")
|
||||
}
|
||||
return []byte(amw.cfg.Secret), nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
invalidAuthResponse(w)
|
||||
return
|
||||
}
|
||||
|
||||
if !token.Valid {
|
||||
invalidAuthResponse(w)
|
||||
return
|
||||
}
|
||||
|
||||
ctx, err = amw.claimsToContext(ctx, claims)
|
||||
if err != nil {
|
||||
invalidAuthResponse(w)
|
||||
return
|
||||
}
|
||||
|
||||
// ctx = SetJWTClaim(ctx, *claims)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
39
auth/jwt.go
39
auth/jwt.go
|
|
@ -6,31 +6,15 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
apiParams "runner-manager/apiserver/params"
|
||||
"runner-manager/config"
|
||||
dbCommon "runner-manager/database/common"
|
||||
runnerErrors "runner-manager/errors"
|
||||
"runner-manager/params"
|
||||
"runner-manager/runner/common"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// InstanceJWTClaims holds JWT claims
|
||||
type InstanceJWTClaims struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PoolID string `json:"provider_id"`
|
||||
// Scope is either repository or organization
|
||||
Scope common.PoolType `json:"scope"`
|
||||
// Entity is the repo or org name
|
||||
Entity string `json:"entity"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
// JWTClaims holds JWT claims
|
||||
type JWTClaims struct {
|
||||
UserID string `json:"user"`
|
||||
|
|
@ -40,29 +24,6 @@ type JWTClaims struct {
|
|||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
func NewInstanceJWTToken(instance params.Instance, secret, entity string, poolType common.PoolType) (string, error) {
|
||||
// make TTL configurable?
|
||||
expireToken := time.Now().Add(3 * time.Hour).Unix()
|
||||
claims := InstanceJWTClaims{
|
||||
StandardClaims: jwt.StandardClaims{
|
||||
ExpiresAt: expireToken,
|
||||
Issuer: "runner-manager",
|
||||
},
|
||||
ID: instance.ID,
|
||||
Name: instance.Name,
|
||||
PoolID: instance.PoolID,
|
||||
Scope: poolType,
|
||||
Entity: entity,
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
tokenString, err := token.SignedString([]byte(secret))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "signing token")
|
||||
}
|
||||
|
||||
return tokenString, nil
|
||||
}
|
||||
|
||||
// jwtMiddleware is the authentication middleware
|
||||
// used with gorilla
|
||||
type jwtMiddleware struct {
|
||||
|
|
|
|||
|
|
@ -17,22 +17,22 @@ BEARER_TOKEN="{{ .CallbackToken }}"
|
|||
|
||||
function call() {
|
||||
PAYLOAD="$1"
|
||||
curl -s -X POST -d \'${PAYLOAD}\' -H 'Accept: application/json' -H "Authorization: Bearer ${BEARER_TOKEN}" "${CALLBACK_URL}" || echo "failed to call home: exit code ($?)"
|
||||
curl -s -X POST -d "${PAYLOAD}" -H 'Accept: application/json' -H "Authorization: Bearer ${BEARER_TOKEN}" "${CALLBACK_URL}" || echo "failed to call home: exit code ($?)"
|
||||
}
|
||||
|
||||
function sendStatus() {
|
||||
MSG="$1"
|
||||
call '{"status": "installing", "message": "'$MSG'"}'
|
||||
call "{\"status\": \"installing\", \"message\": \"$MSG\"}"
|
||||
}
|
||||
|
||||
function success() {
|
||||
MSG="$1"
|
||||
call '{"status": "active", "message": "'$MSG'"}'
|
||||
call "{\"status\": \"idle\", \"message\": \"$MSG\"}"
|
||||
}
|
||||
|
||||
function fail() {
|
||||
MSG="$1"
|
||||
call '{"status": "failed", "message": "'$MSG'"}'
|
||||
call "{\"status\": \"failed\", \"message\": \"$MSG\"}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -281,3 +281,54 @@ func (c *Client) UpdateRepoPool(repoID, poolID string, param params.UpdatePoolPa
|
|||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListRepoInstances(repoID string) ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/repositories/%s/instances", c.Config.BaseURL, repoID)
|
||||
|
||||
var response []params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListPoolInstances(poolID string) ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/pools/instances/%s", c.Config.BaseURL, poolID)
|
||||
|
||||
var response []params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetInstanceByName(instanceName string) (params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/instances/%s", c.Config.BaseURL, instanceName)
|
||||
|
||||
var response params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,10 +52,10 @@ func init() {
|
|||
|
||||
func formatProviders(providers []params.Provider) {
|
||||
t := table.NewWriter()
|
||||
header := table.Row{"Name", "Description"}
|
||||
header := table.Row{"Name", "Description", "Type"}
|
||||
t.AppendHeader(header)
|
||||
for _, val := range providers {
|
||||
t.AppendRow(table.Row{val.Name, val.ProviderType})
|
||||
t.AppendRow(table.Row{val.Name, val.Description, val.ProviderType})
|
||||
t.AppendSeparator()
|
||||
}
|
||||
fmt.Println(t.Render())
|
||||
|
|
|
|||
52
cmd/run-cli/cmd/repo_instances.go
Normal file
52
cmd/run-cli/cmd/repo_instances.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// repoPoolCmd represents the pool command
|
||||
var repoInstancesCmd = &cobra.Command{
|
||||
Use: "runner",
|
||||
SilenceUsage: true,
|
||||
Short: "List runners",
|
||||
Long: `List runners from all pools defined in this repository.`,
|
||||
Run: nil,
|
||||
}
|
||||
|
||||
var repoRunnerListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List repository runners",
|
||||
Long: `List all runners for a given repository.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a repository ID")
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
instances, err := cli.ListRepoInstances(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatInstances(instances)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
repoInstancesCmd.AddCommand(
|
||||
repoRunnerListCmd,
|
||||
)
|
||||
|
||||
repositoryCmd.AddCommand(repoInstancesCmd)
|
||||
}
|
||||
|
|
@ -126,6 +126,29 @@ var repoDeleteCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
var repoInstanceListCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Aliases: []string{"remove", "rm", "del"},
|
||||
Short: "Removes one repository",
|
||||
Long: `Delete one repository from the manager.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a repository ID")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
if err := cli.DeleteRepository(args[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
repoAddCmd.Flags().StringVar(&repoOwner, "owner", "", "The owner of this repository")
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"runner-manager/params"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -14,28 +16,120 @@ import (
|
|||
var runnerCmd = &cobra.Command{
|
||||
Use: "runner",
|
||||
SilenceUsage: true,
|
||||
Short: "A brief description of your command",
|
||||
Long: `A longer description that spans multiple lines and likely contains examples
|
||||
and usage of using your command. For example:
|
||||
Short: "List runners in a pool",
|
||||
Long: `Given a pool ID, of either a repository or an organization,
|
||||
list all instances.`,
|
||||
Run: nil,
|
||||
}
|
||||
|
||||
Cobra is a CLI library for Go that empowers applications.
|
||||
This application is a tool to generate the needed files
|
||||
to quickly create a Cobra application.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("runner called")
|
||||
var runnerListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List pool runners",
|
||||
Long: `List all configured pools for a given repository.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a pool ID")
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
instances, err := cli.ListPoolInstances(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatInstances(instances)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var runnerShowCmd = &cobra.Command{
|
||||
Use: "show",
|
||||
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 {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a runner name")
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
instance, err := cli.GetInstanceByName(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatSingleInstance(instance)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
runnerCmd.AddCommand(
|
||||
runnerListCmd,
|
||||
runnerShowCmd,
|
||||
)
|
||||
|
||||
rootCmd.AddCommand(runnerCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// runnerCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// runnerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
|
||||
func formatInstances(param []params.Instance) {
|
||||
t := table.NewWriter()
|
||||
header := table.Row{"Name", "Status", "Runner Status", "Pool ID"}
|
||||
t.AppendHeader(header)
|
||||
|
||||
for _, inst := range param {
|
||||
t.AppendRow(table.Row{inst.Name, inst.Status, inst.RunnerStatus, inst.PoolID})
|
||||
t.AppendSeparator()
|
||||
}
|
||||
fmt.Println(t.Render())
|
||||
}
|
||||
|
||||
func formatSingleInstance(instance params.Instance) {
|
||||
t := table.NewWriter()
|
||||
|
||||
header := table.Row{"Field", "Value"}
|
||||
|
||||
t.AppendHeader(header)
|
||||
t.AppendRow(table.Row{"ID", instance.ID}, table.RowConfig{AutoMerge: false})
|
||||
t.AppendRow(table.Row{"Provider ID", instance.ProviderID}, table.RowConfig{AutoMerge: false})
|
||||
t.AppendRow(table.Row{"Name", instance.Name}, table.RowConfig{AutoMerge: false})
|
||||
t.AppendRow(table.Row{"OS Type", instance.OSType}, table.RowConfig{AutoMerge: false})
|
||||
t.AppendRow(table.Row{"OS Architecture", instance.OSArch}, table.RowConfig{AutoMerge: false})
|
||||
t.AppendRow(table.Row{"OS Name", instance.OSName}, table.RowConfig{AutoMerge: false})
|
||||
t.AppendRow(table.Row{"OS Version", instance.OSVersion}, table.RowConfig{AutoMerge: false})
|
||||
t.AppendRow(table.Row{"Status", instance.Status}, table.RowConfig{AutoMerge: false})
|
||||
t.AppendRow(table.Row{"Runner Status", instance.RunnerStatus}, table.RowConfig{AutoMerge: false})
|
||||
t.AppendRow(table.Row{"Pool ID", instance.PoolID}, table.RowConfig{AutoMerge: false})
|
||||
|
||||
if len(instance.Addresses) > 0 {
|
||||
for _, addr := range instance.Addresses {
|
||||
t.AppendRow(table.Row{"Addresses", addr}, table.RowConfig{AutoMerge: true})
|
||||
}
|
||||
}
|
||||
|
||||
if len(instance.StatusMessages) > 0 {
|
||||
for _, msg := range instance.StatusMessages {
|
||||
t.AppendRow(table.Row{"Status Updates", fmt.Sprintf("%s: %s", msg.CreatedAt.Format("2006-01-02T15:04:05"), msg.Message)}, table.RowConfig{AutoMerge: true})
|
||||
}
|
||||
}
|
||||
|
||||
t.SetColumnConfigs([]table.ColumnConfig{
|
||||
{Number: 1, AutoMerge: true},
|
||||
{Number: 2, AutoMerge: false},
|
||||
})
|
||||
fmt.Println(t.Render())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,11 @@ func main() {
|
|||
log.Fatalf("failed to create controller: %+v", err)
|
||||
}
|
||||
|
||||
instanceMiddleware, err := auth.NewInstanceMiddleware(db, cfg.JWTAuth)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
jwtMiddleware, err := auth.NewjwtMiddleware(db, cfg.JWTAuth)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
|
@ -100,7 +105,7 @@ func main() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
router := routers.NewAPIRouter(controller, logWriter, jwtMiddleware, initMiddleware)
|
||||
router := routers.NewAPIRouter(controller, logWriter, jwtMiddleware, initMiddleware, instanceMiddleware)
|
||||
|
||||
tlsCfg, err := cfg.APIServer.APITLSConfig()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ func (g *Github) Validate() error {
|
|||
type Provider struct {
|
||||
Name string `toml:"name" json:"name"`
|
||||
ProviderType ProviderType `toml:"provider_type" json:"provider-type"`
|
||||
Description string `toml:"description" json:"description"`
|
||||
LXD LXD `toml:"lxd" json:"lxd"`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ type Store interface {
|
|||
// GetInstance(ctx context.Context, poolID string, instanceID string) (params.Instance, error)
|
||||
GetPoolInstanceByName(ctx context.Context, poolID string, instanceName string) (params.Instance, error)
|
||||
GetInstanceByName(ctx context.Context, instanceName string) (params.Instance, error)
|
||||
AddInstanceStatusMessage(ctx context.Context, instanceID string, statusMessage string) error
|
||||
|
||||
GetUser(ctx context.Context, user string) (params.User, error)
|
||||
GetUserByID(ctx context.Context, userID string) (params.User, error)
|
||||
|
|
|
|||
|
|
@ -83,6 +83,18 @@ type Address struct {
|
|||
|
||||
Address string
|
||||
Type string
|
||||
|
||||
InstanceID uuid.UUID
|
||||
Instance Instance `gorm:"foreignKey:InstanceID"`
|
||||
}
|
||||
|
||||
type InstanceStatusUpdate struct {
|
||||
Base
|
||||
|
||||
Message string `gorm:"type:text"`
|
||||
|
||||
InstanceID uuid.UUID
|
||||
Instance Instance `gorm:"foreignKey:InstanceID"`
|
||||
}
|
||||
|
||||
type Instance struct {
|
||||
|
|
@ -94,13 +106,15 @@ type Instance struct {
|
|||
OSArch config.OSArch
|
||||
OSName string
|
||||
OSVersion string
|
||||
Addresses []Address `gorm:"foreignKey:id"`
|
||||
Addresses []Address `gorm:"foreignKey:InstanceID"`
|
||||
Status common.InstanceStatus
|
||||
RunnerStatus common.RunnerStatus
|
||||
CallbackURL string
|
||||
|
||||
PoolID uuid.UUID
|
||||
Pool Pool `gorm:"foreignKey:PoolID"`
|
||||
|
||||
StatusMessages []InstanceStatusUpdate `gorm:"foreignKey:InstanceID"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ func (s *sqlDatabase) migrateDB() error {
|
|||
&Repository{},
|
||||
&Organization{},
|
||||
&Address{},
|
||||
&InstanceStatusUpdate{},
|
||||
&Instance{},
|
||||
&ControllerInfo{},
|
||||
&User{},
|
||||
|
|
@ -470,7 +471,9 @@ func (s *sqlDatabase) CreateRepositoryPool(ctx context.Context, repoId string, p
|
|||
}
|
||||
|
||||
for _, tt := range tags {
|
||||
s.conn.Model(&newPool).Association("Tags").Append(&tt)
|
||||
if err := s.conn.Model(&newPool).Association("Tags").Append(&tt); err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "saving tag")
|
||||
}
|
||||
}
|
||||
|
||||
pool, err := s.getPoolByID(ctx, newPool.ID.String(), "Tags")
|
||||
|
|
@ -783,22 +786,30 @@ func (s *sqlDatabase) sqlToParamsInstance(instance Instance) params.Instance {
|
|||
id = *instance.ProviderID
|
||||
}
|
||||
ret := params.Instance{
|
||||
ID: instance.ID.String(),
|
||||
ProviderID: id,
|
||||
Name: instance.Name,
|
||||
OSType: instance.OSType,
|
||||
OSName: instance.OSName,
|
||||
OSVersion: instance.OSVersion,
|
||||
OSArch: instance.OSArch,
|
||||
Status: instance.Status,
|
||||
RunnerStatus: instance.RunnerStatus,
|
||||
PoolID: instance.PoolID.String(),
|
||||
CallbackURL: instance.CallbackURL,
|
||||
ID: instance.ID.String(),
|
||||
ProviderID: id,
|
||||
Name: instance.Name,
|
||||
OSType: instance.OSType,
|
||||
OSName: instance.OSName,
|
||||
OSVersion: instance.OSVersion,
|
||||
OSArch: instance.OSArch,
|
||||
Status: instance.Status,
|
||||
RunnerStatus: instance.RunnerStatus,
|
||||
PoolID: instance.PoolID.String(),
|
||||
CallbackURL: instance.CallbackURL,
|
||||
StatusMessages: []params.StatusMessage{},
|
||||
}
|
||||
|
||||
for _, addr := range instance.Addresses {
|
||||
ret.Addresses = append(ret.Addresses, s.sqlAddressToParamsAddress(addr))
|
||||
}
|
||||
|
||||
for _, msg := range instance.StatusMessages {
|
||||
ret.StatusMessages = append(ret.StatusMessages, params.StatusMessage{
|
||||
CreatedAt: msg.CreatedAt,
|
||||
Message: msg.Message,
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
|
|
@ -864,9 +875,18 @@ func (s *sqlDatabase) getPoolInstanceByName(ctx context.Context, poolID string,
|
|||
return instance, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) getInstanceByName(ctx context.Context, instanceName string) (Instance, error) {
|
||||
func (s *sqlDatabase) getInstanceByName(ctx context.Context, instanceName string, preload ...string) (Instance, error) {
|
||||
var instance Instance
|
||||
q := s.conn.Model(&Instance{}).
|
||||
|
||||
q := s.conn
|
||||
|
||||
if len(preload) > 0 {
|
||||
for _, item := range preload {
|
||||
q = q.Preload(item)
|
||||
}
|
||||
}
|
||||
|
||||
q = q.Model(&Instance{}).
|
||||
Preload(clause.Associations).
|
||||
Where("name = ?", instanceName).
|
||||
First(&instance)
|
||||
|
|
@ -885,7 +905,7 @@ func (s *sqlDatabase) GetPoolInstanceByName(ctx context.Context, poolID string,
|
|||
}
|
||||
|
||||
func (s *sqlDatabase) GetInstanceByName(ctx context.Context, instanceName string) (params.Instance, error) {
|
||||
instance, err := s.getInstanceByName(ctx, instanceName)
|
||||
instance, err := s.getInstanceByName(ctx, instanceName, "StatusMessages")
|
||||
if err != nil {
|
||||
return params.Instance{}, errors.Wrap(err, "fetching instance")
|
||||
}
|
||||
|
|
@ -906,6 +926,22 @@ func (s *sqlDatabase) DeleteInstance(ctx context.Context, poolID string, instanc
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) AddInstanceStatusMessage(ctx context.Context, instanceID string, statusMessage string) error {
|
||||
instance, err := s.getInstanceByID(ctx, instanceID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "updating instance")
|
||||
}
|
||||
|
||||
msg := InstanceStatusUpdate{
|
||||
Message: statusMessage,
|
||||
}
|
||||
|
||||
if err := s.conn.Model(&instance).Association("StatusMessages").Append(&msg); err != nil {
|
||||
return errors.Wrap(err, "adding status message")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) UpdateInstance(ctx context.Context, instanceID string, param params.UpdateInstanceParams) (params.Instance, error) {
|
||||
instance, err := s.getInstanceByID(ctx, instanceID)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@ type Address struct {
|
|||
Type AddressType `json:"type"`
|
||||
}
|
||||
|
||||
type StatusMessage struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type Instance struct {
|
||||
// ID is the database ID of this instance.
|
||||
ID string `json:"id"`
|
||||
|
|
@ -50,6 +55,8 @@ type Instance struct {
|
|||
RunnerStatus common.RunnerStatus `json:"runner_status"`
|
||||
PoolID string `json:"pool_id"`
|
||||
|
||||
StatusMessages []StatusMessage `json:"status_messages,omitempty"`
|
||||
|
||||
// Do not serialize sensitive info.
|
||||
CallbackURL string `json:"-"`
|
||||
}
|
||||
|
|
@ -157,4 +164,5 @@ type GithubCredentials struct {
|
|||
type Provider struct {
|
||||
Name string `json:"name"`
|
||||
ProviderType config.ProviderType `json:"type"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,3 +148,8 @@ type UpdateRepositoryParams struct {
|
|||
CredentialsName string `json:"credentials_name"`
|
||||
WebhookSecret string `json:"webhook_secret"`
|
||||
}
|
||||
|
||||
type InstanceUpdateMessage struct {
|
||||
Status common.RunnerStatus `json:"status"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ func (r *Repository) updateArgsFromProviderInstance(providerInstance params.Inst
|
|||
return params.UpdateInstanceParams{
|
||||
ProviderID: providerInstance.ProviderID,
|
||||
OSName: providerInstance.OSName,
|
||||
OSVersion: providerInstance.OSName,
|
||||
OSVersion: providerInstance.OSVersion,
|
||||
Addresses: providerInstance.Addresses,
|
||||
Status: providerInstance.Status,
|
||||
RunnerStatus: providerInstance.RunnerStatus,
|
||||
|
|
@ -464,8 +464,6 @@ func (r *Repository) addInstanceToProvider(instance params.Instance) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// TODO: add function to set runner status to idle when instance calls home on callback url
|
||||
|
||||
func (r *Repository) AddRunner(ctx context.Context, poolID string) error {
|
||||
pool, err := r.store.GetRepositoryPool(r.ctx, r.id, poolID)
|
||||
if err != nil {
|
||||
|
|
@ -484,11 +482,23 @@ func (r *Repository) AddRunner(ctx context.Context, poolID string) error {
|
|||
CallbackURL: r.cfg.Internal.InstanceCallbackURL,
|
||||
}
|
||||
|
||||
_, err = r.store.CreateInstance(r.ctx, poolID, createParams)
|
||||
instance, err := r.store.CreateInstance(r.ctx, poolID, createParams)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "creating instance")
|
||||
}
|
||||
|
||||
updateParams := params.UpdateInstanceParams{
|
||||
OSName: instance.OSName,
|
||||
OSVersion: instance.OSVersion,
|
||||
Addresses: instance.Addresses,
|
||||
Status: instance.Status,
|
||||
ProviderID: instance.ProviderID,
|
||||
}
|
||||
|
||||
if _, err := r.store.UpdateInstance(r.ctx, instance.ID, updateParams); err != nil {
|
||||
return errors.Wrap(err, "updating runner state")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -656,20 +666,3 @@ func (r *Repository) HandleWorkflowJob(job params.WorkflowJob) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) ListInstances() ([]params.Instance, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetInstance() (params.Instance, error) {
|
||||
return params.Instance{}, nil
|
||||
}
|
||||
func (r *Repository) DeleteInstance() error {
|
||||
return nil
|
||||
}
|
||||
func (r *Repository) StopInstance() error {
|
||||
return nil
|
||||
}
|
||||
func (r *Repository) StartInstance() error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@ func (l *LXD) AsParams() params.Provider {
|
|||
return params.Provider{
|
||||
Name: l.cfg.Name,
|
||||
ProviderType: l.cfg.ProviderType,
|
||||
Description: l.cfg.Description,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -283,8 +283,16 @@ func (r *Runner) ListRepoPools(ctx context.Context, repoID string) ([]params.Poo
|
|||
return pools, nil
|
||||
}
|
||||
|
||||
func (r *Runner) ListPoolInstances(ctx context.Context) error {
|
||||
return nil
|
||||
func (r *Runner) ListPoolInstances(ctx context.Context, poolID string) ([]params.Instance, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return nil, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
instances, err := r.store.ListInstances(ctx, poolID)
|
||||
if err != nil {
|
||||
return []params.Instance{}, errors.Wrap(err, "fetching instances")
|
||||
}
|
||||
return instances, nil
|
||||
}
|
||||
|
||||
func (r *Runner) loadRepoPoolManager(repo params.Repository) (common.PoolManager, error) {
|
||||
|
|
@ -345,3 +353,53 @@ func (r *Runner) UpdateRepoPool(ctx context.Context, repoID, poolID string, para
|
|||
}
|
||||
return newPool, nil
|
||||
}
|
||||
|
||||
func (r *Runner) ListRepoInstances(ctx context.Context, repoID string) ([]params.Instance, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return nil, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
instances, err := r.store.ListRepoInstances(ctx, repoID)
|
||||
if err != nil {
|
||||
return []params.Instance{}, errors.Wrap(err, "fetching instances")
|
||||
}
|
||||
return instances, nil
|
||||
}
|
||||
|
||||
// TODO: move these in another file
|
||||
|
||||
func (r *Runner) GetInstance(ctx context.Context, instanceName string) (params.Instance, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.Instance{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
instance, err := r.store.GetInstanceByName(ctx, instanceName)
|
||||
if err != nil {
|
||||
return params.Instance{}, errors.Wrap(err, "fetching instance")
|
||||
}
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (r *Runner) AddInstanceStatusMessage(ctx context.Context, param params.InstanceUpdateMessage) error {
|
||||
instanceID := auth.InstanceID(ctx)
|
||||
if instanceID == "" {
|
||||
return runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
if err := r.store.AddInstanceStatusMessage(ctx, instanceID, param.Message); err != nil {
|
||||
return errors.Wrap(err, "adding status update")
|
||||
}
|
||||
|
||||
// if param.Status == providerCommon.RunnerIdle {
|
||||
// }
|
||||
|
||||
updateParams := params.UpdateInstanceParams{
|
||||
RunnerStatus: param.Status,
|
||||
}
|
||||
|
||||
if _, err := r.store.UpdateInstance(r.ctx, instanceID, updateParams); err != nil {
|
||||
return errors.Wrap(err, "updating runner state")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ func GetCloudConfig(bootstrapParams params.BootstrapInstance, tools github.Runne
|
|||
cloudCfg.AddSSHKey(bootstrapParams.SSHKeys...)
|
||||
cloudCfg.AddFile(installScript, "/install_runner.sh", "root:root", "755")
|
||||
cloudCfg.AddRunCmd("/install_runner.sh")
|
||||
cloudCfg.AddRunCmd("rm -f /install_runner.sh")
|
||||
// cloudCfg.AddRunCmd("rm -f /install_runner.sh")
|
||||
|
||||
asStr, err := cloudCfg.Serialize()
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue