The websocket client and hub interaction has been simplified a bit. The hub now acts only as a tee writer to the various clients that register. Clients must register and unregister explicitly. The hub is no longer passed in to the client. Websocket clients now watch for password changes or jwt token expiration times. Clients are disconnected if auth token expires or if the password is changed. Various aditional safety checks have been added. Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
312 lines
9.9 KiB
Go
312 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)"`
|
|
Generation uint
|
|
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"`
|
|
}
|