Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new forgejo scaler #6495

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Conversation

cobak78
Copy link

@cobak78 cobak78 commented Jan 22, 2025

This PR adds a new forgejo autoscaler with the same characteristics of the github autoscaler.
Here is the issue for this feature #6488

Another important discussions on this topic:

Checklist

@cobak78 cobak78 requested a review from a team as a code owner January 22, 2025 14:40
@cobak78 cobak78 force-pushed the forgejo-runner-scaler branch from 03fd3a1 to 39fd60d Compare January 22, 2025 14:43
@cobak78 cobak78 force-pushed the forgejo-runner-scaler branch from 39fd60d to a7366bc Compare January 22, 2025 14:52
jaime merino added 2 commits January 23, 2025 12:41
Signed-off-by: jaime Merino <[email protected]>
Signed-off-by: jaime merino <[email protected]ª>
@cobak78 cobak78 force-pushed the forgejo-runner-scaler branch from 5b9d520 to f13dbc7 Compare January 23, 2025 11:41
Signed-off-by: jaime merino <[email protected]ª>
Copy link
Member

@JorTurFer JorTurFer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for your contribution! I've left some comment inline. Additionally to them:

  • Please, add an e2e test covering the scaler. You get more info about how to do it here
  • Could you open a PR to docs adding the scaler in next version?
  • All commits must be signed and that's why DCO check is failing, please rebase your branch signing all the commits (how to do that it's explained in the check page)

@@ -0,0 +1,43 @@
/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is just a type definition file, I think that it's better if it's merged with the scaler code. We create packages when there is complex logic or specialized helpers, but just to define some structs, we prefer to keep all together

Comment on lines +25 to +26
orgJobMetricPath = "/api/v1/orgs/%s/actions/runners/jobs" // /api/v1/orgs/{org}/actions/runners/jobs
repoJobMetricPath = "/api/v1/repos/%s/%s/actions/runners/jobs" // {address}/api/v1/repos/{owner}/{repo}/actions/runners/jobs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
orgJobMetricPath = "/api/v1/orgs/%s/actions/runners/jobs" // /api/v1/orgs/{org}/actions/runners/jobs
repoJobMetricPath = "/api/v1/repos/%s/%s/actions/runners/jobs" // {address}/api/v1/repos/{owner}/{repo}/actions/runners/jobs
orgJobMetricPath = "/api/v1/orgs/%s/actions/runners/jobs"
repoJobMetricPath = "/api/v1/repos/%s/%s/actions/runners/jobs"

Comment on lines +46 to +75
func parseForgejoRunnerMetadata(config *scalersconfig.ScalerConfig) (*ForgejoRunnerConfig, error) {
meta := &ForgejoRunnerConfig{}

if val, ok := config.TriggerMetadata["token"]; ok && val != "" {
meta.RunnerMeta.Token = val
} else {
return nil, fmt.Errorf("no token given")
}

if val, ok := config.TriggerMetadata["address"]; ok && val != "" {
meta.RunnerMeta.Address = val
} else {
return nil, fmt.Errorf("no address given")
}

if val, ok := config.TriggerMetadata["labels"]; ok && val != "" {
meta.RunnerMeta.Labels = val
} else {
return nil, fmt.Errorf("no labels given")
}

global := false
if val, ok := config.TriggerMetadata["global"]; ok && val == stringTrue {
global = true
}

meta.RunnerMeta.Global = global

return meta, nil
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, use the new declarative way to define the scaler metadata. We are moving all the scalers to there to build tools around the approach.

You can see an example with other scalers like https://github.com/kedacore/keda/pull/5818/files

externalMetric := &v2.ExternalMetricSource{
Metric: v2.MetricIdentifier{
Name: GenerateMetricNameWithIndex(
1,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value is provided via config.TriggerIndex during the scaler building process, please propagate it until here as it's required to ensure that each scaler has a unique name within the ScaledObject|Job

Metric: v2.MetricIdentifier{
Name: GenerateMetricNameWithIndex(
1,
kedautil.NormalizeString(fmt.Sprintf("forgejo-runner-%s", s.metadata.RunnerMeta.Address)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be used as metric name, so we must ensure that it's a sanitized string (it'll be sent via url). What about just using "forgejo-runner" or concated labels?

adminJobMetricPath = "/api/v1/admin/runners/jobs"
orgJobMetricPath = "/api/v1/orgs/%s/actions/runners/jobs" // /api/v1/orgs/{org}/actions/runners/jobs
repoJobMetricPath = "/api/v1/repos/%s/%s/actions/runners/jobs" // {address}/api/v1/repos/{owner}/{repo}/actions/runners/jobs
UserJobMetricPath = "/api/v1/user/actions/runners/jobs"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
UserJobMetricPath = "/api/v1/user/actions/runners/jobs"
userJobMetricPath = "/api/v1/user/actions/runners/jobs"


metric := GenerateMetricInMili(metricName, float64(len(jobList.Jobs)))

metric.Value.Add(resource.Quantity{})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this? I'd say that it's required because GenerateMetricInMili returns a formatted metric

Comment on lines +156 to +157
err = json.Unmarshal(b, &jobList)
return jobList, err
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea about fogejo API, does it only return pending jobs, or it also returns active/completed jobs somehow? My question is related with the point about if we need to filter the jobs somehow, or just counting them is enough.

@@ -0,0 +1,266 @@
package scalers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use Pascal case for test naming to be consistent with other test cases

Comment on lines +27 to +58
{"no address given", map[string]string{
"token": "some-token", "name": "some-name", "labels": "some-label", "metric_path": "path",
}, true, "no address given", false},
{"no token given", map[string]string{
"address": "https://api.github.com", "name": "some-name", "labels": "some-label", "metric_path": "path",
}, true, "no token given", false},
{"no label given", map[string]string{
"address": "https://api.github.com", "token": "some-token", "name": "some-name", "metric_path": "path",
}, true, "no labels given", false},
{"no name given use default", map[string]string{
"address": "https://api.github.com", "token": "some-token", "labels": "some-label", "metric_path": "path",
}, false, "", false},
{"no metric path given use default", map[string]string{
"address": "https://api.github.com", "token": "some-token", "name": "some-name", "labels": "some-label",
}, false, "", false},
// properly formed
{"properly formed", map[string]string{
"address": "https://api.github.com",
"token": "some-token",
"name": "some-name",
"labels": "some-labels",
"metric_path": "path",
}, false, "", false},
{"properly formed with global", map[string]string{
"address": "https://api.github.com",
"token": "some-token",
"name": "some-name",
"labels": "some-labels",
"global": "true",
"metric_path": "path",
}, false, "", true},
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that the url isn't relevant for this test case but let's use other unrelated with GitHub to avoid misunderstandings or confusions with GitHub scaler

Suggested change
{"no address given", map[string]string{
"token": "some-token", "name": "some-name", "labels": "some-label", "metric_path": "path",
}, true, "no address given", false},
{"no token given", map[string]string{
"address": "https://api.github.com", "name": "some-name", "labels": "some-label", "metric_path": "path",
}, true, "no token given", false},
{"no label given", map[string]string{
"address": "https://api.github.com", "token": "some-token", "name": "some-name", "metric_path": "path",
}, true, "no labels given", false},
{"no name given use default", map[string]string{
"address": "https://api.github.com", "token": "some-token", "labels": "some-label", "metric_path": "path",
}, false, "", false},
{"no metric path given use default", map[string]string{
"address": "https://api.github.com", "token": "some-token", "name": "some-name", "labels": "some-label",
}, false, "", false},
// properly formed
{"properly formed", map[string]string{
"address": "https://api.github.com",
"token": "some-token",
"name": "some-name",
"labels": "some-labels",
"metric_path": "path",
}, false, "", false},
{"properly formed with global", map[string]string{
"address": "https://api.github.com",
"token": "some-token",
"name": "some-name",
"labels": "some-labels",
"global": "true",
"metric_path": "path",
}, false, "", true},
}
{"no address given", map[string]string{
"token": "some-token", "name": "some-name", "labels": "some-label", "metric_path": "path",
}, true, "no address given", false},
{"no token given", map[string]string{
"address": "https://api.myforgejoinstance.com", "name": "some-name", "labels": "some-label", "metric_path": "path",
}, true, "no token given", false},
{"no label given", map[string]string{
"address": "https://api.myforgejoinstance.com", "token": "some-token", "name": "some-name", "metric_path": "path",
}, true, "no labels given", false},
{"no name given use default", map[string]string{
"address": "https://api.myforgejoinstance.com", "token": "some-token", "labels": "some-label", "metric_path": "path",
}, false, "", false},
{"no metric path given use default", map[string]string{
"address": "https://api.myforgejoinstance.com", "token": "some-token", "name": "some-name", "labels": "some-label",
}, false, "", false},
// properly formed
{"properly formed", map[string]string{
"address": "https://api.myforgejoinstance.com",
"token": "some-token",
"name": "some-name",
"labels": "some-labels",
"metric_path": "path",
}, false, "", false},
{"properly formed with global", map[string]string{
"address": "https://api.myforgejoinstance.com",
"token": "some-token",
"name": "some-name",
"labels": "some-labels",
"global": "true",
"metric_path": "path",
}, false, "", true},
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants