2022-05-05 13:25:50 +00:00
|
|
|
// 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.
|
|
|
|
|
|
2022-05-04 13:15:27 +00:00
|
|
|
package sql
|
|
|
|
|
|
|
|
|
|
import (
|
2023-01-30 15:12:42 +00:00
|
|
|
"encoding/json"
|
2022-05-05 13:07:06 +00:00
|
|
|
"fmt"
|
2023-01-18 17:27:53 +01:00
|
|
|
|
2024-03-28 10:08:19 +00:00
|
|
|
"github.com/google/uuid"
|
2022-05-04 13:15:27 +00:00
|
|
|
"github.com/pkg/errors"
|
2023-01-30 00:40:01 +00:00
|
|
|
"gorm.io/datatypes"
|
2022-05-04 13:15:27 +00:00
|
|
|
"gorm.io/gorm"
|
2023-07-21 15:30:22 +00:00
|
|
|
|
2024-03-28 10:08:19 +00:00
|
|
|
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
|
2023-07-21 15:30:22 +00:00
|
|
|
commonParams "github.com/cloudbase/garm-provider-common/params"
|
2024-02-22 16:54:38 +01:00
|
|
|
"github.com/cloudbase/garm-provider-common/util"
|
2024-04-03 14:46:32 +00:00
|
|
|
dbCommon "github.com/cloudbase/garm/database/common"
|
2024-02-22 16:54:38 +01:00
|
|
|
"github.com/cloudbase/garm/params"
|
2022-05-04 13:15:27 +00:00
|
|
|
)
|
|
|
|
|
|
2023-08-28 08:11:44 +00:00
|
|
|
func (s *sqlDatabase) sqlToParamsInstance(instance Instance) (params.Instance, error) {
|
2022-05-04 13:15:27 +00:00
|
|
|
var id string
|
|
|
|
|
if instance.ProviderID != nil {
|
|
|
|
|
id = *instance.ProviderID
|
|
|
|
|
}
|
2023-06-24 00:22:51 +00:00
|
|
|
|
|
|
|
|
var labels []string
|
2023-08-28 08:11:44 +00:00
|
|
|
if len(instance.AditionalLabels) > 0 {
|
|
|
|
|
if err := json.Unmarshal(instance.AditionalLabels, &labels); err != nil {
|
|
|
|
|
return params.Instance{}, errors.Wrap(err, "unmarshalling labels")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-18 06:09:44 +00:00
|
|
|
var jitConfig map[string]string
|
|
|
|
|
if len(instance.JitConfiguration) > 0 {
|
2023-08-19 16:31:02 +00:00
|
|
|
if err := s.unsealAndUnmarshal(instance.JitConfiguration, &jitConfig); err != nil {
|
|
|
|
|
return params.Instance{}, errors.Wrap(err, "unmarshalling jit configuration")
|
2023-08-18 06:09:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2022-05-04 13:15:27 +00:00
|
|
|
ret := params.Instance{
|
2023-03-27 08:40:22 +00:00
|
|
|
ID: instance.ID.String(),
|
|
|
|
|
ProviderID: id,
|
|
|
|
|
AgentID: instance.AgentID,
|
|
|
|
|
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,
|
|
|
|
|
MetadataURL: instance.MetadataURL,
|
|
|
|
|
StatusMessages: []params.StatusMessage{},
|
|
|
|
|
CreateAttempt: instance.CreateAttempt,
|
|
|
|
|
UpdatedAt: instance.UpdatedAt,
|
|
|
|
|
TokenFetched: instance.TokenFetched,
|
2023-08-18 06:09:44 +00:00
|
|
|
JitConfiguration: jitConfig,
|
2023-03-27 08:40:22 +00:00
|
|
|
GitHubRunnerGroup: instance.GitHubRunnerGroup,
|
2023-06-24 00:22:51 +00:00
|
|
|
AditionalLabels: labels,
|
2022-05-10 12:28:39 +00:00
|
|
|
}
|
2024-03-11 15:41:38 +00:00
|
|
|
|
|
|
|
|
if instance.Job != nil {
|
|
|
|
|
paramJob, err := sqlWorkflowJobToParamsJob(*instance.Job)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Instance{}, errors.Wrap(err, "converting job")
|
|
|
|
|
}
|
|
|
|
|
ret.Job = ¶mJob
|
|
|
|
|
}
|
2022-05-10 12:28:39 +00:00
|
|
|
|
|
|
|
|
if len(instance.ProviderFault) > 0 {
|
|
|
|
|
ret.ProviderFault = instance.ProviderFault
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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{
|
2022-12-29 16:49:50 +00:00
|
|
|
CreatedAt: msg.CreatedAt,
|
|
|
|
|
Message: msg.Message,
|
|
|
|
|
EventType: msg.EventType,
|
|
|
|
|
EventLevel: msg.EventLevel,
|
2022-05-04 13:15:27 +00:00
|
|
|
})
|
|
|
|
|
}
|
2023-08-28 08:11:44 +00:00
|
|
|
return ret, nil
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-21 15:30:22 +00:00
|
|
|
func (s *sqlDatabase) sqlAddressToParamsAddress(addr Address) commonParams.Address {
|
|
|
|
|
return commonParams.Address{
|
2022-05-04 13:15:27 +00:00
|
|
|
Address: addr.Address,
|
2023-07-21 15:30:22 +00:00
|
|
|
Type: commonParams.AddressType(addr.Type),
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-16 17:05:18 +00:00
|
|
|
func (s *sqlDatabase) sqlToCommonOrganization(org Organization, detailed bool) (params.Organization, error) {
|
2023-01-23 17:43:32 +01:00
|
|
|
if len(org.WebhookSecret) == 0 {
|
|
|
|
|
return params.Organization{}, errors.New("missing secret")
|
|
|
|
|
}
|
2023-08-19 14:39:16 +00:00
|
|
|
secret, err := util.Unseal(org.WebhookSecret, []byte(s.cfg.Passphrase))
|
2023-01-23 17:43:32 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return params.Organization{}, errors.Wrap(err, "decrypting secret")
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-17 12:10:00 +00:00
|
|
|
endpoint, err := s.sqlToCommonGithubEndpoint(org.Endpoint)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Organization{}, errors.Wrap(err, "converting endpoint")
|
|
|
|
|
}
|
2022-05-04 13:15:27 +00:00
|
|
|
ret := params.Organization{
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
ID: org.ID.String(),
|
|
|
|
|
Name: org.Name,
|
2024-04-16 17:05:18 +00:00
|
|
|
CredentialsName: org.Credentials.Name,
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
Pools: make([]params.Pool, len(org.Pools)),
|
|
|
|
|
WebhookSecret: string(secret),
|
|
|
|
|
PoolBalancerType: org.PoolBalancerType,
|
2024-04-17 12:10:00 +00:00
|
|
|
Endpoint: endpoint,
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
}
|
2024-04-24 12:23:45 +00:00
|
|
|
|
|
|
|
|
if org.CredentialsID != nil {
|
|
|
|
|
ret.CredentialsID = *org.CredentialsID
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-16 17:05:18 +00:00
|
|
|
if detailed {
|
|
|
|
|
creds, err := s.sqlToCommonGithubCredentials(org.Credentials)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Organization{}, errors.Wrap(err, "converting credentials")
|
|
|
|
|
}
|
|
|
|
|
ret.Credentials = creds
|
|
|
|
|
}
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
|
|
|
|
|
if ret.PoolBalancerType == "" {
|
|
|
|
|
ret.PoolBalancerType = params.PoolBalancerTypeRoundRobin
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
2022-06-28 15:13:02 +00:00
|
|
|
for idx, pool := range org.Pools {
|
2023-08-28 08:11:44 +00:00
|
|
|
ret.Pools[idx], err = s.sqlToCommonPool(pool)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Organization{}, errors.Wrap(err, "converting pool")
|
|
|
|
|
}
|
2022-06-28 15:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-23 17:43:32 +01:00
|
|
|
return ret, nil
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
2024-04-16 17:05:18 +00:00
|
|
|
func (s *sqlDatabase) sqlToCommonEnterprise(enterprise Enterprise, detailed bool) (params.Enterprise, error) {
|
2023-01-23 17:43:32 +01:00
|
|
|
if len(enterprise.WebhookSecret) == 0 {
|
|
|
|
|
return params.Enterprise{}, errors.New("missing secret")
|
|
|
|
|
}
|
2023-08-19 14:39:16 +00:00
|
|
|
secret, err := util.Unseal(enterprise.WebhookSecret, []byte(s.cfg.Passphrase))
|
2023-01-23 17:43:32 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return params.Enterprise{}, errors.Wrap(err, "decrypting secret")
|
2023-01-18 17:27:53 +01:00
|
|
|
}
|
|
|
|
|
|
2024-04-17 12:10:00 +00:00
|
|
|
endpoint, err := s.sqlToCommonGithubEndpoint(enterprise.Endpoint)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Enterprise{}, errors.Wrap(err, "converting endpoint")
|
|
|
|
|
}
|
2022-10-13 16:09:28 +00:00
|
|
|
ret := params.Enterprise{
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
ID: enterprise.ID.String(),
|
|
|
|
|
Name: enterprise.Name,
|
2024-04-16 17:05:18 +00:00
|
|
|
CredentialsName: enterprise.Credentials.Name,
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
Pools: make([]params.Pool, len(enterprise.Pools)),
|
|
|
|
|
WebhookSecret: string(secret),
|
|
|
|
|
PoolBalancerType: enterprise.PoolBalancerType,
|
2024-04-17 12:10:00 +00:00
|
|
|
Endpoint: endpoint,
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-04-24 12:23:45 +00:00
|
|
|
if enterprise.CredentialsID != nil {
|
|
|
|
|
ret.CredentialsID = *enterprise.CredentialsID
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-16 17:05:18 +00:00
|
|
|
if detailed {
|
|
|
|
|
creds, err := s.sqlToCommonGithubCredentials(enterprise.Credentials)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Enterprise{}, errors.Wrap(err, "converting credentials")
|
|
|
|
|
}
|
|
|
|
|
ret.Credentials = creds
|
|
|
|
|
}
|
|
|
|
|
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
if ret.PoolBalancerType == "" {
|
|
|
|
|
ret.PoolBalancerType = params.PoolBalancerTypeRoundRobin
|
2022-10-13 16:09:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for idx, pool := range enterprise.Pools {
|
2023-08-28 08:11:44 +00:00
|
|
|
ret.Pools[idx], err = s.sqlToCommonPool(pool)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Enterprise{}, errors.Wrap(err, "converting pool")
|
|
|
|
|
}
|
2022-10-13 16:09:28 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-18 17:27:53 +01:00
|
|
|
return ret, nil
|
2022-10-13 16:09:28 +00:00
|
|
|
}
|
|
|
|
|
|
2023-08-28 08:11:44 +00:00
|
|
|
func (s *sqlDatabase) sqlToCommonPool(pool Pool) (params.Pool, error) {
|
2022-05-04 13:15:27 +00:00
|
|
|
ret := params.Pool{
|
2023-01-20 12:05:32 +02:00
|
|
|
ID: pool.ID.String(),
|
|
|
|
|
ProviderName: pool.ProviderName,
|
|
|
|
|
MaxRunners: pool.MaxRunners,
|
|
|
|
|
MinIdleRunners: pool.MinIdleRunners,
|
|
|
|
|
RunnerPrefix: params.RunnerPrefix{
|
|
|
|
|
Prefix: pool.RunnerPrefix,
|
|
|
|
|
},
|
2022-06-29 23:44:03 +00:00
|
|
|
Image: pool.Image,
|
|
|
|
|
Flavor: pool.Flavor,
|
|
|
|
|
OSArch: pool.OSArch,
|
|
|
|
|
OSType: pool.OSType,
|
|
|
|
|
Enabled: pool.Enabled,
|
|
|
|
|
Tags: make([]params.Tag, len(pool.Tags)),
|
|
|
|
|
Instances: make([]params.Instance, len(pool.Instances)),
|
|
|
|
|
RunnerBootstrapTimeout: pool.RunnerBootstrapTimeout,
|
2023-01-30 15:12:42 +00:00
|
|
|
ExtraSpecs: json.RawMessage(pool.ExtraSpecs),
|
2023-03-27 08:40:22 +00:00
|
|
|
GitHubRunnerGroup: pool.GitHubRunnerGroup,
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
Priority: pool.Priority,
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-28 15:09:54 +00:00
|
|
|
if pool.RepoID != nil {
|
2022-05-05 13:07:06 +00:00
|
|
|
ret.RepoID = pool.RepoID.String()
|
|
|
|
|
if pool.Repository.Owner != "" && pool.Repository.Name != "" {
|
|
|
|
|
ret.RepoName = fmt.Sprintf("%s/%s", pool.Repository.Owner, pool.Repository.Name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-28 15:09:54 +00:00
|
|
|
if pool.OrgID != nil && pool.Organization.Name != "" {
|
2022-05-05 13:07:06 +00:00
|
|
|
ret.OrgID = pool.OrgID.String()
|
|
|
|
|
ret.OrgName = pool.Organization.Name
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-28 15:09:54 +00:00
|
|
|
if pool.EnterpriseID != nil && pool.Enterprise.Name != "" {
|
2022-10-13 18:32:21 +00:00
|
|
|
ret.EnterpriseID = pool.EnterpriseID.String()
|
|
|
|
|
ret.EnterpriseName = pool.Enterprise.Name
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-04 13:15:27 +00:00
|
|
|
for idx, val := range pool.Tags {
|
|
|
|
|
ret.Tags[idx] = s.sqlToCommonTags(*val)
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-28 08:11:44 +00:00
|
|
|
var err error
|
2022-05-04 13:15:27 +00:00
|
|
|
for idx, inst := range pool.Instances {
|
2023-08-28 08:11:44 +00:00
|
|
|
ret.Instances[idx], err = s.sqlToParamsInstance(inst)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Pool{}, errors.Wrap(err, "converting instance")
|
|
|
|
|
}
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
2023-08-28 08:11:44 +00:00
|
|
|
return ret, nil
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *sqlDatabase) sqlToCommonTags(tag Tag) params.Tag {
|
|
|
|
|
return params.Tag{
|
|
|
|
|
ID: tag.ID.String(),
|
|
|
|
|
Name: tag.Name,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-16 17:05:18 +00:00
|
|
|
func (s *sqlDatabase) sqlToCommonRepository(repo Repository, detailed bool) (params.Repository, error) {
|
2023-01-23 17:43:32 +01:00
|
|
|
if len(repo.WebhookSecret) == 0 {
|
|
|
|
|
return params.Repository{}, errors.New("missing secret")
|
|
|
|
|
}
|
2023-08-19 14:39:16 +00:00
|
|
|
secret, err := util.Unseal(repo.WebhookSecret, []byte(s.cfg.Passphrase))
|
2023-01-23 17:43:32 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return params.Repository{}, errors.Wrap(err, "decrypting secret")
|
|
|
|
|
}
|
2024-04-17 12:10:00 +00:00
|
|
|
endpoint, err := s.sqlToCommonGithubEndpoint(repo.Endpoint)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Repository{}, errors.Wrap(err, "converting endpoint")
|
|
|
|
|
}
|
2022-05-04 13:15:27 +00:00
|
|
|
ret := params.Repository{
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
ID: repo.ID.String(),
|
|
|
|
|
Name: repo.Name,
|
|
|
|
|
Owner: repo.Owner,
|
2024-04-16 17:05:18 +00:00
|
|
|
CredentialsName: repo.Credentials.Name,
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
Pools: make([]params.Pool, len(repo.Pools)),
|
|
|
|
|
WebhookSecret: string(secret),
|
|
|
|
|
PoolBalancerType: repo.PoolBalancerType,
|
2024-04-17 12:10:00 +00:00
|
|
|
Endpoint: endpoint,
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-04-24 12:23:45 +00:00
|
|
|
if repo.CredentialsID != nil {
|
|
|
|
|
ret.CredentialsID = *repo.CredentialsID
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-16 17:05:18 +00:00
|
|
|
if detailed {
|
|
|
|
|
creds, err := s.sqlToCommonGithubCredentials(repo.Credentials)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Repository{}, errors.Wrap(err, "converting credentials")
|
|
|
|
|
}
|
|
|
|
|
ret.Credentials = creds
|
|
|
|
|
}
|
|
|
|
|
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
if ret.PoolBalancerType == "" {
|
|
|
|
|
ret.PoolBalancerType = params.PoolBalancerTypeRoundRobin
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for idx, pool := range repo.Pools {
|
2023-08-28 08:11:44 +00:00
|
|
|
ret.Pools[idx], err = s.sqlToCommonPool(pool)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return params.Repository{}, errors.Wrap(err, "converting pool")
|
|
|
|
|
}
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-23 17:43:32 +01:00
|
|
|
return ret, nil
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *sqlDatabase) sqlToParamsUser(user User) params.User {
|
|
|
|
|
return params.User{
|
2024-07-02 22:26:12 +00:00
|
|
|
ID: user.ID.String(),
|
|
|
|
|
CreatedAt: user.CreatedAt,
|
|
|
|
|
UpdatedAt: user.UpdatedAt,
|
|
|
|
|
Email: user.Email,
|
|
|
|
|
Username: user.Username,
|
|
|
|
|
FullName: user.FullName,
|
|
|
|
|
Password: user.Password,
|
|
|
|
|
Enabled: user.Enabled,
|
|
|
|
|
IsAdmin: user.IsAdmin,
|
|
|
|
|
Generation: user.Generation,
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-28 10:08:19 +00:00
|
|
|
func (s *sqlDatabase) getOrCreateTag(tx *gorm.DB, tagName string) (Tag, error) {
|
2022-05-04 13:15:27 +00:00
|
|
|
var tag Tag
|
2024-09-27 07:50:24 +00:00
|
|
|
q := tx.Where("name = ? COLLATE NOCASE", tagName).First(&tag)
|
2022-05-04 13:15:27 +00:00
|
|
|
if q.Error == nil {
|
|
|
|
|
return tag, nil
|
|
|
|
|
}
|
|
|
|
|
if !errors.Is(q.Error, gorm.ErrRecordNotFound) {
|
|
|
|
|
return Tag{}, errors.Wrap(q.Error, "fetching tag from database")
|
|
|
|
|
}
|
|
|
|
|
newTag := Tag{
|
|
|
|
|
Name: tagName,
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-29 18:18:29 +00:00
|
|
|
if err := tx.Create(&newTag).Error; err != nil {
|
|
|
|
|
return Tag{}, errors.Wrap(err, "creating tag")
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
return newTag, nil
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-28 18:23:49 +00:00
|
|
|
func (s *sqlDatabase) updatePool(tx *gorm.DB, pool Pool, param params.UpdatePoolParams) (params.Pool, error) {
|
2022-05-04 13:15:27 +00:00
|
|
|
if param.Enabled != nil && pool.Enabled != *param.Enabled {
|
|
|
|
|
pool.Enabled = *param.Enabled
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if param.Flavor != "" {
|
|
|
|
|
pool.Flavor = param.Flavor
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if param.Image != "" {
|
|
|
|
|
pool.Image = param.Image
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-27 09:05:58 +01:00
|
|
|
if param.Prefix != "" {
|
|
|
|
|
pool.RunnerPrefix = param.Prefix
|
|
|
|
|
}
|
2022-12-19 20:56:16 +01:00
|
|
|
|
2022-05-04 13:15:27 +00:00
|
|
|
if param.MaxRunners != nil {
|
|
|
|
|
pool.MaxRunners = *param.MaxRunners
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if param.MinIdleRunners != nil {
|
|
|
|
|
pool.MinIdleRunners = *param.MinIdleRunners
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if param.OSArch != "" {
|
|
|
|
|
pool.OSArch = param.OSArch
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if param.OSType != "" {
|
|
|
|
|
pool.OSType = param.OSType
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-30 00:40:01 +00:00
|
|
|
if param.ExtraSpecs != nil {
|
|
|
|
|
pool.ExtraSpecs = datatypes.JSON(param.ExtraSpecs)
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-06 17:37:18 +00:00
|
|
|
if param.RunnerBootstrapTimeout != nil && *param.RunnerBootstrapTimeout > 0 {
|
|
|
|
|
pool.RunnerBootstrapTimeout = *param.RunnerBootstrapTimeout
|
2022-06-29 23:44:03 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-27 08:40:22 +00:00
|
|
|
if param.GitHubRunnerGroup != nil {
|
|
|
|
|
pool.GitHubRunnerGroup = *param.GitHubRunnerGroup
|
|
|
|
|
}
|
|
|
|
|
|
Add pool balancing strategy
This change adds the ability to specify the pool balancing strategy to
use when processing queued jobs. Before this change, GARM would round-robin
through all pools that matched the set of tags requested by queued jobs.
When round-robin (default) is used for an entity (repo, org or enterprise)
and you have 2 pools defined for that entity with a common set of tags that
match 10 jobs (for example), then those jobs would trigger the creation of
a new runner in each of the two pools in turn. Job 1 would go to pool 1,
job 2 would go to pool 2, job 3 to pool 1, job 4 to pool 2 and so on.
When "stack" is used, those same 10 jobs would trigger the creation of a
new runner in the pool with the highest priority, every time.
In both cases, if a pool is full, the next one would be tried automatically.
For the stack case, this would mean that if pool 2 had a priority of 10 and
pool 1 would have a priority of 5, pool 2 would be saturated first, then
pool 1.
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:04:34 +00:00
|
|
|
if param.Priority != nil {
|
|
|
|
|
pool.Priority = *param.Priority
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-28 18:23:49 +00:00
|
|
|
if q := tx.Save(&pool); q.Error != nil {
|
2022-05-04 13:15:27 +00:00
|
|
|
return params.Pool{}, errors.Wrap(q.Error, "saving database entry")
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 11:41:38 +00:00
|
|
|
tags := []Tag{}
|
2024-11-26 07:53:02 +01:00
|
|
|
if len(param.Tags) > 0 {
|
2022-06-24 11:41:38 +00:00
|
|
|
for _, val := range param.Tags {
|
2024-03-28 18:23:49 +00:00
|
|
|
t, err := s.getOrCreateTag(tx, val)
|
2022-06-24 11:41:38 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return params.Pool{}, errors.Wrap(err, "fetching tag")
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
2022-06-24 11:41:38 +00:00
|
|
|
tags = append(tags, t)
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
2024-03-28 18:23:49 +00:00
|
|
|
if err := tx.Model(&pool).Association("Tags").Replace(&tags); err != nil {
|
2022-05-04 13:15:27 +00:00
|
|
|
return params.Pool{}, errors.Wrap(err, "replacing tags")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-28 08:11:44 +00:00
|
|
|
return s.sqlToCommonPool(pool)
|
2022-05-04 13:15:27 +00:00
|
|
|
}
|
2024-03-28 10:08:19 +00:00
|
|
|
|
|
|
|
|
func (s *sqlDatabase) getPoolByID(tx *gorm.DB, poolID string, preload ...string) (Pool, error) {
|
|
|
|
|
u, err := uuid.Parse(poolID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Pool{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")
|
|
|
|
|
}
|
|
|
|
|
var pool Pool
|
|
|
|
|
q := tx.Model(&Pool{})
|
|
|
|
|
if len(preload) > 0 {
|
|
|
|
|
for _, item := range preload {
|
|
|
|
|
q = q.Preload(item)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q = q.Where("id = ?", u).First(&pool)
|
|
|
|
|
|
|
|
|
|
if q.Error != nil {
|
|
|
|
|
if errors.Is(q.Error, gorm.ErrRecordNotFound) {
|
|
|
|
|
return Pool{}, runnerErrors.ErrNotFound
|
|
|
|
|
}
|
|
|
|
|
return Pool{}, errors.Wrap(q.Error, "fetching org from database")
|
|
|
|
|
}
|
|
|
|
|
return pool, nil
|
|
|
|
|
}
|
2024-03-28 18:23:49 +00:00
|
|
|
|
2024-03-29 18:18:29 +00:00
|
|
|
func (s *sqlDatabase) hasGithubEntity(tx *gorm.DB, entityType params.GithubEntityType, entityID string) error {
|
2024-03-28 18:23:49 +00:00
|
|
|
u, err := uuid.Parse(entityID)
|
|
|
|
|
if err != nil {
|
2024-03-29 18:18:29 +00:00
|
|
|
return errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")
|
2024-03-28 18:23:49 +00:00
|
|
|
}
|
|
|
|
|
var q *gorm.DB
|
|
|
|
|
switch entityType {
|
|
|
|
|
case params.GithubEntityTypeRepository:
|
|
|
|
|
q = tx.Model(&Repository{}).Where("id = ?", u)
|
|
|
|
|
case params.GithubEntityTypeOrganization:
|
|
|
|
|
q = tx.Model(&Organization{}).Where("id = ?", u)
|
|
|
|
|
case params.GithubEntityTypeEnterprise:
|
|
|
|
|
q = tx.Model(&Enterprise{}).Where("id = ?", u)
|
|
|
|
|
default:
|
2024-03-29 18:18:29 +00:00
|
|
|
return errors.Wrap(runnerErrors.ErrBadRequest, "invalid entity type")
|
2024-03-28 18:23:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var entity interface{}
|
|
|
|
|
if err := q.First(entity).Error; err != nil {
|
|
|
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
2024-03-29 18:18:29 +00:00
|
|
|
return errors.Wrap(runnerErrors.ErrNotFound, "entity not found")
|
2024-03-28 18:23:49 +00:00
|
|
|
}
|
2024-03-29 18:18:29 +00:00
|
|
|
return errors.Wrap(err, "fetching entity from database")
|
2024-03-28 18:23:49 +00:00
|
|
|
}
|
2024-03-29 18:18:29 +00:00
|
|
|
return nil
|
2024-03-28 18:23:49 +00:00
|
|
|
}
|
2024-04-03 14:46:32 +00:00
|
|
|
|
|
|
|
|
func (s *sqlDatabase) marshalAndSeal(data interface{}) ([]byte, error) {
|
|
|
|
|
enc, err := json.Marshal(data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "marshalling data")
|
|
|
|
|
}
|
|
|
|
|
return util.Seal(enc, []byte(s.cfg.Passphrase))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *sqlDatabase) unsealAndUnmarshal(data []byte, target interface{}) error {
|
|
|
|
|
decrypted, err := util.Unseal(data, []byte(s.cfg.Passphrase))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "decrypting data")
|
|
|
|
|
}
|
|
|
|
|
if err := json.Unmarshal(decrypted, target); err != nil {
|
|
|
|
|
return errors.Wrap(err, "unmarshalling data")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-19 12:40:56 +00:00
|
|
|
func (s *sqlDatabase) sendNotify(entityType dbCommon.DatabaseEntityType, op dbCommon.OperationType, payload interface{}) error {
|
|
|
|
|
if s.producer == nil {
|
|
|
|
|
// no producer was registered. Not sending notifications.
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if payload == nil {
|
|
|
|
|
return errors.New("missing payload")
|
|
|
|
|
}
|
2024-04-03 14:46:32 +00:00
|
|
|
message := dbCommon.ChangePayload{
|
|
|
|
|
Operation: op,
|
|
|
|
|
Payload: payload,
|
|
|
|
|
EntityType: entityType,
|
|
|
|
|
}
|
2024-06-19 12:40:56 +00:00
|
|
|
return s.producer.Notify(message)
|
2024-04-03 14:46:32 +00:00
|
|
|
}
|