GARM has a backoff interval when consuming queued jobs. This backoff is intended to allow any potential idle runners to pick up a job before GARM attempts to spin up a new one. This change allows users to set a custom backoff interval or disable it altogether by setting it to 0. Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
311 lines
9.9 KiB
Go
311 lines
9.9 KiB
Go
// Copyright 2022 Cloudbase Solutions SRL
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this file except in compliance with the License. You may obtain
|
|
// a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package sql
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/pkg/errors"
|
|
"gorm.io/datatypes"
|
|
"gorm.io/gorm"
|
|
|
|
commonParams "github.com/cloudbase/garm-provider-common/params"
|
|
"github.com/cloudbase/garm/params"
|
|
)
|
|
|
|
type Base struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;"`
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
DeletedAt gorm.DeletedAt `gorm:"index"`
|
|
}
|
|
|
|
func (b *Base) BeforeCreate(_ *gorm.DB) error {
|
|
emptyID := uuid.UUID{}
|
|
if b.ID != emptyID {
|
|
return nil
|
|
}
|
|
newID, err := uuid.NewRandom()
|
|
if err != nil {
|
|
return errors.Wrap(err, "generating id")
|
|
}
|
|
b.ID = newID
|
|
return nil
|
|
}
|
|
|
|
type Tag struct {
|
|
Base
|
|
|
|
Name string `gorm:"type:varchar(64);uniqueIndex"`
|
|
Pools []*Pool `gorm:"many2many:pool_tags;constraint:OnDelete:CASCADE,OnUpdate:CASCADE;"`
|
|
}
|
|
|
|
type Pool struct {
|
|
Base
|
|
|
|
ProviderName string `gorm:"index:idx_pool_type"`
|
|
RunnerPrefix string
|
|
MaxRunners uint
|
|
MinIdleRunners uint
|
|
RunnerBootstrapTimeout uint
|
|
Image string `gorm:"index:idx_pool_type"`
|
|
Flavor string `gorm:"index:idx_pool_type"`
|
|
OSType commonParams.OSType
|
|
OSArch commonParams.OSArch
|
|
Tags []*Tag `gorm:"many2many:pool_tags;constraint:OnDelete:CASCADE,OnUpdate:CASCADE;"`
|
|
Enabled bool
|
|
// ExtraSpecs is an opaque json that gets sent to the provider
|
|
// as part of the bootstrap params for instances. It can contain
|
|
// any kind of data needed by providers.
|
|
ExtraSpecs datatypes.JSON
|
|
GitHubRunnerGroup string
|
|
|
|
RepoID *uuid.UUID `gorm:"index"`
|
|
Repository Repository `gorm:"foreignKey:RepoID;"`
|
|
|
|
OrgID *uuid.UUID `gorm:"index"`
|
|
Organization Organization `gorm:"foreignKey:OrgID"`
|
|
|
|
EnterpriseID *uuid.UUID `gorm:"index"`
|
|
Enterprise Enterprise `gorm:"foreignKey:EnterpriseID"`
|
|
|
|
Instances []Instance `gorm:"foreignKey:PoolID"`
|
|
Priority uint `gorm:"index:idx_pool_priority"`
|
|
}
|
|
|
|
type Repository struct {
|
|
Base
|
|
|
|
CredentialsName string
|
|
|
|
CredentialsID *uint `gorm:"index"`
|
|
Credentials GithubCredentials `gorm:"foreignKey:CredentialsID;constraint:OnDelete:SET NULL"`
|
|
|
|
Owner string `gorm:"index:idx_owner_nocase,unique,collate:nocase"`
|
|
Name string `gorm:"index:idx_owner_nocase,unique,collate:nocase"`
|
|
WebhookSecret []byte
|
|
Pools []Pool `gorm:"foreignKey:RepoID"`
|
|
Jobs []WorkflowJob `gorm:"foreignKey:RepoID;constraint:OnDelete:SET NULL"`
|
|
PoolBalancerType params.PoolBalancerType `gorm:"type:varchar(64)"`
|
|
|
|
EndpointName *string `gorm:"index:idx_owner_nocase,unique,collate:nocase"`
|
|
Endpoint GithubEndpoint `gorm:"foreignKey:EndpointName;constraint:OnDelete:SET NULL"`
|
|
}
|
|
|
|
type Organization struct {
|
|
Base
|
|
|
|
CredentialsName string
|
|
|
|
CredentialsID *uint `gorm:"index"`
|
|
Credentials GithubCredentials `gorm:"foreignKey:CredentialsID;constraint:OnDelete:SET NULL"`
|
|
|
|
Name string `gorm:"index:idx_org_name_nocase,collate:nocase"`
|
|
WebhookSecret []byte
|
|
Pools []Pool `gorm:"foreignKey:OrgID"`
|
|
Jobs []WorkflowJob `gorm:"foreignKey:OrgID;constraint:OnDelete:SET NULL"`
|
|
PoolBalancerType params.PoolBalancerType `gorm:"type:varchar(64)"`
|
|
|
|
EndpointName *string `gorm:"index"`
|
|
Endpoint GithubEndpoint `gorm:"foreignKey:EndpointName;constraint:OnDelete:SET NULL"`
|
|
}
|
|
|
|
type Enterprise struct {
|
|
Base
|
|
|
|
CredentialsName string
|
|
|
|
CredentialsID *uint `gorm:"index"`
|
|
Credentials GithubCredentials `gorm:"foreignKey:CredentialsID;constraint:OnDelete:SET NULL"`
|
|
|
|
Name string `gorm:"index:idx_ent_name_nocase,collate:nocase"`
|
|
WebhookSecret []byte
|
|
Pools []Pool `gorm:"foreignKey:EnterpriseID"`
|
|
Jobs []WorkflowJob `gorm:"foreignKey:EnterpriseID;constraint:OnDelete:SET NULL"`
|
|
PoolBalancerType params.PoolBalancerType `gorm:"type:varchar(64)"`
|
|
|
|
EndpointName *string `gorm:"index"`
|
|
Endpoint GithubEndpoint `gorm:"foreignKey:EndpointName;constraint:OnDelete:SET NULL"`
|
|
}
|
|
|
|
type Address struct {
|
|
Base
|
|
|
|
Address string
|
|
Type string
|
|
|
|
InstanceID uuid.UUID
|
|
Instance Instance `gorm:"foreignKey:InstanceID"`
|
|
}
|
|
|
|
type InstanceStatusUpdate struct {
|
|
Base
|
|
|
|
EventType params.EventType `gorm:"index:eventType"`
|
|
EventLevel params.EventLevel
|
|
Message string `gorm:"type:text"`
|
|
|
|
InstanceID uuid.UUID `gorm:"index:idx_instance_status_updates_instance_id"`
|
|
Instance Instance `gorm:"foreignKey:InstanceID"`
|
|
}
|
|
|
|
type Instance struct {
|
|
Base
|
|
|
|
ProviderID *string `gorm:"uniqueIndex"`
|
|
Name string `gorm:"uniqueIndex"`
|
|
AgentID int64
|
|
OSType commonParams.OSType
|
|
OSArch commonParams.OSArch
|
|
OSName string
|
|
OSVersion string
|
|
Addresses []Address `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE,OnUpdate:CASCADE;"`
|
|
Status commonParams.InstanceStatus
|
|
RunnerStatus params.RunnerStatus
|
|
CallbackURL string
|
|
MetadataURL string
|
|
ProviderFault []byte `gorm:"type:longblob"`
|
|
CreateAttempt int
|
|
TokenFetched bool
|
|
JitConfiguration []byte `gorm:"type:longblob"`
|
|
GitHubRunnerGroup string
|
|
AditionalLabels datatypes.JSON
|
|
|
|
PoolID uuid.UUID
|
|
Pool Pool `gorm:"foreignKey:PoolID"`
|
|
|
|
StatusMessages []InstanceStatusUpdate `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE,OnUpdate:CASCADE;"`
|
|
|
|
Job *WorkflowJob `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE,OnUpdate:CASCADE;"`
|
|
}
|
|
|
|
type User struct {
|
|
Base
|
|
|
|
Username string `gorm:"uniqueIndex;varchar(64)"`
|
|
FullName string `gorm:"type:varchar(254)"`
|
|
Email string `gorm:"type:varchar(254);unique;index:idx_email"`
|
|
Password string `gorm:"type:varchar(60)"`
|
|
IsAdmin bool
|
|
Enabled bool
|
|
}
|
|
|
|
type ControllerInfo struct {
|
|
Base
|
|
|
|
ControllerID uuid.UUID
|
|
|
|
CallbackURL string
|
|
MetadataURL string
|
|
WebhookBaseURL string
|
|
// MinimumJobAgeBackoff is the minimum time that a job must be in the queue
|
|
// before GARM will attempt to allocate a runner to service it. This backoff
|
|
// is useful if you have idle runners in various pools that could potentially
|
|
// pick up the job. GARM would allow this amount of time for runners to react
|
|
// before spinning up a new one and potentially having to scale down later.
|
|
MinimumJobAgeBackoff uint
|
|
}
|
|
|
|
type WorkflowJob struct {
|
|
// ID is the ID of the job.
|
|
ID int64 `gorm:"index"`
|
|
// RunID is the ID of the workflow run. A run may have multiple jobs.
|
|
RunID int64
|
|
// Action is the specific activity that triggered the event.
|
|
Action string `gorm:"type:varchar(254);index"`
|
|
// Conclusion is the outcome of the job.
|
|
// Possible values: "success", "failure", "neutral", "cancelled", "skipped",
|
|
// "timed_out", "action_required"
|
|
Conclusion string
|
|
// Status is the phase of the lifecycle that the job is currently in.
|
|
// "queued", "in_progress" and "completed".
|
|
Status string
|
|
// Name is the name if the job that was triggered.
|
|
Name string
|
|
|
|
StartedAt time.Time
|
|
CompletedAt time.Time
|
|
|
|
GithubRunnerID int64
|
|
|
|
InstanceID *uuid.UUID `gorm:"index:idx_instance_job"`
|
|
Instance Instance `gorm:"foreignKey:InstanceID"`
|
|
|
|
RunnerGroupID int64
|
|
RunnerGroupName string
|
|
|
|
// repository in which the job was triggered.
|
|
RepositoryName string
|
|
RepositoryOwner string
|
|
|
|
Labels datatypes.JSON
|
|
|
|
// The entity that received the hook.
|
|
//
|
|
// Webhooks may be configured on the repo, the org and/or the enterprise.
|
|
// If we only configure a repo to use garm, we'll only ever receive a
|
|
// webhook from the repo. But if we configure the parent org of the repo and
|
|
// the parent enterprise of the org to use garm, a webhook will be sent for each
|
|
// entity type, in response to one workflow event. Thus, we will get 3 webhooks
|
|
// with the same run_id and job id. Record all involved entities in the same job
|
|
// if we have them configured in garm.
|
|
RepoID *uuid.UUID `gorm:"index"`
|
|
Repository Repository `gorm:"foreignKey:RepoID"`
|
|
|
|
OrgID *uuid.UUID `gorm:"index"`
|
|
Organization Organization `gorm:"foreignKey:OrgID"`
|
|
|
|
EnterpriseID *uuid.UUID `gorm:"index"`
|
|
Enterprise Enterprise `gorm:"foreignKey:EnterpriseID"`
|
|
|
|
LockedBy uuid.UUID
|
|
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
DeletedAt gorm.DeletedAt `gorm:"index"`
|
|
}
|
|
|
|
type GithubEndpoint struct {
|
|
Name string `gorm:"type:varchar(64) collate nocase;primary_key;"`
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
DeletedAt gorm.DeletedAt `gorm:"index"`
|
|
|
|
Description string `gorm:"type:text"`
|
|
APIBaseURL string `gorm:"type:text collate nocase"`
|
|
UploadBaseURL string `gorm:"type:text collate nocase"`
|
|
BaseURL string `gorm:"type:text collate nocase"`
|
|
CACertBundle []byte `gorm:"type:longblob"`
|
|
}
|
|
|
|
type GithubCredentials struct {
|
|
gorm.Model
|
|
|
|
Name string `gorm:"index:idx_github_credentials,unique;type:varchar(64) collate nocase"`
|
|
UserID *uuid.UUID `gorm:"index:idx_github_credentials,unique"`
|
|
User User `gorm:"foreignKey:UserID"`
|
|
|
|
Description string `gorm:"type:text"`
|
|
AuthType params.GithubAuthType `gorm:"index"`
|
|
Payload []byte `gorm:"type:longblob"`
|
|
|
|
Endpoint GithubEndpoint `gorm:"foreignKey:EndpointName"`
|
|
EndpointName *string `gorm:"index"`
|
|
|
|
Repositories []Repository `gorm:"foreignKey:CredentialsID"`
|
|
Organizations []Organization `gorm:"foreignKey:CredentialsID"`
|
|
Enterprises []Enterprise `gorm:"foreignKey:CredentialsID"`
|
|
}
|