Compare commits

...

876 commits
v0.1.1 ... main

Author SHA1 Message Date
6608d0aa8c
refactor(params): ♻️ Simplify ForgeURL logic by removing redundant switch case
Some checks failed
CodeQL / Analyze (push) Failing after 2s
Go Tests / Linters (push) Successful in 3m26s
Go Tests / go-tests (push) Successful in 6m41s
Streamlines the ForgeURL method by removing an unnecessary nested switch case
on ForgeType, consolidating the logic to rely solely on EntityType. This change
reduces complexity and improves code readability without altering functionality.
2025-08-27 16:04:56 +02:00
Gabriel
29f2e2a2b9
Merge pull request #499 from gabriel-samfira/better-cli-log-formatting
Make the debug-log command more useful
2025-08-27 16:27:33 +03:00
Gabriel Adrian Samfira
0faeee703d Make the debug-log command more useful
The debug-log command now supports log level filtering and attribute
filtering. The log level filtering will only be able to set the minimum
log level as low as the server is configured to stream. If the server has
its log level set as INFO, then setting the log level in the CLI to DEBUG
will have no effect.

But anything above what the server sends, is within the control of the client
to filter. This is all done client side.

Attribute filters are useful if you need to watch the logs for a particular
worker, entity, etc.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-27 13:21:56 +00:00
Gabriel
e3a9fe7026
Merge pull request #498 from gabriel-samfira/preload-more-info
Preload more info for entity pools
2025-08-27 12:27:04 +03:00
Gabriel Adrian Samfira
9ef4566cae Preload more info for entity pools
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-27 09:14:45 +00:00
Gabriel
e79a5c1d50
Merge pull request #496 from cloudbase/dependabot/go_modules/github.com/stretchr/testify-1.11.0
Bump github.com/stretchr/testify from 1.10.0 to 1.11.0
2025-08-25 19:35:17 +03:00
Gabriel
89fecd9dcd
Merge pull request #497 from gabriel-samfira/fix-double-pool
Fix double creation of pools
2025-08-25 19:18:07 +03:00
Gabriel Adrian Samfira
6fee10c737 Fix double creation of pools
This change fixes the creation of pools though the UI. Both the modal and
the page were sending a request to create the pool, leading to double pool.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-25 16:12:01 +00:00
dependabot[bot]
642b3bbf92
Bump github.com/stretchr/testify from 1.10.0 to 1.11.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.10.0 to 1.11.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.10.0...v1.11.0)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-version: 1.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 11:54:27 +00:00
Gabriel
1fceec374d
Merge pull request #495 from gabriel-samfira/caching-and-fixes
Attempt to use the scalset API and caching
2025-08-25 01:45:46 +03:00
Gabriel Adrian Samfira
d05df36868 Attempt to use the scalset API and caching
On github, attempt to use the scaleset API to list all runners without
pagination. This will avoid missing runners and accidentally removing them.

Fall back to paginated API if we can't use the scaleset API.

Add ability to retrieve all instances from cache, for an entity.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-24 22:36:44 +00:00
Gabriel
5c703f310b
Merge pull request #494 from gabriel-samfira/small-fixes
Small fixes
2025-08-24 11:53:21 +03:00
Gabriel Adrian Samfira
86a0b0cf4f Small fixes
* Shut down the web server first to prevent errors caused by clients trying
to use functionality that has already been shut down, causing errors and
potentially delaying the shutdown process.
* remove write timeout from the websocket Write() function.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-24 08:35:17 +00:00
Gabriel
5a26614acf
Merge pull request #493 from gabriel-samfira/ensure-scale-set
Ensure scale set exists
2025-08-23 22:12:30 +03:00
Gabriel Adrian Samfira
39003f006a Ensure scale set exists
Github will remove inactive scale sets after 7 days. This change
ensures the scale set exists in github before spinning up the listener.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-23 18:55:08 +00:00
Gabriel
c48bb50f2a
Merge pull request #492 from gabriel-samfira/add-webui-tests
Add webui tests
2025-08-22 00:18:57 +03:00
Gabriel Adrian Samfira
54c6571ccd Update test workflow
Add steps to test the Web UI and to run go generate.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-21 21:00:27 +00:00
Gabriel Adrian Samfira
8d5c6b6738 Bump go version to 1.24.6 and run go generate
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-21 20:36:50 +00:00
Gabriel Adrian Samfira
48769587bb Add web UI tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-21 20:36:50 +00:00
Gabriel
9aa2e297b9
Merge pull request #491 from igrikus/main
fix(jobs): Correctly handle workflow job IDs from webhooks
2025-08-21 22:04:35 +03:00
Gabriel Adrian Samfira
4341b4869c Fix erroneous calls to Job related functions
Some functions were left behind when we added WorkflowJobID.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-21 18:57:42 +00:00
igrikus
8bda81d6cc fix(jobs): Correctly handle workflow job IDs from webhooks 2025-08-21 14:54:38 +02:00
Gabriel
004c03962f
Merge pull request #488 from gabriel-samfira/remove-deprecated
Replace ${base} with resolve()
2025-08-18 16:09:32 +03:00
Gabriel Adrian Samfira
69a2c509a7 Replace ${base} with resolve()
This removes some deprecated code.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-18 13:08:58 +00:00
Gabriel
b8ff6d9e14
Merge pull request #487 from gabriel-samfira/small-fixes
Fix href for entities
2025-08-18 15:03:24 +03:00
Gabriel Adrian Samfira
9028ef64b1 Fix href for entities
The URL from scale sets and pools to the entity to which they belong
was not being properly resolved.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-18 12:02:08 +00:00
Gabriel
eeed5ae508
Merge pull request #486 from gabriel-samfira/small-fixes
Fix endpoint type name and update cookie
2025-08-18 01:28:47 +03:00
Gabriel Adrian Samfira
04d1042a4c Fix endpoint type name and update cookie
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-17 22:27:17 +00:00
Gabriel
102c430e1d
Merge pull request #485 from gabriel-samfira/ui-fixes
Slightly better error handling
2025-08-17 10:42:33 +03:00
Gabriel Adrian Samfira
7f647941f6 Slightly better error handling
Extract error details we get from the API when status code > 2xx.
Also, use toast messages to display the error, properly close delete
modals and prevent full page display of error messages.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-17 07:34:40 +00:00
Gabriel
8cf0b0a56e
Merge pull request #484 from gabriel-samfira/remove-all-flag-scalesets
Remove the --all flag for scalesets
2025-08-17 02:20:16 +03:00
Gabriel Adrian Samfira
f805123a85 Remove the --all flag for scalesets
Display all scalesets by default, similar to runners and pools.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-16 23:13:47 +00:00
Gabriel
6b49c21206
Merge pull request #483 from gabriel-samfira/fix-inconsistency
Allow referencing runners by ID
2025-08-17 02:08:02 +03:00
Gabriel Adrian Samfira
31ad45eeb6 Allow referencing runners by ID
Although runner names are unique, we still have an ID on the model
which is used as a primary key. We should allow using that ID to
reference a runner in the API.

This change allows users to specify ID or runner name.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-16 23:00:55 +00:00
Gabriel
b4113048bb
Merge pull request #482 from gabriel-samfira/switch-to-fmt-errorf
Switch to fmt.Errorf
2025-08-17 01:28:22 +03:00
Gabriel Adrian Samfira
118319c7c1 Switch to fmt.Errorf
Replace all instances of errors.Wrap() with fmt.Errorf.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-16 22:19:05 +00:00
Gabriel
10dcbec954
Merge pull request #481 from cloudbase/dependabot/npm_and_yarn/webapp/npm_and_yarn-2ea0fb2c37
Bump the npm_and_yarn group across 1 directory with 2 updates
2025-08-16 14:31:17 +03:00
dependabot[bot]
b58bf4c895
Bump the npm_and_yarn group across 1 directory with 2 updates
Bumps the npm_and_yarn group with 2 updates in the /webapp directory: [tmp](https://github.com/raszi/node-tmp) and [@openapitools/openapi-generator-cli](https://github.com/OpenAPITools/openapi-generator-cli).


Removes `tmp`

Updates `@openapitools/openapi-generator-cli` from 2.21.4 to 2.22.0
- [Release notes](https://github.com/OpenAPITools/openapi-generator-cli/releases)
- [Changelog](https://github.com/OpenAPITools/openapi-generator-cli/blob/master/.releaserc)
- [Commits](https://github.com/OpenAPITools/openapi-generator-cli/compare/v2.21.4...v2.22.0)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: "@openapitools/openapi-generator-cli"
  dependency-version: 2.22.0
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-16 10:25:06 +00:00
Gabriel
8cc96dbcd1
Merge pull request #479 from gabriel-samfira/spa-webapp
Spa webapp
2025-08-16 13:23:42 +03:00
Gabriel Adrian Samfira
eec158b32c Add SPA UI for GARM
This change adds a single page application front-end to GARM. It uses
a generated REST client, built from the swagger definitions, the websocket
interface for live updates of entities and eager loading of everything
except runners, as users may have many runners and we don't want to load
hundreds of runners in memory.

Proper pagination should be implemented in the API, in future commits,
to avoid loading lots of elements for no reason.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-16 09:09:13 +00:00
Gabriel Adrian Samfira
a811d129d0 Update .gitignore
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-12 12:48:48 +00:00
Gabriel Adrian Samfira
98a769b8d1 Allow cookie login to API endpoints
This change considers cookies as a source for the JWT token.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-12 12:48:48 +00:00
Gabriel Adrian Samfira
5a6ac12118 Fix for gitea tools and scale set cleanup
Filter out gitea tools to only consider archived downloads. This
should help in situations where bandwidth is more important than
CPU time used to unarchive the tools.

Also a drive by fix for scale sets cleanup.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-12 12:48:48 +00:00
Gabriel Adrian Samfira
325bca4af3 Add swagger annotations and updates
Add swagger annotations to models to allow generating a full swagger
definition. This will help generate clients in other languages if needed.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-12 12:48:48 +00:00
Gabriel Adrian Samfira
b2dee1d844 Preload missing resources
There are some inconsistencies in the way the API returns some
values for pools and scale sets. This is due to not preloading
the appropriate relations.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-12 12:48:48 +00:00
Gabriel
9f2764f614
Merge pull request #478 from cloudbase/dependabot/go_modules/github.com/go-openapi/errors-0.22.2
Bump github.com/go-openapi/errors from 0.22.1 to 0.22.2
2025-08-11 21:20:33 +03:00
dependabot[bot]
37eba0fed9
Bump github.com/go-openapi/errors from 0.22.1 to 0.22.2
Bumps [github.com/go-openapi/errors](https://github.com/go-openapi/errors) from 0.22.1 to 0.22.2.
- [Commits](https://github.com/go-openapi/errors/compare/v0.22.1...v0.22.2)

---
updated-dependencies:
- dependency-name: github.com/go-openapi/errors
  dependency-version: 0.22.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 10:34:11 +00:00
Gabriel
389a8538af
Merge pull request #476 from cloudbase/dependabot/go_modules/golang.org/x/crypto-0.41.0
Bump golang.org/x/crypto from 0.40.0 to 0.41.0
2025-08-08 12:54:56 +03:00
dependabot[bot]
f24a22d537
Bump golang.org/x/crypto from 0.40.0 to 0.41.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.40.0 to 0.41.0.
- [Commits](https://github.com/golang/crypto/compare/v0.40.0...v0.41.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.41.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-08 09:47:38 +00:00
Gabriel
dfa9848999
Merge pull request #477 from cloudbase/dependabot/go_modules/golang.org/x/mod-0.27.0
Bump golang.org/x/mod from 0.26.0 to 0.27.0
2025-08-08 12:46:12 +03:00
dependabot[bot]
3f51046279
Bump golang.org/x/mod from 0.26.0 to 0.27.0
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.26.0 to 0.27.0.
- [Commits](https://github.com/golang/mod/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.27.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-08 06:49:58 +00:00
Gabriel
256521ac38
Merge pull request #475 from cloudbase/dependabot/go_modules/github.com/cloudbase/garm-provider-common-0.1.7
Bump github.com/cloudbase/garm-provider-common from 0.1.6 to 0.1.7
2025-08-07 15:34:27 +03:00
dependabot[bot]
e2169865a1
Bump github.com/cloudbase/garm-provider-common from 0.1.6 to 0.1.7
Bumps [github.com/cloudbase/garm-provider-common](https://github.com/cloudbase/garm-provider-common) from 0.1.6 to 0.1.7.
- [Release notes](https://github.com/cloudbase/garm-provider-common/releases)
- [Commits](https://github.com/cloudbase/garm-provider-common/compare/v0.1.6...v0.1.7)

---
updated-dependencies:
- dependency-name: github.com/cloudbase/garm-provider-common
  dependency-version: 0.1.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-07 07:05:40 +00:00
Gabriel
fd9a4d544a
Merge pull request #474 from gabriel-samfira/fix-image-tag
Get the image tag from supplied ref
2025-08-07 00:13:51 +03:00
Gabriel Adrian Samfira
20a16d923c
Get the image tag from supplied ref
We need to pass the ref used in the workflow. If we supply a tag,
we should just get that same tag. If we supply a branch, we should
get the latest release from that branch.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-07 00:12:35 +03:00
Gabriel
212f6fff42
Merge pull request #473 from gabriel-samfira/fix-build-image
Use the Dockerfile from the main branch
2025-08-06 23:11:29 +03:00
Gabriel Adrian Samfira
2ee2fca8ae
Use the Dockerfile from the main branch
There is no way to change the Dockerfile in a tag. We need to
use the Dockerfile in the main branch. So even if we're buildin
the image for a stable version, we need to check out the main branch.

The Dockerfile will take care of checking out the proper tags.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-06 23:09:01 +03:00
Gabriel Adrian Samfira
5915107446
WiP
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-08-06 23:03:45 +03:00
Gabriel
e43acd5b65
Merge pull request #472 from cloudbase/dependabot/go_modules/github.com/prometheus/client_golang-1.23.0
Bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0
2025-08-01 10:10:35 +03:00
dependabot[bot]
f85fe3d63f
Bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.22.0 to 1.23.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/v1.23.0/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.22.0...v1.23.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-01 06:26:29 +00:00
Gabriel
8082e1a30e
Merge pull request #456 from chickenkiller/feat/refactor-builds
Refactor CI/CD builds
2025-07-31 10:58:16 +03:00
Gabriel
daf2a13e48
Merge pull request #471 from cloudbase/dependabot/go_modules/github.com/golang-jwt/jwt/v5-5.3.0
Bump github.com/golang-jwt/jwt/v5 from 5.2.3 to 5.3.0
2025-07-31 10:14:59 +03:00
dependabot[bot]
4ad7d8e856
Bump github.com/golang-jwt/jwt/v5 from 5.2.3 to 5.3.0
Bumps [github.com/golang-jwt/jwt/v5](https://github.com/golang-jwt/jwt) from 5.2.3 to 5.3.0.
- [Release notes](https://github.com/golang-jwt/jwt/releases)
- [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md)
- [Commits](https://github.com/golang-jwt/jwt/compare/v5.2.3...v5.3.0)

---
updated-dependencies:
- dependency-name: github.com/golang-jwt/jwt/v5
  dependency-version: 5.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-31 07:04:47 +00:00
Lionel ORRY
22f655f48d fixes after testing 2025-07-31 08:42:16 +02:00
Lionel ORRY
158b35db06 simplify workflows 2025-07-30 14:35:01 +02:00
Lionel ORRY
eb07ed3774 remove obsolete tech debt 2025-07-30 12:12:03 +02:00
Lionel ORRY
0f4f98dd03 put a better git version in providers 2025-07-30 12:12:02 +02:00
Lionel ORRY
f6f22cb686 small fixes 2025-07-30 12:09:34 +02:00
Lionel ORRY
af1c090db5 transfer providers branch computation inside Dockerfile 2025-07-30 12:09:32 +02:00
Lionel ORRY
be3026e87c fix branch names 2025-07-30 12:04:02 +02:00
Lionel ORRY
5152bab1b8 fix branch names 2025-07-30 12:04:02 +02:00
Lionel ORRY
3687c7fea4 activate release/v2 nightly build 2025-07-30 12:04:02 +02:00
Lionel ORRY
1e8d0d79a6 improvements after review comments 2025-07-30 12:04:02 +02:00
Lionel ORRY
97ef92706b refactor workflows to enable multiple docker images 2025-07-30 12:04:00 +02:00
Gabriel
53cdfd70a1
Merge pull request #470 from cloudbase/dependabot/go_modules/github.com/jedib0t/go-pretty/v6-6.6.8
Bump github.com/jedib0t/go-pretty/v6 from 6.6.7 to 6.6.8
2025-07-28 12:30:47 +03:00
dependabot[bot]
7817d20516
Bump github.com/jedib0t/go-pretty/v6 from 6.6.7 to 6.6.8
Bumps [github.com/jedib0t/go-pretty/v6](https://github.com/jedib0t/go-pretty) from 6.6.7 to 6.6.8.
- [Release notes](https://github.com/jedib0t/go-pretty/releases)
- [Commits](https://github.com/jedib0t/go-pretty/compare/v6.6.7...v6.6.8)

---
updated-dependencies:
- dependency-name: github.com/jedib0t/go-pretty/v6
  dependency-version: 6.6.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-28 08:04:00 +00:00
Gabriel
daadad682b
Merge pull request #468 from cloudbase/dependabot/go_modules/gorm.io/gorm-1.30.1
Bump gorm.io/gorm from 1.30.0 to 1.30.1
2025-07-24 09:55:44 +03:00
dependabot[bot]
f4892be193
Bump gorm.io/gorm from 1.30.0 to 1.30.1
Bumps [gorm.io/gorm](https://github.com/go-gorm/gorm) from 1.30.0 to 1.30.1.
- [Release notes](https://github.com/go-gorm/gorm/releases)
- [Commits](https://github.com/go-gorm/gorm/compare/v1.30.0...v1.30.1)

---
updated-dependencies:
- dependency-name: gorm.io/gorm
  dependency-version: 1.30.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-24 06:47:05 +00:00
Gabriel
e687565671
Merge pull request #467 from cloudbase/dependabot/go_modules/github.com/cloudbase/garm-provider-common-0.1.6
Bump github.com/cloudbase/garm-provider-common from 0.1.5 to 0.1.6
2025-07-21 11:45:24 +03:00
dependabot[bot]
567c465ad7
Bump github.com/cloudbase/garm-provider-common from 0.1.5 to 0.1.6
Bumps [github.com/cloudbase/garm-provider-common](https://github.com/cloudbase/garm-provider-common) from 0.1.5 to 0.1.6.
- [Release notes](https://github.com/cloudbase/garm-provider-common/releases)
- [Commits](https://github.com/cloudbase/garm-provider-common/compare/v0.1.5...v0.1.6)

---
updated-dependencies:
- dependency-name: github.com/cloudbase/garm-provider-common
  dependency-version: 0.1.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 07:58:08 +00:00
Gabriel
f1fed3c462
Merge pull request #466 from gabriel-samfira/update-docs-and-defaults
Update docs and deprecate the --all flag
2025-07-20 23:38:50 +03:00
Gabriel Adrian Samfira
80735ac2eb Update docs and deprecate the --all flag
Update the docs to reflect the latest stable version and deprecate the
--all flag for runner list and pool list.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-07-20 20:31:56 +00:00
Gabriel
bb45324dcd
Merge pull request #459 from gabriel-samfira/account-for-job-id
Handle new jobID for scale sets
2025-07-18 11:39:06 +03:00
Gabriel Adrian Samfira
a984782fd7 Handle new jobID for scale sets
There seems to be a change in the scale set message. It now includes
a jobID and sets the runner request ID to 0. This change adds separate
job ID fields for workflow jobs and scaleset jobs.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-07-18 08:20:50 +00:00
Gabriel
d26973da2a
Merge pull request #458 from gabriel-samfira/fix-scaleset-param
Fix scale set param
2025-07-17 20:06:14 +03:00
Gabriel Adrian Samfira
69779a0a7d Fix scale set param
Do not look for a name when composing the scale set. Preload may not
have been called on an entity, but we still have the ID, which is the
only thing needed when GetEntity() is called.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-07-17 17:01:20 +00:00
Gabriel
c95252547e
Merge pull request #454 from gabriel-samfira/fix-encoding
Handle query args
2025-07-16 17:52:02 +03:00
Gabriel
d17b168b4e
Merge pull request #453 from cloudbase/dependabot/go_modules/github.com/golang-jwt/jwt/v5-5.2.3
Bump github.com/golang-jwt/jwt/v5 from 5.2.2 to 5.2.3
2025-07-16 10:36:26 +03:00
dependabot[bot]
a46c474640
Bump github.com/golang-jwt/jwt/v5 from 5.2.2 to 5.2.3
Bumps [github.com/golang-jwt/jwt/v5](https://github.com/golang-jwt/jwt) from 5.2.2 to 5.2.3.
- [Release notes](https://github.com/golang-jwt/jwt/releases)
- [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md)
- [Commits](https://github.com/golang-jwt/jwt/compare/v5.2.2...v5.2.3)

---
updated-dependencies:
- dependency-name: github.com/golang-jwt/jwt/v5
  dependency-version: 5.2.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-16 06:41:38 +00:00
Gabriel Adrian Samfira
65d6d1ae87 Handle query args
Merge any query args from both the GH url and the supplied URL.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-07-16 06:39:46 +00:00
Gabriel
78547fefaa
Merge pull request #450 from cloudbase/dependabot/go_modules/golang.org/x/mod-0.26.0
Bump golang.org/x/mod from 0.25.0 to 0.26.0
2025-07-11 14:48:26 +03:00
dependabot[bot]
0cc51e48ef
Bump golang.org/x/mod from 0.25.0 to 0.26.0
---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.26.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-11 09:34:59 +00:00
Gabriel
86b8ac9e94
Merge pull request #451 from cloudbase/dependabot/go_modules/golang.org/x/crypto-0.40.0
Bump golang.org/x/crypto from 0.39.0 to 0.40.0
2025-07-11 12:33:37 +03:00
dependabot[bot]
f9b1b26f80
Bump golang.org/x/crypto from 0.39.0 to 0.40.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.39.0 to 0.40.0.
- [Commits](https://github.com/golang/crypto/compare/v0.39.0...v0.40.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-11 06:28:17 +00:00
Gabriel
19e025c2be
Merge pull request #448 from gabriel-samfira/fix-sleep
Fix sleepWithCancel and ensure closed channel
2025-07-07 08:02:32 +03:00
Gabriel Adrian Samfira
b23bca73bc Fix sleepWithCancel and ensure closed channel
* time.NewTicker will panic if the duration is 0. Make it return
early if duration is 0.
* Return a pre-closed channel in Wait() instead of nil. Ensures receiver
will not block forever.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-07-07 04:54:10 +00:00
Gabriel
20d4e68fd4
Merge pull request #447 from gabriel-samfira/fix-makefile
Use the -v flag on podman only
2025-07-07 00:26:46 +03:00
Gabriel Adrian Samfira
6ae3b25b4d Use the -v flag on podman only
Docker does not support the --volume flag at build time. This needs
to be done in the Dockerfile directly on the RUN stanza. Will update
in a future PR, until then, just set the flag for podman.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-07-06 21:17:31 +00:00
Gabriel
e14f3858ef
Merge pull request #446 from gabriel-samfira/fix-url-composition
Use JoinPath() and relative paths
2025-07-06 22:56:35 +03:00
Gabriel Adrian Samfira
18902f884a Use JoinPath() and relative paths
Use JoinPath() in newActionsRequest() and make sure we pass relative
paths to it. This should fix scale sets on GHES.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-07-06 19:22:43 +00:00
Gabriel
379c39095e
Merge pull request #444 from chickenkiller/fix-podman
improve usability of podman in Makefile
2025-07-02 15:15:16 +03:00
Lionel ORRY
3853f8bd94 improve usability of podman in Makefile 2025-07-02 14:04:41 +02:00
Gabriel
9f5cf64542
Merge pull request #441 from cloudbase/dependabot/go_modules/gorm.io/datatypes-1.2.6
Bump gorm.io/datatypes from 1.2.5 to 1.2.6
2025-07-01 12:50:30 +03:00
dependabot[bot]
7c8241579d
Bump gorm.io/datatypes from 1.2.5 to 1.2.6
Bumps [gorm.io/datatypes](https://github.com/go-gorm/datatypes) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/go-gorm/datatypes/releases)
- [Commits](https://github.com/go-gorm/datatypes/compare/v1.2.5...v1.2.6)

---
updated-dependencies:
- dependency-name: gorm.io/datatypes
  dependency-version: 1.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 09:02:05 +00:00
Gabriel
25e7befa08
Merge pull request #440 from gabriel-samfira/forward-port-439
Set http transport config
2025-06-27 11:27:48 +03:00
Gabriel Adrian Samfira
529ce8b7a8 Set http transport config
This change sets the github client http transport options to mirror those
of the default transport from Go, with the addition of the TLSClientConfig.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-06-27 08:19:45 +00:00
Gabriel
42839917f3
Merge pull request #437 from gabriel-samfira/several-fixes
Some cleanup
2025-06-21 20:54:03 +03:00
Gabriel Adrian Samfira
1ec99e8695 Some cleanup
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-06-21 17:31:26 +00:00
Gabriel
6c104b6ece
Merge pull request #432 from gabriel-samfira/use-friendly-names
Allow usage of friendly names in most commands
2025-06-21 20:15:14 +03:00
Gabriel Adrian Samfira
808af82e0d Add endpoint option to all relevant commands
In case of ambiguity when using the name of a repo, org or enterprise,
an --endpoint flag can be used to uniquely identify an entity against
an endpoint.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-06-21 17:05:22 +00:00
Gabriel
7c2086bc64
Merge pull request #436 from cloudbase/dependabot/go_modules/github.com/cloudbase/garm-provider-common-0.1.5
Bump github.com/cloudbase/garm-provider-common from 0.1.5-0.20250417155201-8ef03502d06e to 0.1.5
2025-06-20 14:08:02 +03:00
dependabot[bot]
ed924e8034
Bump github.com/cloudbase/garm-provider-common
Bumps [github.com/cloudbase/garm-provider-common](https://github.com/cloudbase/garm-provider-common) from 0.1.5-0.20250417155201-8ef03502d06e to 0.1.5.
- [Release notes](https://github.com/cloudbase/garm-provider-common/releases)
- [Commits](https://github.com/cloudbase/garm-provider-common/commits/v0.1.5)

---
updated-dependencies:
- dependency-name: github.com/cloudbase/garm-provider-common
  dependency-version: 0.1.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-20 07:08:08 +00:00
Gabriel Adrian Samfira
e92b2c1111 Allow usage of friendly names in most commands
This change adds the ability to use the repo/org/enterprise names
instead of UUID in most garm-cli commands, at the expense of an extra
list API call, leveraging the recently added filter options.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-06-19 09:27:18 +00:00
Gabriel
43a2343828
Merge pull request #431 from gabriel-samfira/add-filter-option
Add a rudimentary filter option when listing entities
2025-06-19 00:34:56 +03:00
Gabriel Adrian Samfira
499fbde60c Add a rudimentary filter option when listing entities
This change adds the ability to filter the list of entities returned
by the API by entity owner, name or endpoint, depending on the entity
type.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-06-18 21:23:34 +00:00
Gabriel
2fd0e720e6
Merge pull request #430 from gabriel-samfira/update-deps
Update dependencies
2025-06-18 00:15:19 +03:00
Gabriel Adrian Samfira
d42160cab2 Update dependencies
This change updates all dependencies.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-06-17 21:09:05 +00:00
Gabriel
e3833e5e48
Merge pull request #429 from tormath1/tormath1/doc
doc/gitea: remove 'version'
2025-06-12 20:17:43 +03:00
Mathieu Tortuyaux
98fa085bc7
doc/gitea: remove 'version'
This field is deprecated:
```
$ docker compose version
Docker Compose version v2.36.2
...
WARN[0000] /home/core/docker-compose.yaml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
```

Signed-off-by: Mathieu Tortuyaux <mtortuyaux@microsoft.com>
2025-06-12 09:53:59 +02:00
Gabriel
d13ea92a54
Merge pull request #428 from tormath1/tormath1/linode
readme: add akamai/linode experimental external provider
2025-06-11 07:25:13 +03:00
Mathieu Tortuyaux
4c536f2584
readme: add Akamai/Linode external provider
The provider is quite new and awaits for feedback, let's mention the
"experimental" status.

Signed-off-by: Mathieu Tortuyaux <mtortuyaux@microsoft.com>
2025-06-10 17:59:29 +02:00
Mathieu Tortuyaux
043359936b
readme: sort external providers
Signed-off-by: Mathieu Tortuyaux <mtortuyaux@microsoft.com>
2025-06-10 17:58:11 +02:00
Gabriel
1c2f349d56
Merge pull request #413 from cloudbase/dependabot/go_modules/gorm.io/gorm-1.30.0
Bump gorm.io/gorm from 1.26.1 to 1.30.0
2025-05-29 21:38:15 +03:00
Gabriel
be86709bdf
Merge pull request #419 from gabriel-samfira/enable-tests-in-release
Trigger tests on release branches
2025-05-29 20:15:00 +03:00
Gabriel Adrian Samfira
48c4ea7d15 Trigger tests on release branches
This change triggers tests for PRs created against release/* branches.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-29 17:07:46 +00:00
Gabriel
c19bf2f9f8
Merge pull request #416 from ChristopherHX/optional-forge-type-for-gitea
Create Repo / Org make --forge-type optional
2025-05-29 20:04:51 +03:00
Christopher Homberger
efd725ea94 Create Repo / Org make --forge-type optional
* This makes gitea garm usage unnessary complex

Signed-off-by: Christopher Homberger <christopher.homberger@web.de>
2025-05-29 18:36:25 +02:00
dependabot[bot]
914f7fbd49
Bump gorm.io/gorm from 1.26.1 to 1.30.0
Bumps [gorm.io/gorm](https://github.com/go-gorm/gorm) from 1.26.1 to 1.30.0.
- [Release notes](https://github.com/go-gorm/gorm/releases)
- [Commits](https://github.com/go-gorm/gorm/compare/v1.26.1...v1.30.0)

---
updated-dependencies:
- dependency-name: gorm.io/gorm
  dependency-version: 1.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-26 06:15:56 +00:00
Gabriel
18ef27bb91
Merge pull request #412 from gabriel-samfira/allow-deleting-default-ep
Make the default github endpoint mutable
2025-05-25 01:32:23 +03:00
Gabriel Adrian Samfira
87055f23da Make the default github endpoint mutable
This change allows users to remove the default github endpoint
if no credentials are set on it.

A new protection is added on URLs of any endpoint that prevents their
update if the endpoint has credentials set.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-24 22:26:01 +00:00
Gabriel
b5bd373061
Merge pull request #411 from gabriel-samfira/add-logo
Experiment with a logo
2025-05-24 23:35:06 +03:00
Gabriel Adrian Samfira
ae69e8c473 Experiment with a logo
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-24 20:13:05 +00:00
Gabriel
451e7c4556
Merge pull request #408 from gabriel-samfira/fix-add-entity-event
Fix AddInstanceEvent and expose events
2025-05-22 22:24:36 +03:00
Gabriel Adrian Samfira
9921a7bfc8 Fix AddInstanceEvent and expose events
* We were passing the wrong type to GORM for events
* We now expose entity events in the API and CLI

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-22 19:19:24 +00:00
Gabriel
ed8e11e244
Merge pull request #405 from gabriel-samfira/ensure-token
Ensure that admin token exists
2025-05-22 00:38:47 +03:00
Gabriel Adrian Samfira
7e576dc631 Ensure that admin token exists
Make sure that the admin info is populated when calling GenerateJitRunnerConfig.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-21 21:29:43 +00:00
Gabriel
d8cb1c5acd
Merge pull request #404 from gabriel-samfira/fix-cli
Avoid nil pointer dereference in CLI
2025-05-21 23:58:56 +03:00
Gabriel Adrian Samfira
9660b28019 Avoid nil pointer dereference in CLI
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-21 20:58:21 +00:00
Gabriel
f5c3363249
Merge pull request #403 from cloudbase/gabriel-samfira-patch-1
Update Dockerfile
2025-05-21 23:46:43 +03:00
Gabriel
4e157fc4cc
Update Dockerfile 2025-05-21 23:46:29 +03:00
Gabriel
ac0caa2ed9
Merge pull request #402 from gabriel-samfira/fix-parse-error
Fix potential nil pointer dereference
2025-05-21 22:50:44 +03:00
Gabriel Adrian Samfira
cfe707e522 Fix potential nil pointer dereference
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-21 19:45:23 +00:00
Gabriel
8c16ee92b3
Merge pull request #400 from kaspar030/patch-1
Fix some typos in scalesets.md
2025-05-21 17:45:25 +03:00
Kaspar Schleiser
8e8d7fd364
Fix some typos in scalesets.md 2025-05-21 16:39:22 +02:00
Gabriel
7646ff4429
Merge pull request #399 from cloudbase/gabriel-samfira-patch-1
Update gitea.md
2025-05-21 13:52:45 +03:00
Gabriel
93768a2796
Update gitea.md 2025-05-21 13:52:15 +03:00
Gabriel
65aa92f517
Merge pull request #398 from gabriel-samfira/add-docker-compose-example
Add examples for setting up GARM with Gitea
2025-05-21 13:28:48 +03:00
Gabriel Adrian Samfira
1c758d010a Add examples for setting up GARM with Gitea
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-21 10:27:59 +00:00
Gabriel
c85aea2d26
Merge pull request #396 from cloudbase/fix-schedule
Use default values for ref and push to project
2025-05-21 11:10:53 +03:00
Gabriel
f95bfee0d9
Merge pull request #397 from cloudbase/dependabot/go_modules/golang.org/x/mod-0.24.0
Bump golang.org/x/mod from 0.17.0 to 0.24.0
2025-05-21 09:43:07 +03:00
dependabot[bot]
4cf1468907
Bump golang.org/x/mod from 0.17.0 to 0.24.0
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.17.0 to 0.24.0.
- [Commits](https://github.com/golang/mod/compare/v0.17.0...v0.24.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.24.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-21 06:30:29 +00:00
Gabriel Adrian Samfira
c5c35f1324 Use default values for ref and push to project
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-21 05:03:07 +00:00
Gabriel
0068119c34
Merge pull request #395 from gabriel-samfira/add-cli-to-docker-image
Add CLI to docker image
2025-05-21 00:15:54 +03:00
Gabriel Adrian Samfira
269c6064e7 Add CLI to docker image
This change adds the GARM cli to the docker image.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-20 21:15:08 +00:00
Gabriel
b7798404f8
Merge pull request #394 from cloudbase/update-build-and-push
Allow for nightly builds
2025-05-20 23:20:55 +03:00
Gabriel Adrian Samfira
bdcc817def Enable daily cron
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-20 20:10:08 +00:00
Gabriel Adrian Samfira
b41318c948 Allow for nightly builds
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-20 17:00:59 +00:00
Gabriel
dee6bf7c9a
Merge pull request #393 from gabriel-samfira/add-gitea
Add gitea
2025-05-20 19:26:46 +03:00
Gabriel Adrian Samfira
1fc72ab5c8 Add more tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-20 16:12:45 +00:00
Gabriel Adrian Samfira
1fe09548bc Add more tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-20 13:52:16 +00:00
Gabriel Adrian Samfira
b4268e6bab Fix tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-20 09:52:13 +00:00
Gabriel Adrian Samfira
6994c8ce05 Add copyright header
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-20 09:43:29 +00:00
Gabriel Adrian Samfira
f0753eeb22 Add more tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-20 09:22:55 +00:00
Gabriel Adrian Samfira
b2d5609352 Add some tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-19 19:45:45 +00:00
Gabriel Adrian Samfira
bb798a288a Properly set webhook secret
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-16 23:58:39 +00:00
Gabriel Adrian Samfira
6a168ba813 Enable orgs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-16 23:02:01 +00:00
Gabriel Adrian Samfira
5dfcfc542e Implement webhooks install for gitea
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-16 20:24:11 +00:00
Gabriel Adrian Samfira
08511e2e7f Account for gitea credentials in cache and watchers
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-15 09:15:44 +00:00
Gabriel Adrian Samfira
b4e92a69c9 Fix existing tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-14 23:20:18 +00:00
Gabriel Adrian Samfira
0270117e8d Fix lint errors
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-14 22:01:11 +00:00
Gabriel Adrian Samfira
39ac658527 Add forge type to repo list
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-14 21:33:46 +00:00
Gabriel Adrian Samfira
3fe4cef884 Cleanup unused code
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-14 21:14:31 +00:00
Gabriel Adrian Samfira
f66b651b59 Fix findEndpointForJob
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-14 21:09:02 +00:00
Gabriel Adrian Samfira
56be5eb698 Do not load scalesets and runners in parallel
Both functions read and write to the same map. We should switch
to sync.Map

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-14 15:36:53 +00:00
Gabriel Adrian Samfira
8538a4ae8a Make sure websocket hub exits properly
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-14 15:22:27 +00:00
Gabriel Adrian Samfira
823a9e4b82 Add Gitea endpoints and credentials
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-14 00:34:54 +00:00
Gabriel Adrian Samfira
40e6581a75 Rename GitHub specific types
This change renames a lot of variables, types and functions to be more
generic. The goal is to allow GARM to add more forges in the future.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-12 21:47:13 +00:00
Gabriel Adrian Samfira
4890eb4732 Add EndpointType
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-12 17:32:37 +00:00
Gabriel Adrian Samfira
ef676488b7 Use cache for github client
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-10 20:08:51 +00:00
Gabriel
5dbaa351d2
Merge pull request #392 from gabriel-samfira/docs
Slight rewording
2025-05-10 09:15:11 +03:00
Gabriel Adrian Samfira
41700cd958 Slight rewording
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-10 06:14:38 +00:00
Gabriel
fd6f01d2c0
Merge pull request #391 from gabriel-samfira/add-some-docs
Add some info about scale sets
2025-05-10 00:29:19 +03:00
Gabriel Adrian Samfira
979c07adbe Add some info about scale sets
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-09 21:28:29 +00:00
Gabriel
6b4c4f610e
Merge pull request #390 from gabriel-samfira/add-some-parallel-startup
Load entities in parallel
2025-05-09 01:31:10 +03:00
Gabriel Adrian Samfira
68183384dc Load entities in parallel
This change uses an error group to load different DB resources
in parallel.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-08 22:26:40 +00:00
Gabriel
49147a015a
Merge pull request #389 from gabriel-samfira/fixes-and-rate-limits
Add rate limit cache and fixes
2025-05-09 00:49:28 +03:00
Gabriel Adrian Samfira
1a719567ff Add rate limit cache and fixes
This change adds a loop that keeps a cache of credentials rate limits
as reported by the github API. The cache is updated every 30 seconds
and is purely informational for the user.

This change also adds some caching improvements. Functions that return
values from the cache as lists, will now sort by ID or creation date.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-08 21:39:55 +00:00
Gabriel
16af8fd97f
Merge pull request #387 from gabriel-samfira/add-tools-update
Add tools update routine and cleanup logging
2025-05-08 11:35:41 +03:00
Gabriel Adrian Samfira
2e9535530d Fix entity update handler
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-08 08:27:41 +00:00
Gabriel Adrian Samfira
a38d72a01c Add runner group to the scale set list output
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-08 08:12:29 +00:00
Gabriel Adrian Samfira
52007f4ffa Add tools update routine and cleanup logging
This change adds an update routine in the cache worker, for github tools
downloads.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-07 23:07:58 +00:00
Gabriel
ffbb3b8d41
Merge pull request #386 from gabriel-samfira/add-cache-worker
Add cache worker
2025-05-07 11:31:18 +03:00
Gabriel Adrian Samfira
90200ffa71 Do not clobber pools and scaleset caches on update
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-07 08:15:29 +00:00
Gabriel Adrian Samfira
d0c9462a5d Add cache worker
Add dedicated worker to maintain cache.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-07 08:01:36 +00:00
Gabriel
e49b35d3d0
Merge pull request #376 from gabriel-samfira/scalesets
Add scale sets
2025-05-07 00:12:57 +03:00
Gabriel Adrian Samfira
2f2ff62411 Deduplicate code
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-06 20:59:41 +00:00
Gabriel Adrian Samfira
f7cd743a9c Add more tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-06 19:37:07 +00:00
Gabriel Adrian Samfira
a80b900ee9 Update dependencies
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-06 18:27:20 +00:00
Gabriel Adrian Samfira
0e1fa0018b Add some more caching, record scaleset jobs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-06 17:50:12 +00:00
Gabriel Adrian Samfira
2f3c74562e Add instance cache
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-05 23:34:53 +00:00
Gabriel Adrian Samfira
9f640965e2 revert main
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-05 21:12:20 +00:00
Gabriel Adrian Samfira
1d093cc336 Slight refactor; add creds cache worker
* Split the main function into a couple of more functions
* Add credentials, entity, pool and scaleset cache
* add credentials worker that updates the cache

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-05 18:21:57 +00:00
Gabriel Adrian Samfira
3b3095c546 Scale sets are unique within a runner group
You can have multiple scale sets with the same name, as long as
they live in different runner groups.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:57:50 +00:00
Gabriel Adrian Samfira
77895d9c89 Add more tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:41 +00:00
Gabriel Adrian Samfira
ff383ea493 Add db scaleset tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:41 +00:00
Gabriel Adrian Samfira
2a5e374ae6 Remove unused field
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:41 +00:00
Gabriel Adrian Samfira
c601f88cf7 Add more tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:41 +00:00
Gabriel Adrian Samfira
92d04c8e8d Add tests for cache and locking
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
059734f064 Add runner periodic cleanup check
Adds a periodic cleanup function that cross checks runners between github,
the provider and the GARM database. If an inconsistency is found, GARM will
attempt to fix it.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
73340da322 Add RateLimit() function to gh client
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
fafe98e62f Update go-github
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
22302fdd7a Add scaleset watcher to provider
Fixes provider not spawning runners for newly added scale set

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
64d1501b0e DeleteInstance should noop if error not found
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
4b1d51f1d0 Fix nil pointer deref
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
55b4e74066 Update mocks
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
884be62a4d Fix lint errors
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
a4ac85aa4a Update CLI to show scale sets
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
f2ad7a3481 Fix leftover instances and refactor
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
004ad1f124 Add provider worker code
Runners now get created and cleaned up in scale sets.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
436fd7746f WiP
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
020210d6ad Handle scale up and down; add provider worker
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
7376a5fe74 Fix scale set restart logic
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
bc470c5f78 WiP
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
8c62b6de8c Obey enabled/disabled status
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
d949cecbe7 Keep a cache of runners in the scaleset worker
We will need to run various checks against the runners that are managed
by a scale set. The runners are updated by the DB watcher, so we should
always have an up to date view of their state. We can then confidently
monitor them without needing to query the DB.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
94f264d444 Handle JobStarted and JobCompleted
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
8d10dd4716 Update garm-provider-common
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
fc4bd863aa Add some db functions to handle scaleset instances
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
c177c31147 Add some message handling
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
12f40a5352 Fix refresh session
It seems that Status is a string when you create a session, but a number
when you refresh it (?).

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
19ba210804 Several fixes
* Close response body in scaleset client
* Wait for message listener loop to exit before attempting restart
* Add LastMessageID field to scaleset model and function to update it

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
a2aeac731c Scale set workers properly come online
This adds the workers needed to start listening for scale set messages.
There is no handling of messages yet.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
6a5c309399 Add some worker code
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
7174e030e2 Add scaleset commands
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
7e1a83c79a Add API endpoint for some scaleset ops
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
85eac363d5 Add ScaleSet models, functions and types
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
5ba53adf84 Switch to locking package
The locking logic was added to its own package as it may need to be used
by other parts of the code.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
e51f19acc8 Fix lint errors
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
d7d6d1e31a Add mocks
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
51c7d2a806 Add scaleset types
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel Adrian Samfira
79b9a1583c Add scaleset client
This change moves the github client to a subpackage in utils
and adds the scaleset github client code.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-03 22:29:40 +00:00
Gabriel
cc1470fe08
Merge pull request #382 from gabriel-samfira/set-base-url
set base URL in ghinstallation transport
2025-05-04 01:28:16 +03:00
Gabriel Adrian Samfira
2f1f61bfc6
set base URL in ghinstallation transport
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-05-04 00:51:25 +03:00
Gabriel
0d53dce16f
Merge pull request #378 from gabriel-samfira/update-deps
Update all dependencies
2025-04-17 18:12:49 +03:00
Gabriel Adrian Samfira
d27bd40531
Update all dependencies
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-04-17 18:07:33 +03:00
Gabriel
4bedb86cf0
Merge pull request #372 from cloudbase/dependabot/go_modules/github.com/prometheus/client_golang-1.22.0
Bump github.com/prometheus/client_golang from 1.21.1 to 1.22.0
2025-04-14 10:51:46 +03:00
dependabot[bot]
b2f84264d4
Bump github.com/prometheus/client_golang from 1.21.1 to 1.22.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.21.1 to 1.22.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.21.1...v1.22.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-09 06:27:01 +00:00
Gabriel
69f6b4f541
Merge pull request #370 from cloudbase/dependabot/go_modules/golang.org/x/oauth2-0.29.0
Bump golang.org/x/oauth2 from 0.28.0 to 0.29.0
2025-04-07 10:56:50 +03:00
dependabot[bot]
595cf51be0
Bump golang.org/x/oauth2 from 0.28.0 to 0.29.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.28.0 to 0.29.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.28.0...v0.29.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-version: 0.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 07:52:29 +00:00
Gabriel
52cf0f5163
Merge pull request #371 from cloudbase/dependabot/go_modules/golang.org/x/crypto-0.37.0
Bump golang.org/x/crypto from 0.36.0 to 0.37.0
2025-04-07 10:51:16 +03:00
dependabot[bot]
4c5c3a0e93
Bump golang.org/x/crypto from 0.36.0 to 0.37.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.36.0 to 0.37.0.
- [Commits](https://github.com/golang/crypto/compare/v0.36.0...v0.37.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 07:46:55 +00:00
Gabriel
16d9b6d650
Merge pull request #369 from cloudbase/dependabot/go_modules/golang.org/x/sync-0.13.0
Bump golang.org/x/sync from 0.12.0 to 0.13.0
2025-04-07 10:45:44 +03:00
dependabot[bot]
6064c07611
Bump golang.org/x/sync from 0.12.0 to 0.13.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.12.0 to 0.13.0.
- [Commits](https://github.com/golang/sync/compare/v0.12.0...v0.13.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-version: 0.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 07:11:47 +00:00
Gabriel
aeaf594f3b
Merge pull request #368 from cloudbase/dependabot/go_modules/go_modules-ba6d682d0f
Bump github.com/golang-jwt/jwt/v4 from 4.5.1 to 4.5.2 in the go_modules group
2025-03-22 20:23:18 +02:00
dependabot[bot]
cad9965497
Bump github.com/golang-jwt/jwt/v4 in the go_modules group
Bumps the go_modules group with 1 update: [github.com/golang-jwt/jwt/v4](https://github.com/golang-jwt/jwt).


Updates `github.com/golang-jwt/jwt/v4` from 4.5.1 to 4.5.2
- [Release notes](https://github.com/golang-jwt/jwt/releases)
- [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md)
- [Commits](https://github.com/golang-jwt/jwt/compare/v4.5.1...v4.5.2)

---
updated-dependencies:
- dependency-name: github.com/golang-jwt/jwt/v4
  dependency-type: indirect
  dependency-group: go_modules
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-22 05:16:51 +00:00
Gabriel
17f3f3e0fa
Merge pull request #367 from cloudbase/dependabot/go_modules/go_modules-036d30de33
Bump github.com/golang-jwt/jwt/v5 from 5.2.1 to 5.2.2 in the go_modules group
2025-03-22 07:15:56 +02:00
dependabot[bot]
1c0d56237c
Bump github.com/golang-jwt/jwt/v5 in the go_modules group
Bumps the go_modules group with 1 update: [github.com/golang-jwt/jwt/v5](https://github.com/golang-jwt/jwt).


Updates `github.com/golang-jwt/jwt/v5` from 5.2.1 to 5.2.2
- [Release notes](https://github.com/golang-jwt/jwt/releases)
- [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md)
- [Commits](https://github.com/golang-jwt/jwt/compare/v5.2.1...v5.2.2)

---
updated-dependencies:
- dependency-name: github.com/golang-jwt/jwt/v5
  dependency-type: direct:production
  dependency-group: go_modules
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-21 22:11:26 +00:00
Gabriel
b168fad0aa
Merge pull request #366 from cloudbase/dependabot/go_modules/github.com/BurntSushi/toml-1.5.0
Bump github.com/BurntSushi/toml from 1.4.0 to 1.5.0
2025-03-21 13:39:21 +02:00
Gabriel
beeb82a9cb
Merge pull request #365 from cloudbase/dependabot/go_modules/github.com/go-openapi/errors-0.22.1
Bump github.com/go-openapi/errors from 0.22.0 to 0.22.1
2025-03-21 13:39:01 +02:00
Gabriel
587d432fb5
Merge pull request #364 from cloudbase/dependabot/go_modules/github.com/go-openapi/swag-0.23.1
Bump github.com/go-openapi/swag from 0.23.0 to 0.23.1
2025-03-21 13:38:40 +02:00
dependabot[bot]
76489fb3cf
Bump github.com/BurntSushi/toml from 1.4.0 to 1.5.0
Bumps [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/BurntSushi/toml/releases)
- [Commits](https://github.com/BurntSushi/toml/compare/v1.4.0...v1.5.0)

---
updated-dependencies:
- dependency-name: github.com/BurntSushi/toml
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 06:54:48 +00:00
dependabot[bot]
632531f735
Bump github.com/go-openapi/errors from 0.22.0 to 0.22.1
Bumps [github.com/go-openapi/errors](https://github.com/go-openapi/errors) from 0.22.0 to 0.22.1.
- [Commits](https://github.com/go-openapi/errors/compare/v0.22.0...v0.22.1)

---
updated-dependencies:
- dependency-name: github.com/go-openapi/errors
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 06:54:43 +00:00
dependabot[bot]
2aeb24858f
Bump github.com/go-openapi/swag from 0.23.0 to 0.23.1
Bumps [github.com/go-openapi/swag](https://github.com/go-openapi/swag) from 0.23.0 to 0.23.1.
- [Commits](https://github.com/go-openapi/swag/compare/v0.23.0...v0.23.1)

---
updated-dependencies:
- dependency-name: github.com/go-openapi/swag
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-13 06:27:27 +00:00
Gabriel
a734f82e45
Merge pull request #363 from gabriel-samfira/update-deps
Update dependencies
2025-03-06 14:15:50 +02:00
Gabriel Adrian Samfira
e3b46209a5 Update dependencies
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-03-06 12:00:19 +00:00
Gabriel
99f56606eb
Merge pull request #356 from cloudbase/dependabot/go_modules/golang.org/x/crypto-0.35.0
Bump golang.org/x/crypto from 0.34.0 to 0.35.0
2025-02-25 10:47:32 +02:00
dependabot[bot]
ccc18d5006
Bump golang.org/x/crypto from 0.34.0 to 0.35.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.34.0 to 0.35.0.
- [Commits](https://github.com/golang/crypto/compare/v0.34.0...v0.35.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-25 06:51:21 +00:00
Gabriel
77a503b61d
Merge pull request #355 from gabriel-samfira/update-deps
Update dependencies
2025-02-24 10:04:09 +02:00
Gabriel Adrian Samfira
5415121a70 Update dependencies
This change updates all dependencies.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-02-24 07:59:10 +00:00
Gabriel
f2b43bac77
Merge pull request #329 from gabriel-samfira/add-backoff
Add a backoff mechanism when deleting runners
2025-02-13 13:12:09 +02:00
Gabriel
bf4636417b
Merge pull request #328 from gabriel-samfira/add-busy-timeout
Add knob to tweak _busy_timeout
2025-02-13 13:10:15 +02:00
Gabriel
09e3df25ba
Merge pull request #349 from cloudbase/dependabot/go_modules/github.com/jedib0t/go-pretty/v6-6.6.6
Bump github.com/jedib0t/go-pretty/v6 from 6.6.5 to 6.6.6
2025-02-11 10:49:19 +02:00
dependabot[bot]
17c9b0a841
Bump github.com/jedib0t/go-pretty/v6 from 6.6.5 to 6.6.6
Bumps [github.com/jedib0t/go-pretty/v6](https://github.com/jedib0t/go-pretty) from 6.6.5 to 6.6.6.
- [Release notes](https://github.com/jedib0t/go-pretty/releases)
- [Commits](https://github.com/jedib0t/go-pretty/compare/v6.6.5...v6.6.6)

---
updated-dependencies:
- dependency-name: github.com/jedib0t/go-pretty/v6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-11 06:41:57 +00:00
Gabriel
aa60ae9c09
Merge pull request #348 from gabriel-samfira/change-event-log
Update event logging
2025-02-10 15:21:35 +02:00
Gabriel Adrian Samfira
b8e77cb125 Update event logging
Ping events are no longer logged. Unknown events are now logged as Debug.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-02-10 13:15:35 +00:00
Gabriel
ce7c67a8a7
Merge pull request #347 from gabriel-samfira/add-created-at
Add additional info when listing resources
2025-02-10 14:51:20 +02:00
Gabriel Adrian Samfira
c0245a18f7 Add additional info when listing resources
This change adds a --long option to most commands and includes the
CreateAt and UpdatedAt fields in the output.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-02-10 12:45:30 +00:00
Gabriel
719bcd05aa
Merge pull request #346 from cloudbase/dependabot/go_modules/golang.org/x/crypto-0.33.0
Bump golang.org/x/crypto from 0.32.0 to 0.33.0
2025-02-10 10:28:38 +02:00
dependabot[bot]
4a05fe600c
Bump golang.org/x/crypto from 0.32.0 to 0.33.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.32.0 to 0.33.0.
- [Commits](https://github.com/golang/crypto/compare/v0.32.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-10 06:46:58 +00:00
Gabriel
ea4f605bf1
Merge pull request #342 from gabriel-samfira/relax-validation
Relax description validation
2025-02-05 22:23:27 +02:00
Gabriel
d4ce174bab
Merge pull request #343 from gabriel-samfira/relax-webhook-url
Relax URLs validation
2025-02-05 22:19:16 +02:00
Gabriel Adrian Samfira
beafcb6316 Relax description validation
Description should not be mandatory when defining a github endpoint.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-02-05 20:18:56 +00:00
Gabriel Adrian Samfira
86d6517a5d Relax URLs validation
Webhook URL was not mandatory in previous versions. While it is needed
if users plan to use the install webhook feature, it is not required if
you want to install it yourself.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-02-05 20:10:02 +00:00
Gabriel
001465d0a2
Merge pull request #326 from cloudbase/dependabot/go_modules/golang.org/x/crypto-0.32.0
Bump golang.org/x/crypto from 0.31.0 to 0.32.0
2025-02-05 10:16:30 +02:00
dependabot[bot]
83001abbae
Bump golang.org/x/crypto from 0.31.0 to 0.32.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.31.0 to 0.32.0.
- [Commits](https://github.com/golang/crypto/compare/v0.31.0...v0.32.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-05 08:11:41 +00:00
Gabriel
453ce1004c
Merge pull request #340 from cloudbase/dependabot/go_modules/golang.org/x/sync-0.11.0
Bump golang.org/x/sync from 0.10.0 to 0.11.0
2025-02-05 10:10:27 +02:00
dependabot[bot]
c179436f97
Bump golang.org/x/sync from 0.10.0 to 0.11.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.10.0 to 0.11.0.
- [Commits](https://github.com/golang/sync/compare/v0.10.0...v0.11.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-05 08:00:13 +00:00
Gabriel
45957e45ba
Merge pull request #341 from cloudbase/dependabot/go_modules/golang.org/x/oauth2-0.26.0
Bump golang.org/x/oauth2 from 0.25.0 to 0.26.0
2025-02-05 09:59:01 +02:00
dependabot[bot]
0932e94799
Bump golang.org/x/oauth2 from 0.25.0 to 0.26.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.25.0 to 0.26.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-05 07:15:38 +00:00
Gabriel
5ec6c25246
Merge pull request #335 from cloudbase/gabriel-samfira-patch-1
Update integration-tests.yml
2025-01-31 21:04:32 +02:00
Gabriel
e255c90213
Update integration-tests.yml 2025-01-31 20:59:25 +02:00
Gabriel Adrian Samfira
edbaf47970 Add a backoff mechanism when deleting runners
This change adds a backoff mechanism when deleting github runners.
If the delete operation fails, we record the event and retry with
a geometric progression of 1.5 starting from 5 seconds, which is the
pool consolidation timeout.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-01-28 23:00:10 +00:00
Gabriel Adrian Samfira
6814b69a09 Add knob to tweak _busy_timeout
In SQLite3 we may need to set a busy_timeout in the case of instances
with high load. This change adds a knob that allows users to set a
timeout if a database is locked for writing by another routine.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2025-01-28 20:07:07 +00:00
Gabriel
e0e60d42c8
Merge pull request #327 from fabi200123/update-docs
Update Performance Considerations - Cached runners section
2025-01-17 13:11:21 +02:00
Fabian Fulga
e221698299 Update Performance Considerations - Cached runners section 2025-01-17 10:14:24 +02:00
Gabriel
b60fad59d5
Merge pull request #324 from cloudbase/dependabot/go_modules/github.com/bradleyfalzon/ghinstallation/v2-2.13.0
Bump github.com/bradleyfalzon/ghinstallation/v2 from 2.12.0 to 2.13.0
2025-01-07 00:19:14 +02:00
Gabriel
a040dde9b4
Merge pull request #325 from cloudbase/dependabot/go_modules/golang.org/x/oauth2-0.25.0
Bump golang.org/x/oauth2 from 0.24.0 to 0.25.0
2025-01-07 00:18:20 +02:00
dependabot[bot]
83ee1724db
Bump golang.org/x/oauth2 from 0.24.0 to 0.25.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.24.0 to 0.25.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-06 06:38:40 +00:00
dependabot[bot]
5d6ace6a2c
Bump github.com/bradleyfalzon/ghinstallation/v2 from 2.12.0 to 2.13.0
Bumps [github.com/bradleyfalzon/ghinstallation/v2](https://github.com/bradleyfalzon/ghinstallation) from 2.12.0 to 2.13.0.
- [Release notes](https://github.com/bradleyfalzon/ghinstallation/releases)
- [Commits](https://github.com/bradleyfalzon/ghinstallation/compare/v2.12.0...v2.13.0)

---
updated-dependencies:
- dependency-name: github.com/bradleyfalzon/ghinstallation/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-03 06:41:00 +00:00
Gabriel
f43f797883
Merge pull request #322 from gabriel-samfira/update-deps
Update dependencies
2024-12-20 20:59:10 +02:00
Gabriel Adrian Samfira
c42c3f580e Update dependencies
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-12-20 18:54:05 +00:00
Gabriel
72034d445a
Merge pull request #321 from cloudbase/dependabot/go_modules/github.com/jedib0t/go-pretty/v6-6.6.5
Bump github.com/jedib0t/go-pretty/v6 from 6.6.4 to 6.6.5
2024-12-20 20:47:47 +02:00
dependabot[bot]
e96145833c
Bump github.com/jedib0t/go-pretty/v6 from 6.6.4 to 6.6.5
Bumps [github.com/jedib0t/go-pretty/v6](https://github.com/jedib0t/go-pretty) from 6.6.4 to 6.6.5.
- [Release notes](https://github.com/jedib0t/go-pretty/releases)
- [Commits](https://github.com/jedib0t/go-pretty/compare/v6.6.4...v6.6.5)

---
updated-dependencies:
- dependency-name: github.com/jedib0t/go-pretty/v6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-20 18:42:29 +00:00
Gabriel
e69838b678
Merge pull request #320 from cloudbase/gabriel-samfira-patch-2
Create dependabot.yml
2024-12-20 20:41:22 +02:00
Gabriel
1f3c7cd34a
Create dependabot.yml 2024-12-20 20:35:04 +02:00
Gabriel
54505289d5
Merge pull request #319 from gabriel-samfira/update-deps
Update dependencies
2024-12-12 23:48:52 +02:00
Gabriel Adrian Samfira
f0aaf20998
Update dependencies
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-12-12 23:42:01 +02:00
Gabriel
1cb2d70546
Merge pull request #318 from gabriel-samfira/fix-nil-pointer-cli
Fix nil pointer dereference when rendering message
2024-12-12 10:49:09 +02:00
Gabriel Adrian Samfira
f8b4118306
Fix nil pointer dereference when rendering message
We failed to properly check the error of the update url call before
trying to access the payload, which lead to a panic in the CLI. This
change should fix that.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-12-12 09:49:42 +02:00
Gabriel
c4a7a59bc9
Merge pull request #316 from gabriel-samfira/fix-run-as-user
Fix hardcoded user value in template
2024-12-05 01:28:43 +02:00
Gabriel Adrian Samfira
67928ccd94
Fix hardcoded user value in template
The User option in the systemd unit file used when JIT configs are enabled
had a hardcoded value of "runner". This change fixes that oversight.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-12-05 00:04:11 +02:00
Gabriel
7d889f0cdd
Merge pull request #315 from mercedes-benz/fix/makefile
fix: remove duplication in Makefile
2024-11-26 16:59:14 +02:00
Michael Kuhnt
53bc1eedce fix: remove duplication in Makefile 2024-11-26 15:04:53 +01:00
Gabriel
8e13588edd
Merge pull request #314 from mercedes-benz/improve_error_message
Improve error messages in garm log
2024-11-26 10:44:41 +02:00
Michael Kuhnt
6167d8c7fd lint: exclude gosec G115 2024-11-26 09:23:58 +01:00
Michael Kuhnt
3a95b8f704 fix linter finding 2024-11-26 07:53:02 +01:00
Michael Kuhnt
386aba18c0 set specific linter version 2024-11-26 07:49:08 +01:00
Michael Kuhnt
d6de59619d commit suggestion 2024-11-22 16:49:56 +01:00
Michael Kuhnt
935c9dcd96
Update database/sql/jobs.go
Co-authored-by: Gabriel <samfiragabriel@gmail.com>
2024-11-22 16:40:23 +01:00
Michael Kuhnt
8a31d81faf ignore workflow_jobs without labels 2024-11-22 11:48:59 +01:00
Michael Kuhnt
c5c74a8dfc add runner name in error message 2024-11-22 11:48:59 +01:00
Gabriel
06dfc2708d
Merge pull request #306 from gabriel-samfira/fix-conflicting-options
Remove conflicting short hand option
2024-10-23 16:43:54 +03:00
Gabriel Adrian Samfira
2273b1de19 Remove conflicting short hand option
The --format command line option is persistent to allow all commands to
output to either json or table. The shorthand of this option caused a
conflict with other subcommands that also define the -f option. Removing
the persitent short form option.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-10-23 13:38:05 +00:00
Gabriel
54aa3815df
Merge pull request #302 from fabi200123/cached-runner-docs
Add Using Cached Runner documentation
2024-10-22 13:22:56 +03:00
Fabian Fulga
8515bf1083 Add Using Cached Runner documentation 2024-10-16 08:28:12 +03:00
Gabriel
465b12beb5
Merge pull request #299 from gabriel-samfira/use-errors-wrap
Use errors.Wrap() in repositories.go
2024-10-06 14:30:36 +03:00
Gabriel
6e38e23cdc
Merge pull request #301 from gabriel-samfira/copy-ca-certs
Copy the CA certificates to final image
2024-09-28 22:40:32 +03:00
Gabriel Adrian Samfira
1ba14f858d Copy the CA certificates to final image
The busybox image does not contain CA certificares. This adds them from
the builder stage.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-09-28 19:30:20 +00:00
Gabriel
72e8aa10ee
Merge pull request #300 from gabriel-samfira/add-default-value
Add a default value to the new --format option
2024-09-28 22:26:54 +03:00
Gabriel Adrian Samfira
f9abb30128 Add a default value to the new --format option
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-09-28 19:21:20 +00:00
Gabriel
5323fcb513
Merge pull request #298 from gabriel-samfira/add-format-option
Add --format command line option
2024-09-28 22:15:13 +03:00
Gabriel Adrian Samfira
36b9e9f296 Use errors.Wrap() in repositories.go
The API code unwraps errors wrapped by the errors.Wrap() function. It
falls back to 500 error if it can't determine any other error type.

Ultimately we need to migrate to the fmt.Errorf() pattern. But for now
at least, we need to return proper errors. Any 500 error will not output
details to the API. Neither will 401 for similar reasons.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-09-28 19:13:05 +00:00
Gabriel Adrian Samfira
63000113ee Add --format command line option
This change adds a --format command line option to the GARM cli. This
option accepts either json or table as a value.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-09-28 19:09:45 +00:00
Gabriel
cf231c9d8d
Merge pull request #297 from gabriel-samfira/add-omitempty
Add omitempty to all struct fields
2024-09-28 21:25:07 +03:00
Gabriel Adrian Samfira
2dfde30aad Add omitempty to all struct fields
The JSON that gets returned by the API is filled with empty values
which serve no purpose. Adding omitempty will skip empty values.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-09-28 18:19:14 +00:00
Gabriel
bdb26c1827
Merge pull request #296 from gabriel-samfira/make-tag-search-case-insensitive
Do a case insensitive search for tags
2024-09-28 21:03:29 +03:00
Gabriel Adrian Samfira
e5fd702544 Fix tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-09-27 08:05:43 +00:00
Gabriel Adrian Samfira
c319341ec5 Do a case insensitive search for tags
This change switches to a case insensitive search for pool tags.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-09-27 07:54:29 +00:00
Gabriel
3a2061afb9
Merge pull request #278 from fabi200123/version-v3
Add provider interface versioning
2024-09-04 15:15:46 +03:00
Fabian Fulga
dcff6f9854 Add getProviderBaseParams function in basePoolManager 2024-09-02 15:25:44 +03:00
Fabian Fulga
7074f01541 Move ValidateResult to common package 2024-09-02 10:39:45 +03:00
Fabian Fulga
08244161a1 Update garm-provider-common package 2024-08-22 11:40:37 +03:00
Fabian Fulga
03f280da59 Version provider interface 2024-08-21 16:14:38 +03:00
Gabriel
deb30e1d25
Merge pull request #288 from gabriel-samfira/use-lxd-image-mirror
Allow using LXD image mirror
2024-08-14 23:57:41 +03:00
Gabriel Adrian Samfira
9a6f0e7926 Pin go version
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-14 20:52:10 +00:00
Gabriel Adrian Samfira
f5992b7344 Allow using LXD image mirror
This change allows GARM tests to use a mirror for LXD images, allowing
for faster image downloads.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-14 19:44:23 +00:00
Gabriel
3b1e3c77e1
Merge pull request #287 from gabriel-samfira/switch-to-self-hosted
Switch to self hosted runner
2024-08-14 20:14:52 +03:00
Gabriel Adrian Samfira
d5cbc5bfb2 Switch to self hosted runner
GitHub hosted runners seem to have issues with LXD containers.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-12 21:15:47 +00:00
Gabriel
fc32978c63
Merge pull request #286 from gabriel-samfira/replace-ngrok
Replace ngrok
2024-08-12 22:29:37 +03:00
Gabriel Adrian Samfira
e1e46211a1 Replace ngrok
This change switches the integration tests to an alternate tunneling
service.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-12 19:22:52 +00:00
Gabriel
237afdb25d
Merge pull request #284 from gabriel-samfira/prepare-v0.1.5
Prepare v0.1.5
2024-08-08 15:32:37 +03:00
Gabriel Adrian Samfira
926797dda5 Pin provider versions and switch to busybox
Thic change pins all providers to a released version. We also switched
the GARM image to busybox. This adds an extra ~45MB, but we get an image
we can exec into.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-08 12:22:16 +00:00
Gabriel
82d70d2310
Merge pull request #4 from fabi200123/small-nits
Update docs
2024-08-08 15:05:17 +03:00
Fabian Fulga
b9aafbe65e Update docs 2024-08-08 15:01:24 +03:00
Gabriel Adrian Samfira
a12ad2fa89 Fix example spaces vs tabs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-08 09:29:15 +00:00
Gabriel Adrian Samfira
932ee4693e Remove extra doc
The database.md doc has been added to config.md.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-08 09:16:09 +00:00
Gabriel Adrian Samfira
1a54bcfc35 Restructure docs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-08 09:13:55 +00:00
Gabriel Adrian Samfira
6640599584 Add more info on events
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-06 15:18:18 +00:00
Gabriel Adrian Samfira
9b0633c557 Update quickstart and using_garm, add events.md
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-06 15:18:18 +00:00
Gabriel Adrian Samfira
35f4bea269 Update docs
Reword some phrases, update links and steps.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-06 15:18:18 +00:00
Gabriel
56b0e6065a
Merge pull request #283 from gabriel-samfira/add-json-tags
Add JSON tags to the ChangePayload struct
2024-08-06 16:53:12 +03:00
Gabriel Adrian Samfira
a7f1a51a7d Add JSON tags to the ChangePayload struct
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-06 13:43:58 +00:00
Gabriel
516908f26c
Merge pull request #282 from gabriel-samfira/update-common
Update garm-provider-common
2024-08-03 19:16:53 +03:00
Gabriel Adrian Samfira
bc4285dc80 Update garm-provider-common
Use the websocket reader from within garm-provider-common.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-03 16:07:21 +00:00
Gabriel
a5b15789a1
Merge pull request #281 from gabriel-samfira/cleanup-websocket-urls
Rename websocket URLs
2024-08-03 01:29:05 +03:00
Gabriel Adrian Samfira
79c1e47427 Rename websocket URLs
Given that we now have multiple websocket URLs (logs and events), this
change categorizes them under the same prefix.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-02 22:19:51 +00:00
Gabriel
7fe2a3ad34
Merge pull request #280 from gabriel-samfira/generalize-ws-reader
Generalize the websocket reader
2024-08-03 00:27:43 +03:00
Gabriel Adrian Samfira
5c45f54ef4 Generalize the websocket reader
This change adds a new message handler that users of the reader can use
to handle websocket messages. Packages should never print to console by
themselves.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-08-02 21:18:31 +00:00
Gabriel
6835419daf
Merge pull request #279 from gabriel-samfira/scope-entities-to-endpoint
Fix: Scope entities to endpoint
2024-08-01 13:19:42 +03:00
Gabriel Adrian Samfira
cc6e985629 Fix: Scope entities to endpoint
This change scopes all github entities to a github endpoint, allowing
users to have the same repo/org/enterprise created for each endpoint.

This way, if your username is the same on github.com and on your GHES
server, and you have the same repository name or org in both places,
GARM can now handle that situation.

This change also fixes a leaky watcher in the pool manager.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-07-29 17:35:57 +00:00
Gabriel
f64ffa8d92
Merge pull request #277 from gabriel-samfira/slight-docs-reword
Reword the section about labels
2024-07-07 00:05:27 +03:00
Gabriel Adrian Samfira
411dcea4fb Reword the section about labels
This change removes a stray line in the quickstart and rewords
the section about labels a bit.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-07-06 21:02:54 +00:00
Gabriel
59de9cdf93
Merge pull request #275 from gabriel-samfira/add-event-stream
Add event stream
2024-07-05 23:06:09 +03:00
Gabriel Adrian Samfira
2554f70b89 Replace time.After with time.NewTimer
Improper use of time.After can lead to memory leaks if the timer never
gets a chance to fire.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-07-05 12:55:35 +00:00
Gabriel Adrian Samfira
49f1b7aa14 Set read limit to 16 KB
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-07-05 12:55:35 +00:00
Gabriel Adrian Samfira
a2c606b87d Simplify logic
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-07-05 12:55:35 +00:00
Gabriel Adrian Samfira
5b24b9e56b Fix shadowing bug in job create function
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-07-05 12:55:35 +00:00
Gabriel Adrian Samfira
5c5b2256bb Create common utility function for ws
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-07-05 12:55:35 +00:00
Gabriel Adrian Samfira
246f826b76 Validate filter payload
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-07-05 12:55:35 +00:00
Gabriel Adrian Samfira
9f8659abd6 Add events websocket endpoint
This change adds a new websocket endpoint for database events. The events
endpoint allows clients to stream events as they happen in GARM. Events
are defined as a structure containning the event type (create, update, delete),
the database entity involved (instances, pools, repos, etc) and the payload
consisting of the object involved in the event. The payload translates
to the types normally returned by the API and can be deserialized as one
of the types present in the params package.

The events endpoint is a websocket endpoint and it accepts filters as
a simple json send over the websocket connection. The filters allows the
user to specify which entities are of interest, and which operations should
be returned. For example, you may be interested in changes made to pools
or runners, in which case you could create a filter that only returns
update operations for pools. Or update and delete operations.

The filters can be defined as:

{
  "filters": [
    {
      "entity_type": "instance",
      "operations": ["update", "delete"]
    },
    {
      "entity_type": "pool"
    },
  ],
  "send_everything": false
}

This would return only update and delete events for instances and all events
for pools. Alternatively you can ask GARM to send you everything:

{
  "send_everything": true
}

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-07-05 12:55:35 +00:00
Gabriel Adrian Samfira
dd1740c189 Refactor the websocket client and add fixes
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>
2024-07-05 12:55:35 +00:00
Gabriel
ca7f20b62d
Merge pull request #276 from gabriel-samfira/add-version-to-api-response
Add version to controller info response
2024-07-05 15:54:45 +03:00
Gabriel Adrian Samfira
42ae3c52d1 Add version to controller info response
This change adds the GARM server version to the controller info response.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-07-05 12:49:16 +00:00
Gabriel
dcee09281b
Merge pull request #274 from gabriel-samfira/make-durations-configuratble
Allow configuration of job backoff interval
2024-07-02 12:03:05 +03:00
Gabriel Adrian Samfira
892a62bfe4 Allow configuration of job backoff interval
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>
2024-07-01 10:27:31 +00:00
Gabriel
8f0d44742e
Merge pull request #269 from gabriel-samfira/remove-update-state
Use watcher and get rid of RefreshState()
2024-06-21 16:51:54 +03:00
Gabriel Adrian Samfira
daaca0bd8f Use watcher and get rid of RefreshState()
This change uses the database watcher to watch for changes to the
github entities, credentials and controller info.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-21 13:47:48 +00:00
Gabriel
38127af747
Merge pull request #268 from gabriel-samfira/lower-log-level
Lower the log level of ignored jobs
2024-06-20 18:35:24 +03:00
Gabriel Adrian Samfira
1dfa74efd8 Lower the log level of ignored jobs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-20 15:30:25 +00:00
Gabriel
98b8a7f15f
Merge pull request #267 from fabi200123/fix-set-watcher
Remove duplicate of watcher.SetWatcher()
2024-06-20 17:59:25 +03:00
Fabian Fulga
61c9470bcf Remove duplicate of watcher.SetWatcher 2024-06-20 17:37:11 +03:00
Gabriel
5eef3b68cb
Merge pull request #266 from gabriel-samfira/consume-watcher-events
Consume events before testing
2024-06-20 15:50:30 +03:00
Gabriel Adrian Samfira
8bf979fe1c Consume events before testing
The watcher uses a buffered channel, so we may get stray events that
we need to consume before generating new ones in the tests.

This is just for testing purposes. In actual use cases, we never expect
to only have one event generated.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-20 12:38:36 +00:00
Gabriel
c188a6f2c1
Merge pull request #263 from gabriel-samfira/add-database-watcher
Add database watcher
2024-06-20 15:01:53 +03:00
Gabriel Adrian Samfira
230f002902 Add more tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-20 11:01:57 +00:00
Gabriel Adrian Samfira
b7d138d2ac Add notifications for jobs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-19 13:44:24 +00:00
Gabriel Adrian Samfira
5f07bc2d7c Check if producer was registered
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-19 12:40:56 +00:00
Gabriel Adrian Samfira
0c8c6f5668 Add more tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-19 12:27:48 +00:00
Gabriel Adrian Samfira
cc9ecf5847 Add more tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-18 19:28:34 +00:00
Gabriel Adrian Samfira
8a79d9e8f9 Add more watcher tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-18 17:45:48 +00:00
Gabriel Adrian Samfira
37f6434ed8 Fix race condition and add some tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-18 16:42:24 +00:00
Gabriel Adrian Samfira
b51683f1ae Add some tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-17 19:42:50 +00:00
Gabriel
a66cbccdd9
Merge pull request #261 from fabi200123/integration-tests
Refactor Integration tests
2024-06-17 13:57:42 +03:00
Fabian Fulga
9d4c0a953c Adding garm test suite 2024-06-17 12:36:00 +03:00
Gabriel Adrian Samfira
6051629810 Add watcher for github creds and endpoints
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-14 20:35:02 +00:00
Gabriel Adrian Samfira
7f9db2e413 Send notify on update controller
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-14 20:24:45 +00:00
Gabriel Adrian Samfira
8d57fc8fa2 Add rudimentary database watcher
Adds a simple database watcher. At this point it's just one process, but
the plan is to allow different implementations that inform the local running
workers of changes that have occured on entities of interest in the database.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-14 19:47:12 +00:00
Gabriel
4c7c9b0e1e
Merge pull request #259 from gabriel-samfira/fix-readme-typos
Fix typos
2024-06-08 12:38:50 +03:00
Gabriel Adrian Samfira
1058c40c43 Fix typos
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-07 18:24:58 +00:00
Gabriel
214cb05072
Merge pull request #256 from gabriel-samfira/move-urls-to-db
Move URLs from default section of config to DB
2024-06-07 13:09:04 +03:00
Gabriel Adrian Samfira
aea328bab9 Remove URLs from sample config
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-07 10:04:34 +00:00
Gabriel Adrian Samfira
37ae7520b8 Update docs
Update the quickstart and the "using garm" sections.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-07 09:27:38 +00:00
Gabriel Adrian Samfira
3992f97d8c Fix tests and make URLs optional in config
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-07 09:27:38 +00:00
Gabriel Adrian Samfira
9748aa47af Move URLs from default section of config to DB
This change moves the callback_url, metadata_url and webhooks_url from
the config to the database. The goal is to move as much as possible from
the config to the DB, in preparation for a potential refactor that will
allow GARM to scale out. This would allow multiple nodes to share a single
source of truth.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-06-07 09:27:24 +00:00
Gabriel
7ee235aeb0
Merge pull request #255 from mercedes-benz/remove_runner_name_lookup_via_job_id
fix: remove unnecessary github api call
2024-06-05 15:05:16 +03:00
Mario Constanti
b4e7dead1c fix: check if runner name is empty and return
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-06-05 13:48:53 +02:00
Mario Constanti
dc74c45317 fix: remove unnecessary github api call
There are only a few cases, where we get a job information from github
where the runner name is not set.

For all this cases we do not need to check github API at all because
these jobs are never ever get scheduled to a runner:

job.Action is:

* queued:
  a queued job is just queued and not scheduled to a runner so we do
  not get a runner name from the GH API
* completed:
  when conclusion=cancelled|failure github never scheduled the job to a
  runner and with that we do not get a runner name from the GH API

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-06-05 12:37:20 +02:00
Gabriel
02ff74bfe8
Merge pull request #254 from mercedes-benz/fix_conclusion_typo
fix: use the american english type of cancelled
2024-06-05 13:10:36 +03:00
Mario Constanti
7adc48c75f fix: use the american english type of cancelled
github is sending job events where conclusion=cancelled is spelled in american english.

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-06-05 11:57:33 +02:00
Gabriel
7538f4add9
Merge pull request #252 from gabriel-samfira/update-readme
Add note about stable release documentation
2024-05-25 09:57:34 +03:00
Gabriel Adrian Samfira
ae80ae0442 Add note about stable release documentation
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-05-25 06:55:10 +00:00
Gabriel
09f050553c
Merge pull request #251 from gabriel-samfira/update-go-swagger
Update go-swagger and run generate
2024-05-23 14:40:52 +03:00
Gabriel Adrian Samfira
ff6db9bd61 Update go-swagger and run generate
This updates go-swagger to v0.31.0, which no longer panics when used
with golang v1.22+.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-05-23 10:24:44 +00:00
Gabriel
ab3bef8b41
Merge pull request #249 from mercedes-benz/new_runners_without_default_labels
New runners without default labels
2024-05-22 21:18:57 +03:00
Mario Constanti
debb9696ce docs: document released provider-common version
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-05-22 06:04:22 +02:00
Mario Constanti
27e081eb36 remove required tags during update
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-05-22 06:03:06 +02:00
Mario Constanti
c4f023b6a8 doc: add some notes about default labels
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-05-21 12:06:54 +02:00
Mario Constanti
40cdf5b639 doc: remove self-hosted label from docs
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-05-21 11:55:12 +02:00
Mario Constanti
1d14a26325 feat: garm pools do not force default labels
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-05-21 11:55:12 +02:00
Gabriel
6e416bb494
Merge pull request #246 from gabriel-samfira/remove-duplicate-pool-characteristics-check
Remove check for duplicate pool
2024-05-10 20:31:37 +03:00
Gabriel
45d5f152ce
Merge pull request #247 from gabriel-samfira/add-toc-to-docs
Add TOC
2024-05-10 11:49:19 +03:00
Gabriel Adrian Samfira
f721d74840 Add TOC
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-05-10 08:48:47 +00:00
Gabriel Adrian Samfira
be4f303b82 Remove check for duplicate pool
This change removes a check that denies the creation of a pool
if the new pool has the same image and flavor set on the same
provider. The reasoning for that check was that if you need to
create another pool with identical settings to an existing one,
you might as well scale up the min-idle-runners on the old one.

This was done when runner groups were not yet added. This in
turn has forced users to alias images with new names in their
provider, leading to terrible UX. In the end, being too
opinionated in this case has caused more harm than good.

Fixes #245

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-05-10 08:12:44 +00:00
Gabriel
76d45ad83f
Merge pull request #243 from gabriel-samfira/use-db-for-gh-creds
Move github credentials to the database
2024-05-09 19:36:04 +03:00
Gabriel Adrian Samfira
b3e2c584bf Update docs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-05-07 21:22:40 +00:00
Gabriel Adrian Samfira
27e74ef277 Add DB migration test
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-05-07 11:52:26 +00:00
Gabriel
75eb45c97a
Update database/sql/sql.go
Co-authored-by: Mario Constanti <github@constanti.de>
2024-05-07 13:13:16 +03:00
Gabriel Adrian Samfira
8726cb994e Move the name check before tx
No point in making a DB query if we know we don't want to be able to
delete/update the default endpoint.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-05-07 10:07:47 +00:00
Gabriel Adrian Samfira
2a3d524a71 Add more unit tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-29 09:47:26 +00:00
Gabriel Adrian Samfira
2b1414d150 Add some unit tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-28 17:20:40 +00:00
Gabriel Adrian Samfira
402c8b70e2 Use different creds than the default ones
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-27 18:55:30 +00:00
Gabriel Adrian Samfira
349ba1f9e8 Fix nil pointer dereference
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-27 18:17:35 +00:00
Gabriel Adrian Samfira
87943db62c Fix lint and add integration tests logging
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-27 18:10:03 +00:00
Gabriel Adrian Samfira
0128f59344 Add some credentials e2e tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-25 17:38:24 +00:00
Gabriel Adrian Samfira
39a5e14eb1 Add more e2e GH endpoint tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-25 07:45:09 +00:00
Gabriel Adrian Samfira
ccf51053b5 Add github endpoint operations e2e test
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-24 14:54:29 +00:00
Gabriel Adrian Samfira
1256473089 Fetch credentials from DB
Do not rely on the entity object to hold updated or detailed credentials,
fetch them from the DB every time.

This change also ensures that we pass in the user context instead of the
runner context to the DB methods.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-24 13:59:15 +00:00
Gabriel Adrian Samfira
c2b974dfa0 Create clone creds for repo update
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-24 11:39:20 +00:00
Gabriel Adrian Samfira
f5682e6323 Work around actions/runner-images#7210
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-24 11:30:15 +00:00
Gabriel Adrian Samfira
8b5584f083 Add some e2e boilerplate
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-24 11:21:27 +00:00
Gabriel Adrian Samfira
e8ea7117ce Fix tests post-rebase
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:10:51 +00:00
Gabriel Adrian Samfira
eb1456479b Deny deleting the default github.com endpoint
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:08:37 +00:00
Gabriel Adrian Samfira
208a4eea37 Ensure github endpoint
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:08:37 +00:00
Gabriel Adrian Samfira
eadbe784b9 Add github credentials API and cli code
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:08:37 +00:00
Gabriel Adrian Samfira
77ecb16166 Add github endpoint API endpoint and CLI code
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:08:37 +00:00
Gabriel Adrian Samfira
257fb0b09a Take into account legacy config
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:08:37 +00:00
Gabriel Adrian Samfira
4610f83209 List credentials from db
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:08:37 +00:00
Gabriel Adrian Samfira
9c1ffe8c20 Enforce same endpoint when updating credentials
When updating credentials on an entity, we must ensure that the new credentials
belong to the same endpoint as the entity.

When an entity is created, the endpoint is determined by the credentials that
were used during the create operation. From that point forward the entity is
associated with an endpoint, and that cannot change.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:08:36 +00:00
Gabriel Adrian Samfira
3e60a48ca8 Preload credentials endpoint and remove extra code
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:03:25 +00:00
Gabriel Adrian Samfira
032d40f5f9 Fix tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:03:25 +00:00
Gabriel Adrian Samfira
90870c11be Use database for github creds
Add database models that deal with github credentials. This change
adds models for github endpoints (github.com, GHES, etc). This change
also adds code to migrate config credntials to the DB.

Tests need to be fixed and new tests need to be written. This will come
in a later commit.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 14:03:25 +00:00
Gabriel
834c3bb798
Merge pull request #244 from gabriel-samfira/update-dependencies
Update dependencies and tests
2024-04-22 16:02:39 +02:00
Gabriel Adrian Samfira
97d03dd38d Update dependencies and tests
This commit updates the dependencies, vendor files and updates tests
to take into account changes to the DB driver.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-22 13:39:04 +00:00
Gabriel
069bdd8b6b
Merge pull request #242 from gabriel-samfira/some-cleanup
Remove some code, move some code around
2024-04-01 17:57:06 +03:00
Gabriel Adrian Samfira
cb4d56773f Remove some code, move some code around
Remove code that was just wrapping other functions at this point, and
move some code around. We need to get a better idea what is actually
still needed in the pool manager, to begin to refactor it into something
that can scale out.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-04-01 14:52:37 +00:00
Gabriel
9525e013da
Merge pull request #241 from gabriel-samfira/some-cleanup
Slightly simplify code
2024-03-30 20:35:24 +02:00
Gabriel Adrian Samfira
36288c65e6 Slightly simplify code
Change instance DB functions from querying by ID to querying by name. Names
are unique in GARM, so we might as well use the name instead of the ID and
spare ourselves the extra query to get the ID when a qorkflow comes in.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-30 18:22:06 +00:00
Gabriel
9cbb2f867e
Merge pull request #240 from gabriel-samfira/deduplicate-db-code
Deduplicate db code
2024-03-29 20:54:59 +02:00
Gabriel Adrian Samfira
f9f545f060 Remove duplicate code
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-29 18:50:04 +00:00
Gabriel Adrian Samfira
9384e37bb1 Fix tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-28 18:23:49 +00:00
Gabriel Adrian Samfira
0152b21529 Implement some common logic for pool creation
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-28 10:09:20 +00:00
Gabriel
72501aee0f
Merge pull request #239 from gabriel-samfira/fix-nil-pointer-cmd-pool
Fix potential nil pointer dereference in cli
2024-03-28 12:08:49 +02:00
Gabriel Adrian Samfira
15129c8c9f Fix potential nil pointer dereference in cli
This change fixes a potential nil pointer dereference when a call to
create a pool, fails.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-28 10:01:50 +00:00
Gabriel
18bb126c0d
Merge pull request #238 from cloudbase/fix-nil-pointer-dereference
Check for nil pointer before dereferencing
2024-03-26 16:44:18 +02:00
Gabriel Adrian Samfira
e2eb8f719b
Check for nil pointer before dereferencing
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-26 16:43:09 +02:00
Gabriel
bb67ae5afe
Merge pull request #237 from gabriel-samfira/fix-jit-config-empty-group
Fix JIT config with empty runner group name
2024-03-25 20:59:56 +02:00
Gabriel Adrian Samfira
39f1be5512 Fix JIT config with empty runner group name
When no runner group is set, do not attempt to resolve the runner group.
Looking for an empty runner group will just return a not found error, which
will make GARM fall back to registration token.

This change fixes that.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-25 18:53:53 +00:00
Gabriel
90dd92d27c
Merge pull request #235 from gabriel-samfira/refactor-internal-gh-client
Refactor internal gh client
2024-03-18 20:12:53 +02:00
Gabriel Adrian Samfira
f0080047a3 Remove superfluous function
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-18 10:56:49 +00:00
Gabriel Adrian Samfira
56da6a4437 Slightly better UX when dealing with webhooks
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-18 10:19:16 +00:00
Gabriel Adrian Samfira
9259f84e56 Fix getting webhook URL info
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-18 09:53:34 +00:00
Gabriel Adrian Samfira
cfb68f8928 Check webhook secret for entity
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-18 09:39:07 +00:00
Gabriel Adrian Samfira
e3ffc153d2 simplify switch statement
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-17 18:08:46 +00:00
Gabriel Adrian Samfira
bef8f30d63 Fix lint
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-17 11:13:14 +00:00
Gabriel Adrian Samfira
fa75ecfa8e Dedupe more code
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-17 10:59:09 +00:00
Gabriel Adrian Samfira
b550d0c5b9 remove extra function
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-17 10:28:35 +00:00
Gabriel Adrian Samfira
1734e6f87c Deduplicate code
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-17 10:21:41 +00:00
Gabriel Adrian Samfira
234f71d9d1 Rename PoolType to GithubEntityType
We'll use GithubEntityType throughout the codebase to determine the
type of operation that is about to take place, so this won't belimited
to determining only pool type. We'll also use this to dedupe the label
scope as well.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-17 06:58:03 +00:00
Gabriel
2c217f0479
Merge pull request #234 from gabriel-samfira/add-oci-provider
Add OCI to provider list
2024-03-17 08:03:55 +02:00
Gabriel Adrian Samfira
e7834820c3 Add OCI to provider list
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-17 06:03:06 +00:00
Gabriel
6bfcddca75
Merge pull request #233 from gabriel-samfira/add-balancing-strategy
Add pool balancing strategy
2024-03-15 23:40:12 +02:00
Gabriel Adrian Samfira
206fe42c73 Remove unused code, update test
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-15 15:48:53 +00:00
Gabriel Adrian Samfira
ac29af6eff Add some unit tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-15 14:35:23 +00:00
Gabriel Adrian Samfira
d7ea80a657 Remove log message
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-15 08:12:16 +00:00
Gabriel Adrian Samfira
cdfda0321a Fix balancer type validation
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-15 07:26:04 +00:00
Gabriel Adrian Samfira
b58555bc10 Fix missing info in pool list
Without preloading the entity we're listing pools for, we don't get that
info when listing pools for a repo/org/enterprise.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-14 20:19:54 +00:00
Gabriel Adrian Samfira
ce3c917ae5 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
Gabriel
569d512819
Merge pull request #232 from gabriel-samfira/add-job-details
Add job info in runner list
2024-03-12 15:14:07 +02:00
Gabriel Adrian Samfira
7d33e0f0cf Add job info in runner list
This change adds information about the job a runner is currently handling.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-11 15:46:18 +00:00
Gabriel
321126629a
Merge pull request #231 from gabriel-samfira/bypass-gh-unauthorized
Allow bypassing Unauthorized error when deleting runner
2024-03-10 17:51:39 +02:00
Gabriel Adrian Samfira
9a6770c3a3 Allow bypassing Unauthorized error when deleting runner
This change allows users to bypass GitHub Unauthorized errors when removing
github runners. This means that removing runners will now be possible even
if the pool manager is stopped.

There is a new flag added to the runner rm command and to the API that
tells GARM to bypass pool being stopped and any 401 error returned by
GitHub.

This means you will be able to remove the runners from garm and your
provider, but will mean that the runner will still exist in github as
"offline" if the credentials are not updated or the runner manually removed.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-10 15:21:39 +00:00
Gabriel
df72c4917e
Merge pull request #229 from gabriel-samfira/add-toc
Add ToC to using_garm.md
2024-03-05 09:52:37 +02:00
Gabriel Adrian Samfira
73a2690d45 Add ToC to using_garm.md
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-05 07:52:01 +00:00
Gabriel
1b11c682c1
Merge pull request #228 from gabriel-samfira/add-github-app-support
Add GitHub App support
2024-03-04 09:46:10 +02:00
Gabriel Adrian Samfira
d734286296 Add some tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-02 20:42:36 +00:00
Gabriel Adrian Samfira
4733cac526 Replace errors.Wrap calls
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-02 19:07:06 +00:00
Gabriel Adrian Samfira
4668461603 Expose the credential type through the API
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-02 17:04:27 +00:00
Gabriel Adrian Samfira
cbb2134f0e Add GitHub App support
This change adds the ability to use GitHub Apps to authenticate against the
GitHub API. This gives us a larger quota for API requests (15k vs 5k for PATs).

Also, each GitHub App has its own quota, whereas PATs share the same user quota.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-03-01 19:47:50 +00:00
Gabriel
2ea6bb9490
Merge pull request #225 from gabriel-samfira/fix-variables
Fix variable name
2024-02-26 21:06:14 +02:00
Gabriel Adrian Samfira
b5e3552776 Fix variable name
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-26 19:04:48 +00:00
Gabriel
d3f6c40258
Merge pull request #224 from gabriel-samfira/simplify-job
simplify integration test job
2024-02-26 19:58:40 +02:00
Gabriel Adrian Samfira
111b93f062 simplify integration test job
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-26 17:58:04 +00:00
Gabriel
c233559d3b
Merge pull request #223 from gabriel-samfira/use-user-service
Use user service
2024-02-26 19:41:51 +02:00
Gabriel Adrian Samfira
43b3db5c0c Use user service
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-26 17:41:04 +00:00
Gabriel
72c5364537
Merge pull request #222 from gabriel-samfira/add-scripts-and-service
Add script and service template
2024-02-26 18:48:47 +02:00
Gabriel Adrian Samfira
a17cd577e0 Add script and service template
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-26 16:48:22 +00:00
Gabriel
5c49bc79ae
Merge pull request #221 from gabriel-samfira/switch-to-apg
Switch to apg for password gen
2024-02-26 18:45:16 +02:00
Gabriel Adrian Samfira
00fd7c1204 Switch to apg for password gen
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-26 16:44:47 +00:00
Gabriel
9d21bd6b51
Merge pull request #220 from gabriel-samfira/fix-integration-tests
Install dependencies and set RUN_USER
2024-02-26 18:39:18 +02:00
Gabriel Adrian Samfira
b9b185d1c1 Install dependencies and set RUN_USER
Install make dependencies and default to current user

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-26 16:38:27 +00:00
Gabriel
8728051c40
Merge pull request #219 from gabriel-samfira/augment-tests
Allow integration tests to run locally
2024-02-26 18:32:00 +02:00
Gabriel Adrian Samfira
b4dde6a839 Allow integration tests to run locally
This change adds the ability to run integration tests locally. You will
still need a number of environment variables set, including a github PAT.

Details on how to use this will come in a subsequent commit.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-26 16:28:07 +00:00
Gabriel
cffb4f23d4
Merge pull request #218 from mercedes-benz/introduce_golangci_config
Introduce golangci config and `make help`
2024-02-22 19:39:49 +02:00
Mario Constanti
d332e7a8ca fix: gocritic linter finding
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 17:40:15 +01:00
Mario Constanti
4c81c16505 fix: goconst linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 17:39:02 +01:00
Mario Constanti
9e7ac60c09 fix: gosec linter finding
we have to keep crypto/sha1 as github is still using it

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 17:34:12 +01:00
Mario Constanti
fd0550eb7f fix: godoc linter findings (TODO comments)
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 17:33:19 +01:00
Mario Constanti
ee3a670456 fix: var-naming linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 17:28:39 +01:00
Mario Constanti
7221812dfa fix: remove unused cobra args
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 17:20:05 +01:00
Mario Constanti
4409beb18a fix: G601: Implicit memory aliasing in for loop
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 16:57:26 +01:00
Mario Constanti
60dbf97ba4 fix: ignore testing secret
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 16:55:42 +01:00
Mario Constanti
9f5c38ef2d fix: unused-parameter linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 16:54:38 +01:00
Mario Constanti
73eb21438a fix: run make lint same way as in ci
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 16:54:20 +01:00
Mario Constanti
b8a9b6c89b fix: ignore testing package typechecks
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
c137f9b662 fix: gocritic linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
742ebabfc3 fix: unneded type conversion
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
b27f523259 fix: ifElseChain linter finding
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
f4e51493f3 fix: var-naming linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
f9e41f11d1 fix: gosec linter finding
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
cbe8f09412 fix: run make lint-fix
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
3fd09f6dcd fix: assignOp linter finding
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
c89deaeca7 fix: ifElseChain linter finding
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
55fe81fe32 fix: gosec linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
09e25ca8b1 fix: gosec linter finding - memory aliasing
G601: Implicit memory aliasing in for loop

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
9f405e0e8f fix: ifElseChain linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
b0e3f78fbb fix: godoc linter warnings (TODOs)
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
acc17eafcd fix: receiver-naming linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
f6404456b9 fix: indent-error-flow linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
6065fb2e3b fix: increment-decrement linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
e664639e98 fix: var-declaration linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
e5ed45c258 fix: unnecessary conversion linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
0ab86a7e51 fix: unused-parameter linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
3b9f8b555b fix: var-naming linter findings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
bd0b27ab10 fix: gci section warnings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
8fc001f5f6 fix: misspell linter warnings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
b3854eaf18 fix: whitespace linter warnings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
023652d76d fix: make build as PHONY target
without build as PHONY target, nothing will happen once the build
directory got created.

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Mario Constanti
9ea2a312d2 feat: introduce golangci config and help in make
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00
Gabriel
dd6f1e48b8
Merge pull request #217 from mercedes-benz/add_counter_metrics
extend metrics for github and provider executions
2024-02-22 09:35:41 +02:00
Mario Constanti
d68cc3bf05 fix: add missing metrics for few gh api callS
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 05:57:42 +01:00
Mario Constanti
6cb6350602 doc: document new operations/errors metrics
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-21 14:41:08 +01:00
Mario Constanti
9716b1d8c9 fix: align metric names
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-21 14:29:43 +01:00
Mario Constanti
b36b5137b6 feat: count github api calls
introduce metrics counter for github api calls

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-21 14:22:45 +01:00
Mario Constanti
0faf0927bc feat: count external provider operations
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-21 14:21:41 +01:00
Gabriel
e108140eb6
Merge pull request #216 from mercedes-benz/extended_metrics
chore: refactor metrics endpoint
2024-02-20 17:46:22 +02:00
Mario Constanti
b1cbfac08a fix: switch to context.Background() for adminctx
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-20 16:42:10 +01:00
Mario Constanti
2a3e4d6563 fix: pass context.TODO by getting admin context
fix linter warnings

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-20 16:39:52 +01:00
Mario Constanti
0a53b8f6d8 fix: stop metrics collector ticker on ctx.Done
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-20 14:57:32 +01:00
Mario Constanti
17d74dfbf0 chore: rework prometheus metrics registration
fail if metric registration panics

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-20 14:27:27 +01:00
Mario Constanti
3e025dda2f feat: define a default duration for metrics update
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-20 10:23:48 +01:00
Mario Constanti
97f172eb51 fix: improve metrics collection loop
by adding the context from main and make auth.GetAdminContext accepting a
context we are now able to stop the metrics collection loop once the
context is canceled

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-20 06:33:21 +01:00
Mario Constanti
1d8d9459eb chore: refactor metrics endpoint
refactoring is needed to make the metrics package usable from within the
runner package for further metrics.

This change also makes the metric-collector independent from requests to
the /metrics endpoint

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-19 16:22:32 +01:00
Gabriel
f68cf98d67
Merge pull request #215 from jepio/fix-static-docker
Dockerfile: Build actually static binaries
2024-02-16 10:39:59 +02:00
Jeremi Piotrowski
b4644ca3c8 Dockerfile: Build actually static binaries
Without '-linkmode external' some of the produced binaries were not actually
static. /bin/garm was fine but providers would fail with "exit code 127" when
executed. Unpacking the container image and running the binaries in strace
showed that they were accessing the musl dynamic linker.

Signed-off-by: Jeremi Piotrowski <jpiotrowski@microsoft.com>
2024-02-16 09:31:04 +01:00
Gabriel
e575053f7c
Merge pull request #210 from gabriel-samfira/add-new-providers
Add new providers
2024-02-12 21:16:52 +02:00
Gabriel Adrian Samfira
342ed8e990 Add new providers
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-12 19:16:12 +00:00
Gabriel
96208bb3c2
Merge pull request #209 from gabriel-samfira/fix-typos
Fix typos in garm-cli
2024-02-12 12:06:52 +02:00
Gabriel Adrian Samfira
eb729320f9 Fix typos in garm-cli
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-12 10:05:23 +00:00
Gabriel
6ca50dc4b2
Merge pull request #208 from gabriel-samfira/update-readme
Add GCP to the list of providers
2024-02-12 11:55:50 +02:00
Gabriel Adrian Samfira
803f7afd70 Add GCP to the list of providers
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-12 09:55:22 +00:00
Gabriel
3b9e822ee0
Merge pull request #207 from gabriel-samfira/update-readme
Update readme
2024-02-12 11:04:33 +02:00
Gabriel Adrian Samfira
8efdcba359 Update README
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-12 09:01:13 +00:00
Gabriel Adrian Samfira
d4a9a821cf Add some more info
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-12 08:44:26 +00:00
Gabriel Adrian Samfira
1ffa562581 Add using garm doc
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-12 01:06:25 +00:00
Gabriel Adrian Samfira
d17629efd4 Add logging section info
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-11 12:47:19 +00:00
Gabriel Adrian Samfira
53264528ee Add Equinix and EC2 in the README
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-02-11 12:28:49 +00:00
Gabriel
7c44b8125a
Merge pull request #206 from gabriel-samfira/more-strict-token-checks
More strict instance token checks
2024-01-30 13:57:14 +02:00
Gabriel Adrian Samfira
9031a4029e More strict instance token checks
This change invalidates tokens based on more parameters. Tokens that were
generated for previous attempts of spinning up an instance will be invalidates.

Also, only instances that are in Running or Creating will be able to authenticate.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-01-30 11:07:55 +00:00
Gabriel
23c9ed6b6d
Merge pull request #205 from gabriel-samfira/add-some-logging
Add some logging
2024-01-30 11:41:53 +02:00
Gabriel Adrian Samfira
43b96c543d Add some logging
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-01-30 09:37:26 +00:00
Gabriel
8e0456c83a
Merge pull request #203 from gabriel-samfira/small-fixes
Small adjustments
2024-01-12 22:07:28 +02:00
Gabriel Adrian Samfira
5b735eaaf4 Small adjustments
This change increases the tools refresh interval to 5 minutes, cleans
up the websocket code a bit, augments the error message that may be returned
when trying to delete a runner in an invalid state and removes a log message
that does not add much value.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-01-12 19:53:27 +00:00
Gabriel
523237ca18
Merge pull request #202 from gabriel-samfira/cleanup-websocket-code
Fix log streamer and cleanup code
2024-01-06 16:22:09 +02:00
Gabriel Adrian Samfira
4d7fcbe23a Safely close the quit channel
Prevent accidental closure of an already closed channel.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-01-06 14:15:52 +00:00
Gabriel Adrian Samfira
70bfff96e0 Fix log streamer and cleanup code
I accidentally disabled the log streamer when I moved the config options
to their own section. This change fixes that.

This change also adds some safety checks and locking when cleaning up stale
clients. The websocket hub Write() function now copies the message before
sending it on the channel to the clients.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-01-06 14:05:38 +00:00
Gabriel
0aaeebde28
Merge pull request #201 from gabriel-samfira/switch-to-slog
Switch to slog
2024-01-06 03:04:09 +02:00
Gabriel Adrian Samfira
d44d64dbfd Use log_file from logging config
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-01-06 00:32:39 +00:00
Gabriel Adrian Samfira
61e97f0896 Append pool_type and pool_mgr info to logs
Pool managers will have 2 fields identifying which manager generated
the log line.

In the future, we will add tracking ids in various cases, allowing
us to track down issues faster.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-01-06 00:21:50 +00:00
Gabriel Adrian Samfira
e441b6ce89 Switch to log/slog
This change switches GARM to the new structured logging standard
library. This will allow us to set log levels and reduce some of
the log spam.

Given that we introduced new knobs to tweak logging, the number of
config options for logging now warrants it's own section.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-01-05 23:46:40 +00:00
Gabriel
f72e97209f
Merge pull request #200 from gabriel-samfira/add-systeminfo-callback
Add system-info instance callback
2024-01-04 17:38:02 +02:00
Gabriel Adrian Samfira
2a5e2409b2 Add system-info instance callback
Allow runners to update their own system information. Runners can now send
back os_name, os_version and agent_id back as part of a POST to
CALLBACK_URL/system-info/.

The goal is to get better info in regard to the actual OS that's running
and to move the agent_id from the status updates to the system-info callback.

The status updates should be used only to send back info about the status of
the installation process.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2024-01-04 15:23:43 +00:00
Gabriel
8fe4f17e1c
Merge pull request #198 from gabriel-samfira/create-dirs
Create needed folders before use
2023-12-18 18:50:22 +02:00
Gabriel Adrian Samfira
912371cf57 Create needed folders before use
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 16:50:02 +00:00
Gabriel Adrian Samfira
6c7c5a913f Define variable before use
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 16:43:30 +00:00
Gabriel
6dbdd5e9b0
Merge pull request #197 from gabriel-samfira/copy-config
Copy provider config in garm folder
2023-12-18 18:39:49 +02:00
Gabriel Adrian Samfira
5d596aa94c Copy provider config in garm folder
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 16:39:30 +00:00
Gabriel
a8f468b4a9
Merge pull request #196 from gabriel-samfira/fix-e2e-tests
Export required variables
2023-12-18 18:32:40 +02:00
Gabriel Adrian Samfira
e6eed93546 Export required variables
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 16:31:52 +00:00
Gabriel
ca62deab8d
Merge pull request #195 from gabriel-samfira/update-deps
Update deps
2023-12-18 18:25:58 +02:00
Gabriel Adrian Samfira
0dd4f38691 Update go-github
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 16:20:44 +00:00
Gabriel Adrian Samfira
66bf762cd6 Update to latest jwt
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 16:20:44 +00:00
Gabriel Adrian Samfira
3ec6aeace2 Update dependencies
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 16:20:44 +00:00
Gabriel
a13c5db1a7
Merge pull request #194 from gabriel-samfira/remove-lxd-provider
Remove the LXD internal provider
2023-12-18 18:15:54 +02:00
Gabriel Adrian Samfira
ff5b9d22a7 Fix k8s path
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 15:24:52 +00:00
Gabriel Adrian Samfira
c4b2a3cd1f Update Dockerfile
Add new providers to Dockerfile:

* k8s
* lxd
* incus

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 14:56:05 +00:00
Gabriel Adrian Samfira
d1d8bfa703 Update docs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 14:49:36 +00:00
Gabriel Adrian Samfira
affb56f9a0 Remove the LXD internal provider
Canonical have relicensed the LXD project to AGPLv3. This means that we can
no longer update the go LXD client without re-licensing GARM as AGPLv3. This
is not desirable or possible.

The existing code seems to be Apache 2.0 and all code that has already been
contributed seems to stay as Apache 2.0, but new contributions from Canonical
employees will be AGPLv3.

We cannot risc including AGPLv3 code now or in the future, so we will separate
the LXD provider into its own project which can be AGPLv3. GARM will simply
execute the external provider.

If the client code of LXD will ever be split from the main project and re-licensed
as Apache 2.0 or a compatible license, we will reconsider adding it back as a
native provider. Although in the long run, I believe external providers will
be the only option as they are easier to write, easier to maintain and safer to
ship (a bug in the provider does not crash GARM itself).

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-18 12:16:48 +00:00
Gabriel
fc7a7dde35
Merge pull request #193 from gabriel-samfira/prevent-api-spam
Prevent abusing the GH API
2023-12-16 14:06:30 +02:00
Gabriel Adrian Samfira
459906d97e Prevent abusing the GH API
On large deployments with many jobs, we cannot check each job that
we recorded in the DB against the GH API.

Before this change, if a job was updated more than 10 minutes ago,
garm would check against the GH api if that job still existed. While
this approach allowed us to maintain a consistent view over which jobs
still exist and which are stale, it had the potential of spamming the
GH API, leading to rate limiting.

This change uses the scale-down loop as an indicator for job staleness.

If a job remains in queued state in our DB, but has dissapeared from GH
or was serviced by another runner and we never got the hook (garm was down
or GH had an issue - happened in the past), then garm will spin up a new
runner for it. If that runner or any other runner is scaled down, we check
if we have jobs in the queue that should have matched that runner. If we did,
there is a high chance that the job no longer exists in GH and we can remove
the job from the queue.

Of course, there is a chance that GH is having issues and the job is never
pushed to the runner, but we can't really account for everything. In this case
I'd rather avoid rate limiting ourselves.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-15 22:41:50 +00:00
Gabriel
46ac1b8166
Merge pull request #191 from gabriel-samfira/update-readme
Add some more info to README
2023-12-11 17:53:32 +02:00
Gabriel Adrian Samfira
71c741c43a Add some more info to README
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-11 15:48:28 +00:00
Gabriel
c6ec83a7c6
Merge pull request #190 from gabriel-samfira/update-readme
Add the k8s provider to the list
2023-12-11 17:22:18 +02:00
Gabriel Adrian Samfira
71657bd06b Add the k8s provider to the list
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-11 15:17:12 +00:00
Gabriel
c712366663
Merge pull request #189 from gabriel-samfira/add-option-to-disable-jit-config
Add option to disable JIT config
2023-12-11 16:15:45 +02:00
Gabriel Adrian Samfira
49e06efdf8 Update sample config
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-11 14:05:10 +00:00
Gabriel Adrian Samfira
85968598b0 Add option to disable JIT config
This change adds a flag on providers that allows users to disable JIT
configuration even when it's available. For context, JIT is available
on github.com and any GHES instance >=3.10.

This option is a stopgap measure for providers that have not yet been
updated to use JIT configs instead of runner registration tokens.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-12-11 12:37:33 +00:00
Gabriel
0e36eb7056
Merge pull request #188 from mercedes-benz/bypass_additional_environment_variables
feat: passthrough additional env vars to provider bin
2023-12-01 13:06:27 +02:00
Mario Constanti
927a1a4308 feat: build garm with go 1.21
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2023-12-01 11:56:06 +01:00
Mario Constanti
215bd71855 feat: passthrough additional env vars to provider
as some provider binaries probably need additional environment variables
set (e.g kubernetes as client-go depends on KUBERNETES_SERVICE_ vars) it
should be possible to define a list of environment variables which
should get bypassed into the provider binary execution
2023-12-01 11:54:34 +01:00
Gabriel
05e179604d
Merge pull request #183 from gabriel-samfira/force-remove-runner
Add force delete runner
2023-11-21 20:56:24 +02:00
Gabriel Adrian Samfira
b9c7c93f7f
Fix linting issues
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-11-21 20:52:40 +02:00
Gabriel
70501ffc78
Merge pull request #3 from mihaelabalutoiu/add-more-integration-tests
Add more integration tests
2023-11-21 20:40:29 +02:00
Mihaela Balutoiu
c563ace750 Add integration tests for test external provider
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-11-06 13:03:25 +02:00
Gabriel Adrian Samfira
d09f12dfd8 Add force delete runner
This branch adds the ability to forcefully remove a runner from GARM.

When the operator wishes to manually remove a runner, the workflow is as
follows:

* Check that the runner exists in GitHub. If it does, attempt to
  remove it. An error here indicates that the runner may be processing
  a job. In this case, we don't continue and the operator gets immediate
  feedback from the API.
* Mark the runner in the database as pending_delete
* Allow the consolidate loop to reap it from the provider and remove it
  from the database.

Removing the instance from the provider is async. If the provider errs out,
GARM will keep trying to remove it in perpetuity until the provider succedes.

In situations where the provider is misconfigured, this will never happen, leaving
the instance in a permanent state of pending_delete.

A provider may fail for various reasons. Either credentials have expired, the
API endpoint has changed, the provider is misconfigured or the operator may just
have removed it from the config before cleaning up the runners. While some cases
are recoverable, some are not. We cannot have a situation in which we cannot clean
resources in garm because of a misconfiguration.

This change adds the pending_force_delete instance status. Instances marked with
this status, will be removed from GARM even if the provider reports an error.

The GARM cli has been modified to give new meaning to the --force-remove-runner
option. This option in the CLI is no longer mandatory. Instead, setting it will mark
the runner with the new pending_force_delete status. Omitting it will mark the runner
with the old status of pending_delete.

Fixes: #160

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-10-12 06:15:36 +00:00
Gabriel
7f4f4bd7e1
Merge pull request #182 from gabriel-samfira/update-common
Update garm-provider-common
2023-10-09 14:02:09 +03:00
Gabriel Adrian Samfira
26dbc3d8e5 Update garm-provider-common
This update pulls in the latest version of garm-provider-common which removes
its dependency on go-github, making future updates much less painful.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-10-09 10:55:11 +00:00
Gabriel
7fda604a37
Merge pull request #180 from mercedes-benz/additional_metrics
feat: add new metrics
2023-10-06 11:43:00 +03:00
Mario Constanti
58e8b3454c feat: add new metrics
add info metrics about providers, enterprises, organizations,
repositories and pools.

Also expose most of the configurable pool information as metric like
e.g. max Runners as garm_pool_max_runners

Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2023-10-06 10:21:56 +02:00
Gabriel
a48ec0c0a8
Merge pull request #163 from gabriel-samfira/add-jit-config
Add jit config
2023-09-24 17:15:38 +03:00
Gabriel Adrian Samfira
019948acbe Add JIT config as part of instance create
We must create the DB entry for a runner with a JIT config included. Adding it later
via an update runs the risk of having the consolidate loop pick up the incomplete instance.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:51:17 +00:00
Gabriel Adrian Samfira
8c507a9251 Run go generate
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:51:17 +00:00
Gabriel Adrian Samfira
4bedb1dd63 Fix URLs for enterprises
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:51:17 +00:00
Gabriel Adrian Samfira
5f2cb19503 Use accessors when getting response values
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:51:17 +00:00
Gabriel Adrian Samfira
e238f84781 update modules
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:51:16 +00:00
Gabriel Adrian Samfira
e53c271337 Add metadata URLs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:50:21 +00:00
Gabriel Adrian Samfira
1268507ce6 Add jit config routes
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:50:20 +00:00
Gabriel Adrian Samfira
5214aca228 Add jit config for new runner
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:49:57 +00:00
Gabriel Adrian Samfira
6dea1c1937 Add temporary replace to fork
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:49:56 +00:00
Gabriel Adrian Samfira
d5f8cf079e Ignore instances that are still being created from reaping
When using JIT runners, we register the runner on GitHub before we get
a chance to spin up the instance in the provider. In such cases, we end
up with a runner in "offline" state while we're creating the actual resource
that will embody the runner. This change will give runners a chance to come
online before garm tries to clean them up.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:49:06 +00:00
Gabriel Adrian Samfira
591641a8a3 Add temporary redirect to go-github fork
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:49:04 +00:00
Gabriel Adrian Samfira
09d2f1b061 Add Jit functions to GH client interface
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:48:09 +00:00
Gabriel Adrian Samfira
de17fb04b4 Add helper functions for marshaling and sealing
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:48:09 +00:00
Gabriel Adrian Samfira
034cc47185 Add jitconfig model field
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 13:48:09 +00:00
Gabriel
6089f17b08
Merge pull request #179 from gabriel-samfira/update-dependencies
Update go-github and garm-provider-common
2023-09-24 11:10:54 +03:00
Gabriel Adrian Samfira
90c954e0e5 Replace deprecated function call
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 08:04:00 +00:00
Gabriel Adrian Samfira
fc77a4b735 Update go-github and garm-provider-common
We need to abstract away the tools struct and not have garm-provider-common
depend on go-github just for that one struct. It makes it hard to update
go-github without updating garm-provider-common first and then all the rest
of the providers.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-09-24 07:56:56 +00:00
Gabriel
b1dd54c07e
Merge pull request #175 from mihaelabalutoiu/add-cleanup-webhooks
Cleaning up leftover Github webhooks for `org/repo`
2023-08-29 17:54:55 +03:00
Mihaela Balutoiu
f9c3f30ae4 Cleaning up leftover Github webhooks for org/repo
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-29 11:10:11 +03:00
Gabriel
0da5f106a0
Merge pull request #174 from gabriel-samfira/add-ca-cert-bundle-metadata
Add root CA bundle metadata URL
2023-08-28 13:10:40 +03:00
Gabriel Adrian Samfira
2caf25f18b Run go generate
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-28 09:58:13 +00:00
Gabriel Adrian Samfira
a26907fb91 Add root CA bundle metadata URL
Thic change adds a metadata endpoint that returns a list of root CA
certificates a runner must install in order to be able to validate all
relevant API endpoints it may require. This includes any GHES API that
runs on a self signed certificate.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-28 09:44:18 +00:00
Gabriel
f463a41ce2
Merge pull request #173 from gabriel-samfira/switch-to-seal-unseal
Switch to seal unseal
2023-08-28 11:42:25 +03:00
Gabriel Adrian Samfira
4d1acdcaab Switch to util.Seal and util.Unseal
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-28 08:15:50 +00:00
Gabriel Adrian Samfira
d700b790ac Update garm-provider-common and go-github
* Updates the garm-provider-common and go-github packages.
* Update sqlToParamsInstance to return an error when unmarshaling

This change is needed to pull in the new Seal/Unseal functions in common.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-28 08:13:44 +00:00
Gabriel
4348999cb1
Merge pull request #172 from gabriel-samfira/add-relation-to-jobs
Add relation to jobs
2023-08-26 23:19:22 +03:00
Gabriel Adrian Samfira
f2100f7c91 Fix tests
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-26 20:13:48 +00:00
Gabriel Adrian Samfira
891b6d3105 Run go generate
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-26 19:47:17 +00:00
Gabriel Adrian Samfira
59e6fb28c2 Create relation between WorkflowJobs and Instances
Ensure that there is a foreign key constraint between runners and jobs.
Once a runner is associated with a job, we want the job to be removed along
with the runner.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-26 19:45:59 +00:00
Gabriel
d3479790d7
Merge pull request #171 from ionutbalutoiu/optimize-wait-pool-running-idle-func
Optimize `waitPoolRunningIdleInstances` func
2023-08-25 17:37:15 +03:00
Ionut Balutoiu
93d290df47 Optimize waitPoolRunningIdleInstances func
Instead of asking for all the GARM instances from the API, and then
filtering them by `poolID`, we can ask the API to return only the
instances that are in the `poolID` pool.

Therefore, we only need to count the instances that are running and idle.

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-08-25 17:14:11 +03:00
Gabriel
4f8ca6082c
Merge pull request #170 from gabriel-samfira/fix-runner-group-on-create-pool
Properly set runner group when creating a pool
2023-08-25 16:39:26 +03:00
Gabriel Adrian Samfira
7b6f51c032 Properly set runner group when creating a pool
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-25 13:29:26 +00:00
Gabriel
b44f04be5d
Merge pull request #169 from gabriel-samfira/fix-pool-manager-start
Fix garm pool manager startup
2023-08-25 12:04:14 +03:00
Gabriel Adrian Samfira
baa7df65a4 Fix garm pool manager startup
If we fail to get the tools for one pool, garm fails to start due to pool
manager startup timeout. Launch the initial tools update function as a
goroutine and return from Start(). If it fails, it will retry, and we won't
block garm from starting.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-25 08:57:24 +00:00
Gabriel
e314688ad7
Merge pull request #168 from ionutbalutoiu/fix-e2e-tests
Fix `waitPoolRunningIdleInstances` function
2023-08-24 16:43:16 +03:00
Ionut Balutoiu
4e3ad41c0b Fix waitPoolRunningIdleInstances function
The variable `runningIdleCount` would get incremented for instances
on every pool, instead of only for the pool we are interested in.
This change fixes this.

Also, adjust the logging message when error occurs in this timeout
exceeded scenario.

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-08-24 16:12:00 +03:00
Gabriel
385a00ef9d
Merge pull request #167 from ionutbalutoiu/refactor-e2e-tests
Refactor integration E2E tests
2023-08-24 15:56:12 +03:00
Ionut Balutoiu
318bc52b57 Refactor integration E2E tests
* General cleanup of the integration tests Golang code. Move the
  `e2e.go` codebase into its own package and separate files.
* Reduce the overall log spam from the integration tests output.
* Add final GitHub workflow step that stops GARM server, and does the
  GitHub cleanup of any orphaned resources.
* Add `TODO` to implement cleanup of the orphaned GitHub webhooks.
  This is useful, if the uninstall of the webhooks failed.
* Add `TODO` for extra missing checks on the GitHub webhooks
  install / uninstall logic.

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-08-24 15:22:46 +03:00
Gabriel
789644c27f
Merge pull request #166 from gabriel-samfira/fix-gh-client-tls-bug
Fix TLS client bug
2023-08-23 14:33:30 +03:00
Gabriel
e263db16c1
Merge pull request #165 from gabriel-samfira/fix-cli-nil-pointer-dereference
Fix nil pointer dereference
2023-08-23 14:28:45 +03:00
Gabriel Adrian Samfira
073ea1175e Fix TLS client bug
The CA bundle must be set on RootCAs to properly validate the remote server.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-23 11:27:18 +00:00
Gabriel Adrian Samfira
fb2bb7fb08 Fix nil pointer dereference
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-23 11:21:15 +00:00
Gabriel
bc0a34bae9
Merge pull request #164 from gabriel-samfira/use-apg-for-password
Use apg to generate passwords
2023-08-22 22:32:40 +03:00
Gabriel Adrian Samfira
6e98c3e088 Use apg to generate passwords
It appears that in some cases, generating passwords by reading /dev/urandom
and piping to tr, fails. Use apg.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 19:32:15 +00:00
Gabriel
348058baf1
Merge pull request #161 from mihaelabalutoiu/add-webhooks-integration-tests
Add webhooks integration tests for `organization` and `repository`
2023-08-22 22:03:45 +03:00
Mihaela Balutoiu
300ad110f0 Add webhooks integration tests
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-22 21:23:56 +03:00
Gabriel
153df36066
Merge pull request #162 from ionutbalutoiu/fix-e2e-secrets-generation
Fix e2e secrets generation
2023-08-22 11:55:41 +03:00
Ionut Balutoiu
5ced5c4b1c Fix spacing
Remove extra spaces from the `integration-tests.yml` file.

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-08-22 11:47:48 +03:00
Ionut Balutoiu
3d3ce2922d Silence tr stderr output
This seems to be related to the distribution used by the GitHub
`ubuntu-latest` runners, as I can't reproduce it locally on my
Ubuntu 22.04 server.

An useful discussion on this topic:
https://stackoverflow.com/questions/48725875/is-there-a-workaround-for-this-broken-pipe-error

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-08-22 11:43:06 +03:00
Ionut Balutoiu
8900de7a1b [integration-tests] Update randomStringGenerator bash function
Some integration tests workflows failed with:
```
Error: Invalid format 'ORG_WEBHOOK_SECRET=***'
```
or
```
Error: Invalid format 'GARM_PASSWORD=***'
```

Workflow runs logs:
* https://github.com/cloudbase/garm/actions/runs/5920389694/job/16051606203#step:7:26
* https://github.com/cloudbase/garm/actions/runs/5908193226/job/16027297143#step:7:26

This is a transient error, as it only happens sometimes.

I suspect that sometimes there is some illegal sequence of characters
in the random generated strings. Thus, the GitHub actions logic to
parse the environment fails.

This change removes the special characters that would have a special
meaning in bash, from the `randomStringGenerator` function, in hopes
to fix the transient issue.

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-08-22 11:17:43 +03:00
Gabriel
9a7fbde025
Merge pull request #154 from gabriel-samfira/add-webhook-configuration
Add webhook management for repositories and organizations
2023-08-22 09:48:47 +03:00
Gabriel Adrian Samfira
3b651afe07
Add optional --install-webhook flag when creating repo/org
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:02 +03:00
Gabriel Adrian Samfira
93bfb6fe07
ping the webhook after creation
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:02 +03:00
Gabriel Adrian Samfira
7bd3e0b6f7
Add ping hook functions to client
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:02 +03:00
Gabriel Adrian Samfira
64d3da4034
Update comment on option
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:02 +03:00
Gabriel Adrian Samfira
d57e488f12
Return details in case PAT does not have access
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:02 +03:00
Gabriel Adrian Samfira
c641e1d596
Fixup field name
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:02 +03:00
Gabriel Adrian Samfira
1c0ff85a0d
Add flag to toggle webhook management
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:02 +03:00
Gabriel Adrian Samfira
c00048e128
Add optional keepWebhook flag when removing an entity
The user can opt to not delete the webhook (if installed) when removing
the entity from garm. Garm will only ever try to remove a webhook that
exactly matches the URL that is composed of the base webhook URL configured
in the config.toml file and the unique controller ID that is generated
when the controller is first installed. It should be safe to remove the
webhook when the entity is removed.

Of course, this behavior can be disabled.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:02 +03:00
Gabriel Adrian Samfira
bb6ee9c668
Add keepWebhook flag when deleting entities
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:01 +03:00
Gabriel Adrian Samfira
763eb705d8
Remove webhook when removing an entity & cmd fixes
* When removing a repo or org, we uninstall the webhook as well.
  * Upgrade cobra command and mark "webhook-secret" and "random-webhook-secret"
    as MarkFlagsOneRequired()

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:01 +03:00
Gabriel Adrian Samfira
779afe980e
Add webhook show, return info and some fixes
* Added a webhook show command. This gives us info about the webhook and
    if it is installed.
  * Return webhook info when installing the webhook
  * Small typo fixes.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:01 +03:00
Gabriel Adrian Samfira
6051fa016c
Return bad request if hook already installed
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:01 +03:00
Gabriel Adrian Samfira
dbd41f518d
Add CLI webhook enablement
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:01 +03:00
Gabriel Adrian Samfira
7ce3f007b0
Add functions to (un)install webhooks for orgs and repos
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:01 +03:00
Gabriel Adrian Samfira
f2796f1d5a
Add admin required middleware and webhook endpoint
* Add a new middleware that tests for admin access
  * Add a new controller ID suffixed webhook endpoint. This will be used
    to accept webhook events on a webhook URL that is suffixed with our own
    controller ID.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-22 09:39:01 +03:00
Gabriel
aa2b42fddb
Merge pull request #156 from gabriel-samfira/build-windows
Enable Windows builds
2023-08-18 17:52:29 +03:00
Gabriel Adrian Samfira
af54b55cea Enable Windows builds
This change adds the needed bits to enable Windows builds. This also adds
a new make target to create the release files that will be uploaded as part
of new releases.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-18 14:46:00 +00:00
Gabriel
c9cf114d92
Merge pull request #153 from mihaelabalutoiu/fix-doc-typo
Small fixes for the docs
2023-08-14 16:05:40 +03:00
Mihaela Balutoiu
93c2368c55 Small fixes for the docs
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-14 15:46:26 +03:00
Gabriel
10cc209105
Merge pull request #152 from mihaelabalutoiu/fix-timeout-logic
Fix timeout logic
2023-08-14 14:47:38 +03:00
Mihaela Balutoiu
6b77979ab5 Fix timeout logic
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-14 14:35:07 +03:00
Gabriel
bf509ad9c9
Merge pull request #151 from mihaelabalutoiu/add-timeout
Log `orgPool/repoPool` details on timeout exceeded
2023-08-14 12:33:12 +03:00
Mihaela Balutoiu
475cc6425b Add log orgPool/repoPool details on timeout exceeded
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-14 11:45:10 +03:00
Gabriel
e2b617e12e
Merge pull request #150 from gabriel-samfira/add-controller-info
Add controller info
2023-08-13 02:03:31 +03:00
Gabriel Adrian Samfira
99539edde7 Add controller info
This change adds a new controller info endpoint and associated client and
CLI command. The controller info endpoint returns information about controller
status and configuration.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-12 22:47:50 +00:00
Gabriel
63d2764ddd
Merge pull request #149 from mihaelabalutoiu/add-cleanup-runners
Cleaning up leftover runners for `org/repo`
2023-08-09 17:26:43 +03:00
Mihaela Balutoiu
aa956ae939 Cleaning up leftover runners for org/repo
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-09 16:31:50 +03:00
Gabriel
1a07073820
Merge pull request #148 from mihaelabalutoiu/fix-handle-error
Set pipefail to the script and log org/repo details on timeout exceeded
2023-08-07 12:43:06 +03:00
Mihaela Balutoiu
191d44fb3f Log org/repo details on timeout exceeded
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-07 12:37:09 +03:00
Mihaela Balutoiu
1bd288f56d Set pipefail to the script
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-07 12:37:09 +03:00
Gabriel
29660c0b2c
Merge pull request #147 from gabriel-samfira/add-workflow-dispatch
Add workflow dispatch trigger
2023-08-07 12:35:07 +03:00
Gabriel Adrian Samfira
8c82864e11
Add workflow dispatch trigger
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-07 10:30:50 +03:00
Gabriel
a4bd45bedd
Merge pull request #146 from mihaelabalutoiu/add-upload-artifacts
Add upload artifacts and log instance details on timeout exceeded
2023-08-05 02:06:46 +03:00
Mihaela Balutoiu
97d1202225 Log instance details on timeout exceeded
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-04 23:28:26 +03:00
Mihaela Balutoiu
a7198a7d51 Add upload artifacts
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-04 23:24:43 +03:00
Gabriel
c64b8c36d4
Merge pull request #145 from mihaelabalutoiu/add-integration-tests
Add GitHub workflow for integration tests
2023-08-02 20:36:22 +03:00
Mihaela Balutoiu
cf0c1f188b Fix org_name/repo_name
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-02 20:24:44 +03:00
Mihaela Balutoiu
528f521897 Set schedule workflow to run every day at midnight
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-02 19:34:41 +03:00
Mihaela Balutoiu
4fa83b6ffc
Merge pull request #1 from gabriel-samfira/add-ngrok
Add ngrok
2023-08-02 18:57:37 +03:00
Gabriel Adrian Samfira
9927a18b9a
Update ngrok action
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-02 18:54:07 +03:00
Gabriel Adrian Samfira
d02292bd1a
Fix config dir location
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-02 17:29:08 +03:00
Gabriel Adrian Samfira
d2ffa22204
Set up ngrok and use sudo
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-08-02 17:14:27 +03:00
Mihaela Balutoiu
6f69f942cf Add GitHub workflow for integration tests
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-08-02 16:11:55 +03:00
Gabriel
d373b1cfa3
Merge pull request #144 from gabriel-samfira/enable-debug-spec-in-lxd
Update to latest version of garm-provider-common and update docs
2023-07-26 19:11:29 +03:00
Gabriel Adrian Samfira
3e446a8191 Update docs and deps
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-26 16:03:36 +00:00
Gabriel
7d74b6bc52
Merge pull request #142 from mihaelabalutoiu/add-new-garm-cli
Update `garm-cli` tool to use the new swagger generated client library
2023-07-25 20:00:06 +03:00
Mihaela Balutoiu
ff5abf1294 Implement API client functionality in the garm-cli
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-07-25 19:26:00 +03:00
Gabriel
851a9bd0ae
Merge pull request #143 from gabriel-samfira/move-code-to-external-package
Move code to external package
2023-07-24 15:44:49 +03:00
Gabriel Adrian Samfira
101072caff Update deps
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-24 11:53:24 +00:00
Gabriel Adrian Samfira
7235006e65 Update deps
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-24 07:21:34 +00:00
Gabriel Adrian Samfira
72f45bba47 Remove unused code
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-24 07:14:29 +00:00
Gabriel Adrian Samfira
dbb824e718 Add extra specs doc
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-23 17:02:56 +00:00
Gabriel Adrian Samfira
7e4dcea056 Update deps
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-23 15:50:49 +00:00
Gabriel Adrian Samfira
e33b64aacb Providers now return ProviderInstance{}
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-23 12:47:56 +00:00
Gabriel Adrian Samfira
2a6b453fc1 Move the exec helper
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-23 12:33:49 +00:00
Gabriel Adrian Samfira
f0332b7578 Run go generate
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-22 22:42:57 +00:00
Gabriel Adrian Samfira
e775c9c11d Move most of util package
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-22 22:39:17 +00:00
Gabriel Adrian Samfira
ed651bb7d0 Move errors to external package
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-22 22:26:47 +00:00
Gabriel Adrian Samfira
da13cec2de Move code to external package
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-21 15:34:18 +00:00
Gabriel
14586f0154
Merge pull request #141 from gabriel-samfira/docks-update
Remove unfinished doc
2023-07-20 14:02:06 +03:00
Gabriel Adrian Samfira
9cc49aad52 Remove unfinished doc
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-20 11:01:34 +00:00
Gabriel
0987bba343
Merge pull request #129 from gabriel-samfira/docs-update
Update some docs
2023-07-20 13:52:34 +03:00
Gabriel Adrian Samfira
cc228a035b Cleanup old docs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-20 10:46:22 +00:00
Gabriel
019d9ef927
Merge pull request #140 from mihaelabalutoiu/add-more-swagger-client-api
Complete the swagger client library with full functionality
2023-07-19 18:55:51 +03:00
Mihaela Balutoiu
d2b78793f5 Update generated swagger client code
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-07-19 18:06:16 +03:00
Mihaela Balutoiu
802c7527fe Add more swagger annotations for apiserver
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-07-19 18:06:13 +03:00
Gabriel
ddd6976115
Merge pull request #139 from mihaelabalutoiu/fix-swagger-annotations
Fix swagger annotations
2023-07-18 20:03:36 +03:00
Mihaela Balutoiu
e3275b4dc1 Update generated swagger client code
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-07-18 19:29:02 +03:00
Mihaela Balutoiu
9ba3ae487b Update the swagger annotations for the apiserver
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-07-18 19:27:21 +03:00
Gabriel
018692ecc3
Merge pull request #2 from icadariu/lint_fix
docs: lint + spell check
2023-07-18 18:44:48 +03:00
Ionut Cadariu
8af61fd920
docs: lint + spell check
Signed-off-by: Ionut Cadariu <ionut.cadariu@gmail.com>
2023-07-18 17:24:41 +02:00
Ionut Cadariu
fc40796a51
docs: lint + spell check
Signed-off-by: Ionut Cadariu <ionut.cadariu@gmail.com>
2023-07-18 17:17:49 +02:00
Gabriel Adrian Samfira
3f7d9b9b99 Update README
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-18 14:56:58 +00:00
Gabriel Adrian Samfira
6a56a19eb8 Add missing sections in Quickstart
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-18 14:39:08 +00:00
Gabriel
0d08808c81
Merge pull request #138 from ionutbalutoiu/small-fixes
Small fixes to the GARM api server
2023-07-18 17:25:30 +03:00
Ionut Balutoiu
572094700d Fix calling /api/v1/first-run without ending /
The endpoint endpoint `/api/v1/first-run` only works when we
have ending `/`.

This commit fixes this.

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-07-18 17:01:17 +03:00
Ionut Balutoiu
4787622450 Fix Content-Type not being set on invalidAuthResponse
When `w.WriteHeader(...)` is called, the HTTP headers are written in
the HTTP response.

Therefore, calling `w.Header().Add(...)` after `w.WriteHeader(...)`
will not have any effect.

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-07-18 16:42:32 +03:00
Gabriel
91dd082f81
Merge pull request #136 from mihaelabalutoiu/add-more-swagger-client-api
Add more functionality to swagger client library
2023-07-18 16:00:16 +03:00
Mihaela Balutoiu
520f468500 Update generated swagger client code
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-07-18 15:20:31 +03:00
Mihaela Balutoiu
f13d19b4ec Add more functionality to swagger client library
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-07-18 15:19:53 +03:00
Gabriel Adrian Samfira
9e7797e459 Add quickstart
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-18 08:47:55 +00:00
Gabriel Adrian Samfira
751da62b1e Update webhooks doc
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-17 15:48:12 +00:00
Gabriel Adrian Samfira
0ae1f7f5f2 Merge branch 'docs-update' of github.com:gabriel-samfira/garm into docs-update 2023-07-17 15:03:49 +00:00
Gabriel
8089244c9c
Merge pull request #134 from mihaelabalutoiu/add-more-swagger-client-api
Implement more features for the swagger client API
2023-07-17 16:16:46 +03:00
Mihaela Balutoiu
db21fb6ea9 Update generated swagger client code
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-07-17 14:24:54 +03:00
Mihaela Balutoiu
98e415bf11 Add more swagger annotations to apiserver
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-07-17 12:00:51 +03:00
Gabriel Adrian Samfira
dd3322175d Add some more docs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 12:02:23 +00:00
Gabriel Adrian Samfira
e8da39dd91 Add some more docs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 12:02:23 +00:00
Gabriel Adrian Samfira
407440bbd8 Remove debugging_and_profiling.md
This file was merged in config_default.md

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 12:02:23 +00:00
Gabriel Adrian Samfira
666a08f653 Fix typo
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 12:02:23 +00:00
Gabriel Adrian Samfira
078659f81f Remove leftover test
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 12:02:23 +00:00
Gabriel Adrian Samfira
01d44067dc Update instance show example
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 12:02:23 +00:00
Gabriel Adrian Samfira
f5978f82d3 Remove some options and add docs
* Remove the unused CondifGir option
  * Add docs for the default section
  * Move some docs from other files

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 12:02:23 +00:00
Gabriel Adrian Samfira
73096dd5e6 Add profiling doc
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 12:02:23 +00:00
Gabriel Adrian Samfira
556050e270 Update some docs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 12:02:23 +00:00
Gabriel
fbee4d4cbd
Merge pull request #133 from gabriel-samfira/fix-garm-cli-version
Properly set garm-cli version
2023-07-16 14:13:10 +03:00
Gabriel Adrian Samfira
2076581d47 Properly set garm-cli version
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 11:12:32 +00:00
Gabriel Adrian Samfira
e5d3cae47a Add some more docs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 10:12:48 +00:00
Gabriel Adrian Samfira
1682e98ceb Add some more docs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 10:12:48 +00:00
Gabriel Adrian Samfira
dc27a549e2 Remove debugging_and_profiling.md
This file was merged in config_default.md

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 10:12:48 +00:00
Gabriel Adrian Samfira
40ff3589c9 Fix typo
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 10:12:48 +00:00
Gabriel Adrian Samfira
bcf3216314 Remove leftover test
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 10:12:48 +00:00
Gabriel Adrian Samfira
f1d5a3ce5b Update instance show example
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 10:12:48 +00:00
Gabriel Adrian Samfira
44bfa83fc0 Remove some options and add docs
* Remove the unused CondifGir option
  * Add docs for the default section
  * Move some docs from other files

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 10:12:48 +00:00
Gabriel Adrian Samfira
462e9415a5 Add profiling doc
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 10:12:48 +00:00
Gabriel Adrian Samfira
c2fa808cd3 Update some docs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-16 10:12:48 +00:00
Gabriel
824a1efd78
Merge pull request #132 from gabriel-samfira/add-dockerfile-and-workflow
Add dockerfile and workflow
2023-07-16 02:34:03 +03:00
Gabriel Adrian Samfira
30036bd128 Copy x509 root CAs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-15 23:22:38 +00:00
Gabriel Adrian Samfira
f96ea1edcf Add dockerfile and workflow
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-15 23:22:32 +00:00
Gabriel
72e0b12f62
Merge pull request #131 from mihaelabalutoiu/fix-routers-typo
Fix `apiserver/routers/routers.go` typo
2023-07-10 19:50:10 +03:00
Mihaela Balutoiu
a871931210 Fix apiserver/routers/routers.go typo
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-07-10 19:20:19 +03:00
Gabriel
9e849ed8f9
Merge pull request #128 from gabriel-samfira/set-on-delete-for-jobs
Set on delete for jobs
2023-07-05 22:56:41 +03:00
Gabriel Adrian Samfira
dea941df43 Set on delete for jobs
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-05 19:49:48 +00:00
Gabriel
9a8773539a
Merge pull request #127 from ionutbalutoiu/add-swagger-client-auth-info
Add swagger client auth info
2023-07-05 14:37:51 +03:00
Ionut Balutoiu
e5b52bea34 Update swagger client generated code
Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-07-05 14:25:31 +03:00
Ionut Balutoiu
a952729082 Update swagger:meta API info
* Include details about what API consumes / produces.
* Add info about GARM authentication.

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-07-05 14:24:37 +03:00
Gabriel
5e18f8570e
Merge pull request #126 from ionutbalutoiu/swagger-client-api-implementation
Add more swagger client API implementation
2023-07-05 13:58:29 +03:00
Ionut Balutoiu
5891216179 Update generated swagger client code
Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-07-05 13:48:01 +03:00
Ionut Balutoiu
ca878507b5 Add more functionality to swagger client library
* Update `go:generate` annotations to use stable swagger tag instead
  of relying on the `swagger` CLI tool already installed.
* Rename the following route IDs from repositories:
    * `Create` -> `CreateRepo`
    * `List` -> `ListRepos`
    * `Get` -> `GetRepo`
    * `Delete` -> `DeleteRepo`
  The swagger CLI spec validation will fail if the route IDs are not unique.
* Fully implement the all the API calls to:
    * `/api/v1/repositories`
    * `/api/v1/instances`

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-07-05 13:47:58 +03:00
Gabriel
3fe5d510fe
Merge pull request #124 from gabriel-samfira/fix-entity-update
Fix entity update
2023-07-05 13:39:07 +03:00
Gabriel Adrian Samfira
fe2cb01528 Slight refactor and fix tests
Updating a pool will no longer try to create a pool manager if one does
not already exist. A pool manager must be started when a pool is created.
Updating an existing pool without a pool manager is an error condition.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-05 09:46:19 +00:00
Gabriel
2efb1b2109
Merge pull request #125 from gabriel-samfira/add-entity-update-subcommand
Add entity update subcommand
2023-07-05 03:06:08 +03:00
Gabriel Adrian Samfira
86ed06d6ff Rename UpdateRepositoryParams to UpdateEntityParams
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-05 00:00:24 +00:00
Gabriel Adrian Samfira
6c6c6636ba Add org and enterprise update
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-04 23:24:19 +00:00
Gabriel Adrian Samfira
c162bde6cb Set pool manager status
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-04 23:05:01 +00:00
Gabriel Adrian Samfira
cec1d59991 Add repo update command
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-04 22:27:25 +00:00
Gabriel Adrian Samfira
3d26900d32 Set credentials in pool manager
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-04 22:11:45 +00:00
Gabriel Adrian Samfira
f12d93f14c Use random UUID4
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-04 14:24:06 +00:00
Gabriel
e1cf03d02e
Merge pull request #122 from gabriel-samfira/amend-comment
Update comment on function
2023-07-04 13:48:52 +03:00
Gabriel Adrian Samfira
a41eeb6f1e Update comment on function
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-04 10:48:14 +00:00
Gabriel
0889f6c999
Merge pull request #86 from gabriel-samfira/add-job-tracking
Add job tracking
2023-07-04 10:23:42 +03:00
Gabriel Adrian Samfira
6c06afb8e8 Don't add aditional labels to GH runner
For now, the aditional labels would only contain the job ID that triggered
the creation of the runner. It does not make sense to add this label to the
actual runner that registeres against github. We can simply use it internally
by fetching it from the DB.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:48:22 +00:00
Gabriel Adrian Samfira
0ab8f73bb4 Use r.log()
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
9101cdc0a2 Lower the tool update interval to 1 minute
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
f92ac2a74f Lower backoff timer to 1 minute
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
7f510ec40a Check if we have a recorded job
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
45dceae88c Add requested labels to cli
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
774b790cca tweak select
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
6169677cd9 Convert uuid.Nil to NULL
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
f027bc4fbd Attempt to add OnDelete:CASCADE to sqlite
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
117a41e9ed Add cascade on tags
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
f0e761bc6d Fix constraints
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
a526c1024c Various fixes
* enable foreign key constraints on sqlite
  * on delete cascade for addresses and status messages
  * add debug server config option
  * fix rr allocation

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
f7cf6bb619 increase backoff to 30 seconds
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
b6a593b20c fix sqlite connection URI
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
3796c25228 Amend some log messages
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
8f604c8a32 Fix test
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
bf90eb323a Add back update locks
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
4ec684b493 use journal mode WAL
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
4a2ba68867 Use the same db connection in runner
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
b3c754c015 set max connections to 1 when using sqlite3
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
faf4f18e0e Remove lock for update
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
b52f107bde Update log messages
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
c04a93dde9 Add basic round robin for pools
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
4b9c20e1be Reduce timeout to 10 seconds
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
28360fd662 Do not record jobs not meant for us
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
a15a91b974 Break lock and lower scale down timeout
Break the lock on a job if it's still queued and the runner that it
triggered was assigned to another job. This may cause leftover runners
to be created, but we scale those down in ~3 minutes.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
1287a93cf2 Add job list to API and CLI
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
b6a02db446 Remove completed jobs and slight optimization
* Removes completed jobs from the db
  * Skip ensure min idle runners for pools with min idle runners set to 0

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
5153738359 Small fixes
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel Adrian Samfira
fbffd8157b Add job tracking
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:46:20 +00:00
Gabriel
8abf94ef85
Merge pull request #121 from gabriel-samfira/use-errgroup
Replace wait implementation with errgroup
2023-07-03 10:45:48 +03:00
Gabriel Adrian Samfira
5bca63eeb1 Replace wait implementation with errgroup
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-07-03 07:40:57 +00:00
Gabriel
32464c7b6a
Merge pull request #120 from SystemKeeper/add-performance-considerations
Add doc about performance considerations
2023-07-02 00:19:41 +03:00
Marcel Müller
4d09a7977a Add doc about performance considerations
Signed-off-by: Marcel Müller <marcel-mueller@gmx.de>
2023-07-01 16:29:56 +02:00
Gabriel
681702e3db
Merge pull request #119 from mihaelabalutoiu/add-swagger-client
Generate client library via swagger
2023-06-30 22:30:19 +03:00
Ionut Balutoiu
4a68f3b046 Generate initial swagger API client library code
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-06-30 19:04:13 +03:00
Ionut Balutoiu
d122f293cf Add swagger annotations to apiserver
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-06-30 19:03:57 +03:00
Gabriel
b506df20da
Merge pull request #118 from gabriel-samfira/add-logging
Add logging and fix backoff loop
2023-06-30 09:54:45 +03:00
Gabriel Adrian Samfira
67b871488d Log the actual error
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-06-30 09:14:10 +03:00
Gabriel Adrian Samfira
0a27acd818 Remove extra loop and add logging
* removes an extra loop. The fetch tools loop does the same job
  * add a lot of log messages

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-06-30 08:52:16 +03:00
Gabriel Adrian Samfira
7358beb2b9 Merge Unlock() and UnlockAndDelete()
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-06-30 08:48:29 +03:00
Gabriel
aa44bf4f98
Merge pull request #116 from ionutbalutoiu/sighup-log-rotate
Rotate log file on SIGHUP
2023-06-27 20:12:55 +03:00
Ionut Balutoiu
721cbefd6a Rotate log file on SIGHUP
Add functionality to rotate the log file when `SIGHUP` signal is received.

Also, a doc is added with few details about logging.

Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
2023-06-27 20:04:20 +03:00
Gabriel
c45bd1d1d8
Merge pull request #115 from gabriel-samfira/use-su-to-install-runner
Use su to install the runner
2023-06-27 18:04:05 +03:00
Gabriel Adrian Samfira
c0347b0e9b Use su to install the runner
This change executes the runner install script provided via userdata using
su. The script itself has also been changed to assume it's running as the
runner user.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-06-27 07:15:31 +00:00
Gabriel
442e76e278
Merge pull request #112 from gabriel-samfira/use-select-with-wait
Refactor pool manager loop
2023-06-23 18:49:48 +03:00
Gabriel Adrian Samfira
1edb9247a8 Add per instance mux
Lock operations per instance name. This should avoid go routines trying
to update the same instance when operations may be slow.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-06-23 15:43:31 +00:00
Gabriel Adrian Samfira
a9cf5127a9 More granular loops, update go-github
This commit adds:

  * more granular loops for various operations
  * update go-github to latest version
  * skip trying to fetch runner info for canceled or skipped jobs
  * loops use waitgroups to signal exit

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-06-23 08:16:41 +00:00
Gabriel Adrian Samfira
f84da48f5b Accomodate older versions of curl
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-06-22 22:46:09 +00:00
Gabriel Adrian Samfira
4921692ee2 Wrap errgroup in select
This commit:

  * swaps WaitGroups with errgroups
  * wraps errgroup.Wait() in a select to prevent situations in which an
    operation takes a long time and prevents garm from being restarted.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2023-06-23 01:07:55 +03:00
Gabriel
f5226aec17
Merge pull request #111 from mihaelabalutoiu/fix-pools-typo
Fix `runner/pools.go` typo
2023-06-21 12:35:42 +03:00
Mihaela Balutoiu
d698e2815e Fix runner/pools.go typo
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-06-21 10:56:51 +03:00
Gabriel
1ebbbd6915
Merge pull request #110 from mihaelabalutoiu/add-more-pools-unit-tests
Add more `runner/pools.go` unit tests
2023-06-20 23:25:58 +03:00
Mihaela Balutoiu
00c0ada0aa Add more runner/pools.go unit tests
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
2023-06-19 23:39:07 +03:00
3288 changed files with 512069 additions and 226593 deletions

11
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"

61
.github/workflows/build-and-push.yml vendored Normal file
View file

@ -0,0 +1,61 @@
name: "Build and push GARM images"
on:
workflow_call:
inputs:
push_to_project:
description: "Project to build images for"
required: false
type: string
default: "ghcr.io/cloudbase"
ref:
description: "Ref to build"
required: false
type: string
default: "main"
permissions:
contents: read
jobs:
images:
permissions:
packages: write
name: "Build GARM images"
runs-on: ubuntu-latest
steps:
- name: "Checkout"
uses: actions/checkout@v4
with:
path: src/github.com/cloudbase/garm
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push image
env:
IMAGE_REGISTRY: ${{ inputs.push_to_project }}
GH_REF: ${{ inputs.ref }}
working-directory: src/github.com/cloudbase/garm
run: |
if [ "$GH_REF" == "main" ]; then
IMAGE_TAG="nightly"
else
IMAGE_TAG=$(git describe --tags --match='v[0-9]*' --always ${GH_REF})
fi
docker buildx build \
--provenance=false \
--platform linux/amd64,linux/arm64 \
--label "org.opencontainers.image.source=https://github.com/cloudbase/garm/tree/${GH_REF}" \
--label "org.opencontainers.image.description=GARM ${GH_REF}" \
--label "org.opencontainers.image.licenses=Apache 2.0" \
--build-arg="GARM_REF=${GH_REF}" \
-t ${IMAGE_REGISTRY}/garm:"${IMAGE_TAG}" \
--push .

View file

@ -4,9 +4,11 @@ on:
push: push:
branches: branches:
- main - main
- 'release/**'
pull_request: pull_request:
branches: branches:
- main - main
- 'release/**'
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }} group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }}
@ -17,23 +19,22 @@ permissions: {}
jobs: jobs:
linters: linters:
name: Linters name: Linters
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y libbtrfs-dev build-essential sudo apt-get install -y libbtrfs-dev build-essential apg jq
- uses: actions/setup-go@v3
with:
go-version: 'stable'
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: golangci/golangci-lint-action@v3 - uses: actions/setup-go@v5
with: with:
skip-cache: true go-version-file: go.mod
args: --timeout=8m --build-tags testing
- name: make lint
run: make golangci-lint && GOLANGCI_LINT_EXTRA_ARGS="--timeout=8m --build-tags=testing,integration" make lint
- name: Verify go vendor, go modules and gofmt - name: Verify go vendor, go modules and gofmt
run: | run: |
sudo apt-get install -y jq sudo apt-get install -y jq
@ -43,15 +44,39 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [linters] needs: [linters]
steps: steps:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libbtrfs-dev build-essential apg jq default-jre
- uses: actions/setup-node@v4
with:
node-version: '>=v24.5.0'
- name: Set up openapi-generator-cli
run: |
mkdir -p $HOME/openapi-generator
cd $HOME/openapi-generator
npm install @openapitools/openapi-generator-cli
echo "$HOME/openapi-generator/node_modules/.bin" >> $GITHUB_PATH
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Setup Golang - name: Setup Golang
uses: actions/setup-go@v3 uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
- run: go version - run: go version
- name: Run go generate
run: |
GOTOOLCHAIN=go1.24.6 make generate
- name: Run GARM Go Tests - name: Run GARM Go Tests
run: make go-test run: make go-test
- name: Run web UI tests
run: |
make webui-test

122
.github/workflows/integration-tests.yml vendored Normal file
View file

@ -0,0 +1,122 @@
name: Integration Tests
on:
workflow_dispatch: {}
schedule:
- cron: "0 0 * * *"
jobs:
integration-tests:
runs-on: ubuntu-noble-garm
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v3
with:
go-version-file: go.mod
- name: Setup LXD
uses: canonical/setup-lxd@main
with:
channel: latest/stable
- name: Install dependencies
run: |
sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get -qq update && sudo apt-get -qq install -y apg coreutils make jq build-essential libsqlite3-dev libsqlite3-0
- name: Set up tunnel
shell: bash
run: |
mkdir -p /home/runner/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > /home/runner/.ssh/ssh_key
sudo chown -R runner:runner /home/runner/.ssh
sudo chmod 500 /home/runner/.ssh
sudo chmod 400 /home/runner/.ssh/ssh_key
SUBDOMAIN=$(apg -a 0 -M l -m 12 -n 1)
echo "::add-mask::$SUBDOMAIN"
BASE_URL="${{ secrets.TUNNEL_BASE_URL }}"
GARM_BASE_URL="https://$SUBDOMAIN.$BASE_URL"
echo "::add-mask::$GARM_BASE_URL"
echo "GARM_BASE_URL=$GARM_BASE_URL" >> $GITHUB_ENV
cat <<EOF | sudo tee /etc/systemd/system/garm-tunnel.service
[Unit]
Description=GARM tunnel
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/ssh -q -i /home/runner/.ssh/ssh_key -N -n -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -R $SUBDOMAIN:80:127.0.0.1:9997 $BASE_URL
Restart=always
User=runner
[Install]
WantedBy=default.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable garm-tunnel
sudo systemctl start garm-tunnel
- name: Generate secrets
run: |
GARM_PASSWORD=$(apg -n1 -m32)
REPO_WEBHOOK_SECRET=$(apg -n1 -m32)
ORG_WEBHOOK_SECRET=$(apg -n1 -m32)
echo "::add-mask::$GARM_PASSWORD"
echo "::add-mask::$REPO_WEBHOOK_SECRET"
echo "::add-mask::$ORG_WEBHOOK_SECRET"
echo "GARM_PASSWORD=$GARM_PASSWORD" >> $GITHUB_ENV
echo "REPO_WEBHOOK_SECRET=$REPO_WEBHOOK_SECRET" >> $GITHUB_ENV
echo "ORG_WEBHOOK_SECRET=$ORG_WEBHOOK_SECRET" >> $GITHUB_ENV
echo "GARM_CHECKOUT_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV
- name: Create logs directory
if: always()
run: sudo mkdir -p /artifacts-logs && sudo chmod 777 /artifacts-logs
- name: Run integration tests
run: |
set -o pipefail
set -o errexit
make integration 2>&1
env:
ORG_NAME: gsamfira
REPO_NAME: garm-testing
CREDENTIALS_NAME: test-garm-creds
WORKFLOW_FILE_NAME: test.yml
GH_TOKEN: ${{ secrets.GH_OAUTH_TOKEN }}
LXD_REMOTE_SERVER: ${{ secrets.LXD_REMOTE_SERVER }}
- name: Show GARM logs
if: always()
run: |
sudo systemctl status garm@runner || true
sudo journalctl --no-pager 2>&1 > /artifacts-logs/system.log
sudo journalctl -u garm@runner --no-pager 2>&1 > /artifacts-logs/garm.log
- name: Upload GARM and e2e logs
if: always()
uses: actions/upload-artifact@v4
with:
name: garm-logs
path: /artifacts-logs
- name: Cleanup orphan GARM resources via GitHub API
if: always()
run: |
set -o pipefail
set -o errexit
sudo systemctl stop garm@runner || true
go run ./test/integration/gh_cleanup/main.go || true
env:
ORG_NAME: gsamfira
REPO_NAME: garm-testing
GH_TOKEN: ${{ secrets.GH_OAUTH_TOKEN }}

19
.github/workflows/trigger-manual.yml vendored Normal file
View file

@ -0,0 +1,19 @@
name: Manual build of GARM images
on:
workflow_dispatch:
inputs:
push_to_project:
description: "Project to build images for"
required: true
default: "ghcr.io/cloudbase"
ref:
description: "Ref to build"
required: true
default: "main"
jobs:
call-build-and-push:
uses: ./.github/workflows/build-and-push.yml
with:
push_to_project: ${{ inputs.push_to_project }}
ref: ${{ inputs.ref }}

10
.github/workflows/trigger-nightly.yml vendored Normal file
View file

@ -0,0 +1,10 @@
name: Nightly build of GARM images
on:
schedule:
- cron: "0 2 * * *"
jobs:
call-build-and-push:
uses: ./.github/workflows/build-and-push.yml
with:
ref: "main"

9
.gitignore vendored
View file

@ -4,6 +4,7 @@
*.dll *.dll
*.so *.so
*.dylib *.dylib
*.DS_Store
# Test binary, built with `go test -c` # Test binary, built with `go test -c`
*.test *.test
@ -16,3 +17,11 @@ bin/
# vendor/ # vendor/
.vscode .vscode
cmd/temp cmd/temp
build/
release/
node_modules/
.svelte-kit/
debug.html
git_push.sh
webapp/src/lib/api/generated/docs
.env

44
.golangci.yml Normal file
View file

@ -0,0 +1,44 @@
# SPDX-License-Identifier: MIT
linters:
disable-all: true
fast: false
enable:
- gci
- goconst
- gocritic
- gocyclo
- gofmt
- gofumpt
- goimports
- godox
- govet
- gosec
- gosimple
- importas
- ineffassign
- loggercheck
- misspell
- nakedret
- nilerr
- predeclared
- promlinter
- revive
- staticcheck
- unconvert
- unused
- wastedassign
- whitespace
linters-settings:
gci:
sections:
- standard
- default
- prefix(github.com/cloudbase/garm)
goimports:
local-prefixes: github.com/cloudbase/garm
gosec:
excludes:
- G115

27
.mockery.yaml Normal file
View file

@ -0,0 +1,27 @@
with-expecter: true
dir: "mocks"
mockname: "{{ .InterfaceName }}"
outpkg: "mocks"
filename: "{{ .InterfaceName }}.go"
# V3 compatibility settings
resolve-type-alias: false
disable-version-string: true
issue-845-fix: true
packages:
# Database store interfaces
github.com/cloudbase/garm/database/common:
interfaces:
Store:
config:
dir: "{{ .InterfaceDir }}/mocks"
# Runner interfaces
github.com/cloudbase/garm/runner:
interfaces:
PoolManagerController:
config:
dir: "{{ .InterfaceDir }}/mocks"
# Runner common interfaces (generate all interfaces in this package)
github.com/cloudbase/garm/runner/common:
config:
dir: "{{ .InterfaceDir }}/mocks"
all: true

View file

@ -1,11 +1,77 @@
FROM docker.io/golang:alpine FROM docker.io/golang:alpine AS builder
ARG GARM_REF
WORKDIR /root LABEL stage=builder
USER root
RUN apk add musl-dev gcc libtool m4 autoconf g++ make libblkid util-linux-dev git linux-headers mingw-w64-gcc RUN apk add --no-cache musl-dev gcc libtool m4 autoconf g++ make libblkid util-linux-dev git linux-headers upx curl jq
RUN git config --global --add safe.directory /build && git config --global --add advice.detachedHead false
RUN echo ${GARM_REF}
ADD ./scripts/build-static.sh /build-static.sh ADD . /build/garm
RUN chmod +x /build-static.sh
CMD ["/bin/sh"] RUN git -C /build/garm checkout ${GARM_REF}
RUN cd /build/garm \
&& go build -o /bin/garm \
-tags osusergo,netgo,sqlite_omit_load_extension \
-ldflags "-linkmode external -extldflags '-static' -s -w -X github.com/cloudbase/garm/util/appdefaults.Version=$(git describe --tags --match='v[0-9]*' --dirty --always)" \
/build/garm/cmd/garm && upx /bin/garm
RUN cd /build/garm/cmd/garm-cli \
&& go build -o /bin/garm-cli \
-tags osusergo,netgo,sqlite_omit_load_extension \
-ldflags "-linkmode external -extldflags '-static' -s -w -X github.com/cloudbase/garm/util/appdefaults.Version=$(git describe --tags --match='v[0-9]*' --dirty --always)" \
. && upx /bin/garm-cli
RUN set -ex; \
mkdir -p /opt/garm/providers.d; \
for repo in \
cloudbase/garm-provider-azure \
cloudbase/garm-provider-openstack \
cloudbase/garm-provider-lxd \
cloudbase/garm-provider-incus \
cloudbase/garm-provider-aws \
cloudbase/garm-provider-gcp \
cloudbase/garm-provider-equinix \
flatcar/garm-provider-linode \
mercedes-benz/garm-provider-k8s; \
do \
export PROVIDER_NAME="$(basename $repo)"; \
export PROVIDER_SUBDIR=""; \
if [ "$GARM_REF" == "main" ]; then \
export PROVIDER_REF="main"; \
else \
export PROVIDER_REF="$(curl -s -L https://api.github.com/repos/$repo/releases/latest | jq -r '.tag_name')"; \
fi; \
git clone --branch "$PROVIDER_REF" "https://github.com/$repo" "/build/$PROVIDER_NAME"; \
case $PROVIDER_NAME in \
"garm-provider-k8s") \
export PROVIDER_SUBDIR="cmd/garm-provider-k8s"; \
export PROVIDER_LDFLAGS="-linkmode external -extldflags \"-static\" -s -w"; \
;; \
"garm-provider-linode") \
export PROVIDER_LDFLAGS="-linkmode external -extldflags \"-static\" -s -w"; \
;; \
*) \
export PROVIDER_VERSION=$(git -C /build/$PROVIDER_NAME describe --tags --match='v[0-9]*' --dirty --always); \
export PROVIDER_LDFLAGS="-linkmode external -extldflags \"-static\" -s -w -X main.Version=$PROVIDER_VERSION"; \
;; \
esac; \
cd "/build/$PROVIDER_NAME/$PROVIDER_SUBDIR" \
&& go build -ldflags="$PROVIDER_LDFLAGS" -o /opt/garm/providers.d/$PROVIDER_NAME . \
&& upx /opt/garm/providers.d/$PROVIDER_NAME; \
done
FROM busybox
COPY --from=builder /bin/garm /bin/garm
COPY --from=builder /bin/garm-cli /bin/garm-cli
COPY --from=builder /opt/garm/providers.d/garm-provider-openstack /opt/garm/providers.d/garm-provider-openstack
COPY --from=builder /opt/garm/providers.d/garm-provider-lxd /opt/garm/providers.d/garm-provider-lxd
COPY --from=builder /opt/garm/providers.d/garm-provider-incus /opt/garm/providers.d/garm-provider-incus
COPY --from=builder /opt/garm/providers.d/garm-provider-azure /opt/garm/providers.d/garm-provider-azure
COPY --from=builder /opt/garm/providers.d/garm-provider-aws /opt/garm/providers.d/garm-provider-aws
COPY --from=builder /opt/garm/providers.d/garm-provider-gcp /opt/garm/providers.d/garm-provider-gcp
COPY --from=builder /opt/garm/providers.d/garm-provider-equinix /opt/garm/providers.d/garm-provider-equinix
COPY --from=builder /opt/garm/providers.d/garm-provider-k8s /opt/garm/providers.d/garm-provider-k8s
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/bin/garm", "-config", "/etc/garm/config.toml"]

17
Dockerfile.build-static Normal file
View file

@ -0,0 +1,17 @@
FROM docker.io/golang:alpine
WORKDIR /root
USER root
RUN apk add musl-dev gcc libtool m4 autoconf g++ make libblkid util-linux-dev git linux-headers mingw-w64-gcc
RUN wget http://musl.cc/aarch64-linux-musl-cross.tgz -O /tmp/aarch64-linux-musl-cross.tgz && \
tar --strip-components=1 -C /usr/local -xzf /tmp/aarch64-linux-musl-cross.tgz && \
rm /tmp/aarch64-linux-musl-cross.tgz
ADD ./scripts/build-static.sh /build-static.sh
RUN chmod +x /build-static.sh
ADD . /build/garm
CMD ["/bin/sh"]

136
Makefile
View file

@ -1,53 +1,139 @@
SHELL := bash SHELL := /bin/bash
export SHELLOPTS:=$(if $(SHELLOPTS),$(SHELLOPTS):)pipefail:errexit
.ONESHELL:
GEN_PASSWORD=$(shell (/usr/bin/apg -n1 -m32))
IMAGE_TAG = garm-build IMAGE_TAG = garm-build
USER_ID=$(shell ((docker --version | grep -q podman) && echo "0" || id -u)) IMAGE_BUILDER=$(shell (which docker || which podman))
USER_GROUP=$(shell ((docker --version | grep -q podman) && echo "0" || id -g)) IS_PODMAN=$(shell (($(IMAGE_BUILDER) --version | grep -q podman) && echo "yes" || echo "no"))
USER_ID=$(if $(filter yes,$(IS_PODMAN)),0,$(shell id -u))
USER_GROUP=$(if $(filter yes,$(IS_PODMAN)),0,$(shell id -g))
ROOTDIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) ROOTDIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
GOPATH ?= $(shell go env GOPATH) GOPATH ?= $(shell go env GOPATH)
VERSION ?= $(shell git describe --tags --match='v[0-9]*' --dirty --always) VERSION ?= $(shell git describe --tags --match='v[0-9]*' --dirty --always)
GARM_REF ?= $(shell git rev-parse --abbrev-ref HEAD)
GO ?= go GO ?= go
export GARM_PASSWORD ?= ${GEN_PASSWORD}
export REPO_WEBHOOK_SECRET = ${GEN_PASSWORD}
export ORG_WEBHOOK_SECRET = ${GEN_PASSWORD}
export CREDENTIALS_NAME ?= test-garm-creds
export WORKFLOW_FILE_NAME ?= test.yml
export GARM_ADMIN_USERNAME ?= admin
ifeq ($(IS_PODMAN),yes)
EXTRA_ARGS := -v /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt
endif
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
default: build default: build
.PHONY : build-static test install-lint-deps lint go-test fmt fmtcheck verify-vendor verify ##@ Build
build-static:
@echo Building garm
docker build --tag $(IMAGE_TAG) .
docker run --rm -e USER_ID=$(USER_ID) -e USER_GROUP=$(USER_GROUP) -v $(PWD):/build/garm:z $(IMAGE_TAG) /build-static.sh
@echo Binaries are available in $(PWD)/bin
build: .PHONY : build-static test install-lint-deps lint go-test fmt fmtcheck verify-vendor verify create-release-files release
build-static: ## Build garm statically
@echo Building garm
$(IMAGE_BUILDER) build $(EXTRA_ARGS) --tag $(IMAGE_TAG) -f Dockerfile.build-static .
mkdir -p build
$(IMAGE_BUILDER) run --rm -e USER_ID=$(USER_ID) -e GARM_REF=$(GARM_REF) -e USER_GROUP=$(USER_GROUP) -v $(PWD)/build:/build/output:z $(IMAGE_TAG) /build-static.sh
@echo Binaries are available in $(PWD)/build
clean: ## Clean up build artifacts
@rm -rf ./bin ./build ./release
.PHONY: build
build: ## Build garm
@echo Building garm ${VERSION} @echo Building garm ${VERSION}
$(shell mkdir -p ./bin) $(shell mkdir -p ./bin)
@$(GO) build -ldflags "-s -w -X main.Version=${VERSION}" -tags osusergo,netgo,sqlite_omit_load_extension -o bin/garm ./cmd/garm @$(GO) build -ldflags "-s -w -X github.com/cloudbase/garm/util/appdefaults.Version=${VERSION}" -tags osusergo,netgo,sqlite_omit_load_extension -o bin/garm ./cmd/garm
@$(GO) build -ldflags "-s -w -X github.com/cloudbase/garm/cmd/garm-cli/cmd.Version=${VERSION}" -tags osusergo,netgo,sqlite_omit_load_extension -o bin/garm-cli ./cmd/garm-cli @$(GO) build -ldflags "-s -w -X github.com/cloudbase/garm/util/appdefaults.Version=${VERSION}" -tags osusergo,netgo,sqlite_omit_load_extension -o bin/garm-cli ./cmd/garm-cli
@echo Binaries are available in $(PWD)/bin @echo Binaries are available in $(PWD)/bin
test: verify go-test .PHONY: build-webui
build-webui:
@echo Building GARM web ui
./build-webapp.sh
rm -rf webapp/assets/_app
cp -r webapp/build/* webapp/assets/
install-lint-deps: .PHONY: generate
@$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest generate: ## Run go generate after checking required tools are in PATH
@echo Checking required tools...
@which openapi-generator-cli > /dev/null || (echo "Error: openapi-generator-cli not found in PATH" && exit 1)
@echo Running go generate
@$(GO) generate ./...
lint: test: verify go-test ## Run tests
@golangci-lint run --timeout=8m --build-tags testing
go-test: ##@ Release
@$(GO) test -race -mod=vendor -tags testing -v $(TEST_ARGS) -timeout=15m -parallel=4 -count=1 ./... create-release-files:
./scripts/make-release.sh
fmt: release: build-static create-release-files ## Create a release
@$(GO) fmt $$(go list ./...)
fmtcheck: ##@ Lint / Verify
@gofmt -l -s $$(go list ./... | sed 's|github.com/cloudbase/garm/||g') | grep ".*\.go"; if [ "$$?" -eq 0 ]; then echo "gofmt check failed; please run gofmt -w -s"; exit 1;fi .PHONY: lint
lint: golangci-lint $(GOLANGCI_LINT) ## Run linting.
$(GOLANGCI_LINT) run -v --build-tags=testing,integration $(GOLANGCI_LINT_EXTRA_ARGS)
.PHONY: lint-fix
lint-fix: golangci-lint $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linte
GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint
verify-vendor: ## verify if all the go.mod/go.sum files are up-to-date verify-vendor: ## verify if all the go.mod/go.sum files are up-to-date
$(eval TMPDIR := $(shell mktemp -d)) $(eval TMPDIR := $(shell mktemp -d))
@cp -R ${ROOTDIR} ${TMPDIR} @cp -R ${ROOTDIR} ${TMPDIR}/.
@(cd ${TMPDIR}/garm && ${GO} mod tidy) @(cd ${TMPDIR}/garm && ${GO} mod tidy)
@diff -r -u -q ${ROOTDIR} ${TMPDIR}/garm >/dev/null 2>&1; if [ "$$?" -ne 0 ];then echo "please run: go mod tidy && go mod vendor"; exit 1; fi @diff -r -u -q ${ROOTDIR} ${TMPDIR}/garm >/dev/null 2>&1; if [ "$$?" -ne 0 ];then echo "please run: go mod tidy && go mod vendor"; exit 1; fi
@rm -rf ${TMPDIR} @rm -rf ${TMPDIR}
verify: verify-vendor lint fmtcheck verify: verify-vendor lint fmtcheck ## Run all verify-* targets
integration: build ## Run integration tests
function cleanup {
if [ -e "$$GITHUB_ENV" ];then
source $$GITHUB_ENV
fi
./test/integration/scripts/taredown_garm.sh
$(GO) run ./test/integration/gh_cleanup/main.go
}
trap cleanup EXIT
@./test/integration/scripts/setup-garm.sh
@$(GO) test -v ./test/integration/. -timeout=30m -tags=integration
##@ Development
go-test: ## Run tests
@$(GO) test -race -mod=vendor -tags testing -v $(TEST_ARGS) -timeout=15m -parallel=4 -count=1 ./...
fmt: ## Run go fmt against code.
@$(GO) fmt $$(go list ./...)
webui-test:
(cd webapp && npm install)
(cd webapp && npm run test:run)
##@ Build Dependencies
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)
## Tool Binaries
GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint
## Tool Versions
GOLANGCI_LINT_VERSION ?= v1.64.8
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. If wrong version is installed, it will be overwritten.
$(GOLANGCI_LINT): $(LOCALBIN)
test -s $(LOCALBIN)/golangci-lint && $(LOCALBIN)/golangci-lint --version | grep -q $(GOLANGCI_LINT_VERSION) || \
GOBIN=$(LOCALBIN) go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)

183
README.md
View file

@ -1,14 +1,59 @@
# GitHub Actions Runner Manager (garm)
<p align="center">
<img src="doc/images/garm-light.svg#gh-light-mode-only" width="384px" alt="Light mode image" />
<img src="doc/images/garm-dark.svg#gh-dark-mode-only" width="384px" alt="Dark mode image" />
</p>
# GitHub Actions Runner Manager (GARM)
[![Go Tests](https://github.com/cloudbase/garm/actions/workflows/go-tests.yml/badge.svg)](https://github.com/cloudbase/garm/actions/workflows/go-tests.yml) [![Go Tests](https://github.com/cloudbase/garm/actions/workflows/go-tests.yml/badge.svg)](https://github.com/cloudbase/garm/actions/workflows/go-tests.yml)
Welcome to garm! <!-- TOC -->
Garm enables you to create and automatically maintain pools of [self-hosted GitHub runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners), with autoscaling that can be used inside your github workflow runs. - [GitHub Actions Runner Manager GARM](#github-actions-runner-manager-garm)
- [About GARM](#about-garm)
- [Join us on slack](#join-us-on-slack)
- [Installing](#installing)
- [Quickstart](#quickstart)
- [Installing on Kubernetes](#installing-on-kubernetes)
- [Configuring GARM for GHES](#configuring-garm-for-ghes)
- [Configuring GARM for Gitea](#configuring-garm-for-gitea)
- [Enabling the web UI](#enabling-the-web-ui)
- [Using GARM](#using-garm)
- [Supported providers](#supported-providers)
- [Installing external providers](#installing-external-providers)
- [Optimizing your runners](#optimizing-your-runners)
- [Write your own provider](#write-your-own-provider)
The goal of ```garm``` is to be simple to set up, simple to configure and simple to use. It is a single binary that can run on any GNU/Linux machine without any other requirements other than the providers it creates the runners in. It is intended to be easy to deploy in any environment and can create runners in any system you can write a provider for. There is no complicated setup process and no extremely complex concepts to understand. Once set up, it's meant to stay out of your way. <!-- /TOC -->
Garm supports creating pools on either GitHub itself or on your own deployment of [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@3.5/admin/overview/about-github-enterprise-server). For instructions on how to use ```garm``` with GHE, see the [credentials](/doc/github_credentials.md) section of the documentation. ## About GARM
Welcome to GARM!
GARM enables you to create and automatically maintain pools of self-hosted runners in both [Github](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners) and [Gitea](https://github.com/go-gitea/gitea/) with auto-scaling that can be used inside your workflow runs.
The goal of ```GARM``` is to be simple to set up, simple to configure and simple to use. The server itself is a single binary that can run on any GNU/Linux machine without any other requirements other than the providers you want to enable in your setup. It is intended to be easy to deploy in any environment and can create runners in virtually any system you can write a provider for (if one does not alreay exist). There is no complicated setup process and no extremely complex concepts to understand. Once set up, it's meant to stay out of your way.
Through the use of providers, `GARM` can create runners in a variety of environments using the same `GARM` instance. Whether you want to create runners in your OpenStack cloud, your Azure cloud or your Kubernetes cluster, that is easily achieved by installing the appropriate providers, configuring them in `GARM` and creating pools that use them. You can create zero-runner pools for instances with high costs (large VMs, GPU enabled instances, etc) and have them spin up on demand, or you can create large pools of eagerly created k8s backed runners that can be used for your CI/CD pipelines at a moment's notice. You can mix them up and create pools in any combination of providers or resource allocations you want.
GARM supports two modes of operation:
* Pools
* Scale sets
Here is a brief architectural diagram of how pools work and how GARM reacts to workflows triggered in GitHub (click the image to see a larger version):
![GARM architecture diagram](/doc/images/garm-light.diagram.svg?raw=true#gh-light-mode-only)
![GARM architecture diagram](/doc/images/garm-dark.diagram.svg?raw=true#gh-dark-mode-only)
**Scale sets** work differently. While pools (as they are defined in GARM) rely on webhooks to know when a job was started and GARM needs to internally make the right decission in terms of which pool should handle that runner, scale sets have a lot of the scheduling and decission making logic done in GitHub itself.
> [!IMPORTANT]
> The README and documentation in the `main` branch are relevant to the not yet released code that is present in `main`. Following the documentation from the `main` branch for a stable release of GARM, may lead to errors. To view the documentation for the latest stable release, please switch to the appropriate tag. For information about setting up `v0.1.6`, please refer to the [v0.1.6 tag](https://github.com/cloudbase/garm/tree/v0.1.6).
> [!CAUTION]
> The `main` branch holds the latest code and is not guaranteed to be stable. If you are looking for a stable release, please check the releases page. If you plan to use the `main` branch, please do so on a new instance. Do not upgrade from a stable release to `main`.
## Join us on slack ## Join us on slack
@ -18,120 +63,68 @@ Whether you're running into issues or just want to drop by and say "hi", feel fr
## Installing ## Installing
## Build from source ### Quickstart
You need to have Go installed, then run: Check out the [quickstart](/doc/quickstart.md) document for instructions on how to install ```GARM```. If you'd like to build from source, check out the [building from source](/doc/building_from_source.md) document.
```bash ### Installing on Kubernetes
git clone https://github.com/cloudbase/garm
cd garm
go install ./...
```
You should now have both ```garm``` and ```garm-cli``` in your ```$GOPATH/bin``` folder. Thanks to the efforts of the amazing folks at [@mercedes-benz](https://github.com/mercedes-benz/), GARM can now be integrated into k8s via their operator. Check out the [GARM operator](https://github.com/mercedes-benz/garm-operator/) for more details.
If you have docker/podman installed, you can also build statically linked binaries by running: ## Configuring GARM for GHES
```bash GARM supports creating pools and scale sets in either GitHub itself or in your own deployment of [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@3.10/admin/overview/about-github-enterprise-server). For instructions on how to use ```GARM``` with GHE, see the [credentials](/doc/github_credentials.md) section of the documentation.
make build-static
```
The ```garm``` and ```garm-cli``` binaries will be built and copied to the ```bin/``` folder in your current working directory. ## Configuring GARM for Gitea
## Install the service GARM now has support for Gitea (>=1.24.0). For information on getting started with Gitea, see the [Gitea quickstart](/doc/gitea.md) document.
Add a new system user: ## Enabling the web UI
```bash GARM now ships with a single page application. To enable it, add the following to your GARM config:
useradd --shell /usr/bin/false \
--system \
--groups lxd \
--no-create-home garm
```
The ```lxd``` group is only needed if you have a local LXD install and want to connect to the unix socket to use it. If you're connecting to a remote LXD server over TCP, you can skip adding the ```garm``` user to the ```lxd``` group. ```toml
[apiserver.webui]
enable = true
```
Copy the binary to somewhere in the system ```$PATH```: Check the [README.md](/webapp/README.md) file for details on the web UI.
```bash ## Using GARM
sudo cp $(go env GOPATH)/bin/garm /usr/local/bin/garm
```
Or if you built garm using ```make```: GARM is designed with simplicity in mind. At least we try to keep it as simple as possible. We're aware that adding a new tool in your workflow can be painful, especially when you already have to deal with so many. The cognitive load for OPS has reached a level where it feels overwhelming at times to even wrap your head around a new tool. As such, we believe that tools should be simple, should take no more than a few hours to understand and set up and if you absolutely need to interact with the tool, it should be as intuitive as possible. Although we try our best to make this happen, we're aware that GARM has some rough edges, especially for new users. If you encounter issues or feel like the setup process was too complicated, please let us know. We're always looking to improve the user experience.
```bash We've written a short introduction into some of the commands that GARM has and some of the concepts involved in setting up GARM, managing runners and how GitHub does some of the things it does.
sudo cp ./bin/garm /usr/local/bin/garm
```
Create the config folder: [You can find it here](/doc/using_garm.md).
```bash Please, feel free to [open an issue](https://github.com/cloudbase/garm/issues/new) if you find the documentation lacking and would like more info. Sometimes we forget the challenges that new users face as we're so close to the code and how it works. Any feedback is welcome and we're always looking to improve the documentation.
sudo mkdir -p /etc/garm
```
Copy the config template: ## Supported providers
```bash GARM uses providers to create runners in a particular IaaS. The providers are external executables that GARM calls into to create runners. Before you can create runners, you'll need to install at least one provider.
sudo cp ./testdata/config.toml /etc/garm/
```
Copy the external provider (optional): ### Installing external providers
```bash External providers are binaries that GARM calls into to create runners in a particular IaaS. There are several external providers available:
sudo cp -a ./contrib/providers.d /etc/garm/
```
Copy the systemd service file: * [Akamai/Linode](https://github.com/flatcar/garm-provider-linode) - Experimental
* [Amazon EC2](https://github.com/cloudbase/garm-provider-aws)
* [Azure](https://github.com/cloudbase/garm-provider-azure)
* [Equinix Metal](https://github.com/cloudbase/garm-provider-equinix)
* [Google Cloud Platform (GCP)](https://github.com/cloudbase/garm-provider-gcp)
* [Incus](https://github.com/cloudbase/garm-provider-incus)
* [Kubernetes](https://github.com/mercedes-benz/garm-provider-k8s) - Thanks to the amazing folks at @mercedes-benz for sharing their awesome provider!
* [LXD](https://github.com/cloudbase/garm-provider-lxd)
* [OpenStack](https://github.com/cloudbase/garm-provider-openstack)
* [Oracle Cloud Infrastructure (OCI)](https://github.com/cloudbase/garm-provider-oci)
```bash Follow the instructions in the README of each provider to install them.
sudo cp ./contrib/garm.service /etc/systemd/system/
```
Change permissions on config folder: ## Optimizing your runners
```bash If you would like to optimize the startup time of new instance, take a look at the [performance considerations](/doc/performance_considerations.md) page.
sudo chown -R garm:garm /etc/garm
sudo chmod 750 -R /etc/garm
```
Enable the service:
```bash
sudo systemctl enable garm
```
Customize the config in ```/etc/garm/config.toml```, and start the service:
```bash
sudo systemctl start garm
```
## Configuration
The ```garm``` configuration is a simple ```toml```. A sample of the config file can be found in [the testdata folder](/testdata/config.toml).
There are 3 major sections of the config that require your attention:
* [Github credentials section](/doc/github_credentials.md)
* [Providers section](/doc/providers.md)
* [The database section](/doc/database.md)
Once you've configured your database, providers and github credentials, you'll need to configure your [webhooks and the callback_url](/doc/webhooks_and_callbacks.md).
At this point, you should be done. Have a look at the [running garm document](/doc/running_garm.md) for usage instructions and available features.
If you would like to use ```garm``` with a different IaaS than the ones already available, have a loot at the [writing an external provider](/doc/external_provider.md) page.
## Security considerations
Garm does not apply any ACLs of any kind to the instances it creates. That task remains in the responsibility of the user. [Here is a guide for creating ACLs in LXD](https://linuxcontainers.org/lxd/docs/master/howto/network_acls/). You can of course use ```iptables``` or ```nftables``` to create any rules you wish. I recommend you create a separate isolated lxd bridge for runners, and secure it using ACLs/iptables/nftables.
You must make sure that the code that runs as part of the workflows is trusted, and if that cannot be done, you must make sure that any malicious code that will be pulled in by the actions and run as part of a workload, is as contained as possible. There is a nice article about [securing your workflow runs here](https://blog.gitguardian.com/github-actions-security-cheat-sheet/).
## Write your own provider ## Write your own provider
The providers are interfaces between ```garm``` and a particular IaaS in which we spin up GitHub Runners. These providers can be either **native** or **external**. The **native** providers are written in ```Go```, and must implement [the interface defined here](https://github.com/cloudbase/garm/blob/main/runner/common/provider.go#L22-L39). **External** providers can be written in any language, as they are in the form of an external executable that ```garm``` calls into. The providers are interfaces between ```GARM``` and a particular IaaS in which we spin up GitHub Runners. **External** providers can be written in any language, as they are in the form of an external executable that ```GARM``` calls into. Please see the [Writing an external provider](/doc/external_provider.md) document for details. Also, feel free to inspect the two available sample external providers in this repository.
There is currently one **native** provider for [LXD](https://linuxcontainers.org/lxd/) and two **external** providers for [Openstack and Azure](/contrib/providers.d/).
If you want to write your own provider, you can choose to write a native one, or implement an **external** one. The easiest one to write is probably an **external** provider. Please see the [Writing an external provider](/doc/external_provider.md) document for details. Also, feel free to inspect the two available external providers in this repository.

View file

@ -15,26 +15,60 @@
package controllers package controllers
import ( import (
"context"
"encoding/json" "encoding/json"
"errors"
"fmt"
"io" "io"
"log" "log/slog"
"net/http" "net/http"
"net/url"
"strings" "strings"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/apiserver/params" "github.com/cloudbase/garm/apiserver/params"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
gErrors "github.com/cloudbase/garm/errors" "github.com/cloudbase/garm/config"
"github.com/cloudbase/garm/metrics" "github.com/cloudbase/garm/metrics"
runnerParams "github.com/cloudbase/garm/params" runnerParams "github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner" "github.com/cloudbase/garm/runner" //nolint:typecheck
"github.com/cloudbase/garm/util" garmUtil "github.com/cloudbase/garm/util"
wsWriter "github.com/cloudbase/garm/websocket" wsWriter "github.com/cloudbase/garm/websocket"
"github.com/cloudbase/garm/workers/websocket/events"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
) )
func NewAPIController(r *runner.Runner, authenticator *auth.Authenticator, hub *wsWriter.Hub) (*APIController, error) { func NewAPIController(r *runner.Runner, authenticator *auth.Authenticator, hub *wsWriter.Hub, apiCfg config.APIServer) (*APIController, error) {
controllerInfo, err := r.GetControllerInfo(auth.GetAdminContext(context.Background()))
if err != nil {
return nil, fmt.Errorf("failed to get controller info: %w", err)
}
var checkOrigin func(r *http.Request) bool
if len(apiCfg.CORSOrigins) > 0 {
checkOrigin = func(r *http.Request) bool {
origin := r.Header["Origin"]
if len(origin) == 0 {
return true
}
u, err := url.Parse(origin[0])
if err != nil {
return false
}
for _, val := range apiCfg.CORSOrigins {
corsVal, err := url.Parse(val)
if err != nil {
continue
}
if garmUtil.ASCIIEqualFold(u.Host, corsVal.Host) {
return true
}
}
return false
}
}
return &APIController{ return &APIController{
r: r, r: r,
auth: authenticator, auth: authenticator,
@ -42,37 +76,38 @@ func NewAPIController(r *runner.Runner, authenticator *auth.Authenticator, hub *
upgrader: websocket.Upgrader{ upgrader: websocket.Upgrader{
ReadBufferSize: 1024, ReadBufferSize: 1024,
WriteBufferSize: 16384, WriteBufferSize: 16384,
CheckOrigin: checkOrigin,
}, },
controllerID: controllerInfo.ControllerID.String(),
}, nil }, nil
} }
type APIController struct { type APIController struct {
r *runner.Runner r *runner.Runner
auth *auth.Authenticator auth *auth.Authenticator
hub *wsWriter.Hub hub *wsWriter.Hub
upgrader websocket.Upgrader upgrader websocket.Upgrader
controllerID string
} }
func handleError(w http.ResponseWriter, err error) { func handleError(ctx context.Context, w http.ResponseWriter, err error) {
w.Header().Add("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
origErr := errors.Cause(err)
apiErr := params.APIErrorResponse{ apiErr := params.APIErrorResponse{
Details: origErr.Error(), Details: err.Error(),
} }
switch {
switch origErr.(type) { case errors.Is(err, gErrors.ErrNotFound):
case *gErrors.NotFoundError:
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
apiErr.Error = "Not Found" apiErr.Error = "Not Found"
case *gErrors.UnauthorizedError: case errors.Is(err, gErrors.ErrUnauthorized):
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
apiErr.Error = "Not Authorized" apiErr.Error = "Not Authorized"
// Don't include details on 401 errors. // Don't include details on 401 errors.
apiErr.Details = "" apiErr.Details = ""
case *gErrors.BadRequestError: case errors.Is(err, gErrors.ErrBadRequest):
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
apiErr.Error = "Bad Request" apiErr.Error = "Bad Request"
case *gErrors.DuplicateUserError, *gErrors.ConflictError: case errors.Is(err, gErrors.ErrDuplicateEntity), errors.Is(err, &gErrors.ConflictError{}):
w.WriteHeader(http.StatusConflict) w.WriteHeader(http.StatusConflict)
apiErr.Error = "Conflict" apiErr.Error = "Conflict"
default: default:
@ -83,72 +118,122 @@ func handleError(w http.ResponseWriter, err error) {
} }
if err := json.NewEncoder(w).Encode(apiErr); err != nil { if err := json.NewEncoder(w).Encode(apiErr); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
func (a *APIController) webhookMetricLabelValues(valid, reason string) []string { func (a *APIController) handleWorkflowJobEvent(ctx context.Context, w http.ResponseWriter, r *http.Request) {
controllerInfo, err := a.r.GetControllerInfo(auth.GetAdminContext())
if err != nil {
log.Printf("failed to get controller info: %s", err)
// If labels are empty, not attempt will be made to record webhook.
return []string{}
}
return []string{
valid, reason,
controllerInfo.Hostname, controllerInfo.ControllerID.String(),
}
}
func (a *APIController) handleWorkflowJobEvent(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close() defer r.Body.Close()
body, err := io.ReadAll(r.Body) body, err := io.ReadAll(r.Body)
if err != nil { if err != nil {
handleError(w, gErrors.NewBadRequestError("invalid post body: %s", err)) handleError(ctx, w, gErrors.NewBadRequestError("invalid post body: %s", err))
return return
} }
signature := r.Header.Get("X-Hub-Signature-256") signature := r.Header.Get("X-Hub-Signature-256")
hookType := r.Header.Get("X-Github-Hook-Installation-Target-Type") hookType := r.Header.Get("X-Github-Hook-Installation-Target-Type")
giteaTargetType := r.Header.Get("X-Gitea-Hook-Installation-Target-Type")
var labelValues []string forgeType := runnerParams.GithubEndpointType
defer func() { if giteaTargetType != "" {
if len(labelValues) == 0 { forgeType = runnerParams.GiteaEndpointType
hookType = giteaTargetType
}
if err := a.r.DispatchWorkflowJob(hookType, signature, forgeType, body); err != nil {
switch {
case errors.Is(err, gErrors.ErrNotFound):
metrics.WebhooksReceived.WithLabelValues(
"false", // label: valid
"owner_unknown", // label: reason
).Inc()
slog.With(slog.Any("error", err)).ErrorContext(ctx, "got not found error from DispatchWorkflowJob. webhook not meant for us?")
return return
} case strings.Contains(err.Error(), "signature"):
if err := metrics.RecordWebhookWithLabels(labelValues...); err != nil { // nolint:golangci-lint,godox TODO: check error type
log.Printf("failed to record metric: %s", err) metrics.WebhooksReceived.WithLabelValues(
} "false", // label: valid
}() "signature_invalid", // label: reason
).Inc()
if err := a.r.DispatchWorkflowJob(hookType, signature, body); err != nil { default:
if errors.Is(err, gErrors.ErrNotFound) { metrics.WebhooksReceived.WithLabelValues(
labelValues = a.webhookMetricLabelValues("false", "owner_unknown") "false", // label: valid
log.Printf("got not found error from DispatchWorkflowJob. webhook not meant for us?: %q", err) "unknown", // label: reason
return ).Inc()
} else if strings.Contains(err.Error(), "signature") { // TODO: check error type
labelValues = a.webhookMetricLabelValues("false", "signature_invalid")
} else {
labelValues = a.webhookMetricLabelValues("false", "unknown")
} }
handleError(w, err) handleError(ctx, w, err)
return return
} }
labelValues = a.webhookMetricLabelValues("true", "") metrics.WebhooksReceived.WithLabelValues(
"true", // label: valid
"", // label: reason
).Inc()
} }
func (a *APIController) CatchAll(w http.ResponseWriter, r *http.Request) { func (a *APIController) WebhookHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
controllerID, ok := vars["controllerID"]
// If the webhook URL includes a controller ID, we validate that it's meant for us. We still
// support bare webhook URLs, which are tipically configured manually by the user.
// The controllerID suffixed webhook URL is useful when configuring the webhook for an entity
// via garm. We cannot tag a webhook URL on github, so there is no way to determine ownership.
// Using a controllerID suffix is a simple way to denote ownership.
if ok && controllerID != a.controllerID {
slog.InfoContext(ctx, "ignoring webhook meant for foreign controller", "req_controller_id", controllerID)
return
}
headers := r.Header.Clone() headers := r.Header.Clone()
event := runnerParams.Event(headers.Get("X-Github-Event")) event := runnerParams.Event(headers.Get("X-Github-Event"))
switch event { switch event {
case runnerParams.WorkflowJobEvent: case runnerParams.WorkflowJobEvent:
a.handleWorkflowJobEvent(w, r) a.handleWorkflowJobEvent(ctx, w, r)
case runnerParams.PingEvent:
// Ignore ping event. We may want to save the ping in the github entity table in the future.
default: default:
log.Printf("ignoring unknown event %s", util.SanitizeLogEntry(string(event))) slog.DebugContext(ctx, "ignoring unknown event", "gh_event", util.SanitizeLogEntry(string(event)))
}
}
func (a *APIController) EventsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if !auth.IsAdmin(ctx) {
w.WriteHeader(http.StatusForbidden)
if _, err := w.Write([]byte("events are available to admin users")); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return return
} }
conn, err := a.upgrader.Upgrade(w, r, nil)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "error upgrading to websockets")
return
}
defer conn.Close()
wsClient, err := wsWriter.NewClient(ctx, conn)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to create new client")
return
}
defer wsClient.Stop()
eventHandler, err := events.NewHandler(ctx, wsClient)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to create new event handler")
return
}
if err := eventHandler.Start(); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to start event handler")
return
}
<-eventHandler.Done()
} }
func (a *APIController) WSHandler(writer http.ResponseWriter, req *http.Request) { func (a *APIController) WSHandler(writer http.ResponseWriter, req *http.Request) {
@ -156,153 +241,267 @@ func (a *APIController) WSHandler(writer http.ResponseWriter, req *http.Request)
if !auth.IsAdmin(ctx) { if !auth.IsAdmin(ctx) {
writer.WriteHeader(http.StatusForbidden) writer.WriteHeader(http.StatusForbidden)
if _, err := writer.Write([]byte("you need admin level access to view logs")); err != nil { if _, err := writer.Write([]byte("you need admin level access to view logs")); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
if a.hub == nil { if a.hub == nil {
handleError(writer, gErrors.NewBadRequestError("log streamer is disabled")) handleError(ctx, writer, gErrors.NewBadRequestError("log streamer is disabled"))
return return
} }
conn, err := a.upgrader.Upgrade(writer, req, nil) conn, err := a.upgrader.Upgrade(writer, req, nil)
if err != nil { if err != nil {
log.Printf("error upgrading to websockets: %v", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error upgrading to websockets")
return return
} }
defer conn.Close()
// TODO (gsamfira): Handle ExpiresAt. Right now, if a client uses client, err := wsWriter.NewClient(ctx, conn)
// a valid token to authenticate, and keeps the websocket connection
// open, it will allow that client to stream logs via websockets
// until the connection is broken. We need to forcefully disconnect
// the client once the token expires.
client, err := wsWriter.NewClient(conn, a.hub)
if err != nil { if err != nil {
log.Printf("failed to create new client: %v", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to create new client")
return return
} }
if err := a.hub.Register(client); err != nil { if err := a.hub.Register(client); err != nil {
log.Printf("failed to register new client: %v", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to register new client")
return return
} }
client.Go() defer a.hub.Unregister(client)
if err := client.Start(); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to start client")
return
}
<-client.Done()
slog.Info("client disconnected", "client_id", client.ID())
} }
// NotFoundHandler is returned when an invalid URL is acccessed // NotFoundHandler is returned when an invalid URL is acccessed
func (a *APIController) NotFoundHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) NotFoundHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
apiErr := params.APIErrorResponse{ apiErr := params.APIErrorResponse{
Details: "Resource not found", Details: "Resource not found",
Error: "Not found", Error: "Not found",
} }
w.WriteHeader(http.StatusNotFound)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound)
if err := json.NewEncoder(w).Encode(apiErr); err != nil { if err := json.NewEncoder(w).Encode(apiErr); err != nil {
log.Printf("failet to write response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failet to write response")
} }
} }
// swagger:route GET /metrics-token metrics-token GetMetricsToken
//
// Returns a JWT token that can be used to access the metrics endpoint.
//
// Responses:
// 200: JWTResponse
// 401: APIErrorResponse
func (a *APIController) MetricsTokenHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) MetricsTokenHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
if !auth.IsAdmin(ctx) { if !auth.IsAdmin(ctx) {
handleError(w, gErrors.ErrUnauthorized) handleError(ctx, w, gErrors.ErrUnauthorized)
return return
} }
token, err := a.auth.GetJWTMetricsToken(ctx) token, err := a.auth.GetJWTMetricsToken(ctx)
if err != nil { if err != nil {
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(runnerParams.JWTResponse{Token: token}) err = json.NewEncoder(w).Encode(runnerParams.JWTResponse{Token: token})
if err != nil { if err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route POST /auth/login login Login
//
// Logs in a user and returns a JWT token.
//
// Parameters:
// + name: Body
// description: Login information.
// type: PasswordLoginParams
// in: body
// required: true
//
// Responses:
// 200: JWTResponse
// 400: APIErrorResponse
//
// LoginHandler returns a jwt token // LoginHandler returns a jwt token
func (a *APIController) LoginHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) LoginHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var loginInfo runnerParams.PasswordLoginParams var loginInfo runnerParams.PasswordLoginParams
if err := json.NewDecoder(r.Body).Decode(&loginInfo); err != nil { if err := json.NewDecoder(r.Body).Decode(&loginInfo); err != nil {
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
if err := loginInfo.Validate(); err != nil { if err := loginInfo.Validate(); err != nil {
handleError(w, err) handleError(ctx, w, err)
return return
} }
ctx := r.Context()
ctx, err := a.auth.AuthenticateUser(ctx, loginInfo) ctx, err := a.auth.AuthenticateUser(ctx, loginInfo)
if err != nil { if err != nil {
handleError(w, err) handleError(ctx, w, err)
return return
} }
tokenString, err := a.auth.GetJWTToken(ctx) tokenString, err := a.auth.GetJWTToken(ctx)
if err != nil { if err != nil {
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(runnerParams.JWTResponse{Token: tokenString}); err != nil { if err := json.NewEncoder(w).Encode(runnerParams.JWTResponse{Token: tokenString}); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route POST /first-run first-run FirstRun
//
// Initialize the first run of the controller.
//
// Parameters:
// + name: Body
// description: Create a new user.
// type: NewUserParams
// in: body
// required: true
//
// Responses:
// 200: User
// 400: APIErrorResponse
func (a *APIController) FirstRunHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) FirstRunHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if a.auth.IsInitialized() { if a.auth.IsInitialized() {
err := gErrors.NewConflictError("already initialized") err := gErrors.NewConflictError("already initialized")
handleError(w, err) handleError(ctx, w, err)
return return
} }
ctx := r.Context()
var newUserParams runnerParams.NewUserParams var newUserParams runnerParams.NewUserParams
if err := json.NewDecoder(r.Body).Decode(&newUserParams); err != nil { if err := json.NewDecoder(r.Body).Decode(&newUserParams); err != nil {
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
newUser, err := a.auth.InitController(ctx, newUserParams) newUser, err := a.auth.InitController(ctx, newUserParams)
if err != nil { if err != nil {
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(newUser); err != nil { if err := json.NewEncoder(w).Encode(newUser); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
func (a *APIController) ListCredentials(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
creds, err := a.r.ListCredentials(ctx)
if err != nil {
handleError(w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(creds); err != nil {
log.Printf("failed to encode response: %q", err)
} }
} }
// swagger:route GET /providers providers ListProviders
//
// List all providers.
//
// Responses:
// 200: Providers
// 400: APIErrorResponse
func (a *APIController) ListProviders(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListProviders(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
providers, err := a.r.ListProviders(ctx) providers, err := a.r.ListProviders(ctx)
if err != nil { if err != nil {
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(providers); err != nil { if err := json.NewEncoder(w).Encode(providers); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /jobs jobs ListJobs
//
// List all jobs.
//
// Responses:
// 200: Jobs
// 400: APIErrorResponse
func (a *APIController) ListAllJobs(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
jobs, err := a.r.ListAllJobs(ctx)
if err != nil {
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(jobs); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /controller-info controllerInfo ControllerInfo
//
// Get controller info.
//
// Responses:
// 200: ControllerInfo
// 409: APIErrorResponse
func (a *APIController) ControllerInfoHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
info, err := a.r.GetControllerInfo(ctx)
if err != nil {
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(info); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route PUT /controller controller UpdateController
//
// Update controller.
//
// Parameters:
// + name: Body
// description: Parameters used when updating the controller.
// type: UpdateControllerParams
// in: body
// required: true
//
// Responses:
// 200: ControllerInfo
// 400: APIErrorResponse
func (a *APIController) UpdateControllerHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var updateParams runnerParams.UpdateControllerParams
if err := json.NewDecoder(r.Body).Decode(&updateParams); err != nil {
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if err := updateParams.Validate(); err != nil {
handleError(ctx, w, err)
return
}
info, err := a.r.UpdateController(ctx, updateParams)
if err != nil {
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(info); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }

View file

@ -16,54 +16,106 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"log" "log/slog"
"net/http" "net/http"
"github.com/cloudbase/garm/apiserver/params"
gErrors "github.com/cloudbase/garm/errors"
runnerParams "github.com/cloudbase/garm/params"
"github.com/gorilla/mux" "github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
) )
// swagger:route POST /enterprises enterprises CreateEnterprise
//
// Create enterprise with the given parameters.
//
// Parameters:
// + name: Body
// description: Parameters used to create the enterprise.
// type: CreateEnterpriseParams
// in: body
// required: true
//
// Responses:
// 200: Enterprise
// default: APIErrorResponse
func (a *APIController) CreateEnterpriseHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) CreateEnterpriseHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
var enterpriseData runnerParams.CreateEnterpriseParams var enterpriseData runnerParams.CreateEnterpriseParams
if err := json.NewDecoder(r.Body).Decode(&enterpriseData); err != nil { if err := json.NewDecoder(r.Body).Decode(&enterpriseData); err != nil {
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
enterprise, err := a.r.CreateEnterprise(ctx, enterpriseData) enterprise, err := a.r.CreateEnterprise(ctx, enterpriseData)
if err != nil { if err != nil {
log.Printf("error creating enterprise: %+v", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating enterprise")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(enterprise); err != nil { if err := json.NewEncoder(w).Encode(enterprise); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /enterprises enterprises ListEnterprises
//
// List all enterprises.
//
// Parameters:
// + name: name
// description: Exact enterprise name to filter by
// type: string
// in: query
// required: false
//
// + name: endpoint
// description: Exact endpoint name to filter by
// type: string
// in: query
// required: false
//
// Responses:
// 200: Enterprises
// default: APIErrorResponse
func (a *APIController) ListEnterprisesHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListEnterprisesHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
enterprise, err := a.r.ListEnterprises(ctx) filter := runnerParams.EnterpriseFilter{
Name: r.URL.Query().Get("name"),
Endpoint: r.URL.Query().Get("endpoint"),
}
enterprise, err := a.r.ListEnterprises(ctx, filter)
if err != nil { if err != nil {
log.Printf("listing enterprise: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing enterprise")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(enterprise); err != nil { if err := json.NewEncoder(w).Encode(enterprise); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /enterprises/{enterpriseID} enterprises GetEnterprise
//
// Get enterprise by ID.
//
// Parameters:
// + name: enterpriseID
// description: The ID of the enterprise to fetch.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Enterprise
// default: APIErrorResponse
func (a *APIController) GetEnterpriseByIDHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) GetEnterpriseByIDHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -75,24 +127,37 @@ func (a *APIController) GetEnterpriseByIDHandler(w http.ResponseWriter, r *http.
Error: "Bad Request", Error: "Bad Request",
Details: "No enterprise ID specified", Details: "No enterprise ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
enterprise, err := a.r.GetEnterpriseByID(ctx, enterpriseID) enterprise, err := a.r.GetEnterpriseByID(ctx, enterpriseID)
if err != nil { if err != nil {
log.Printf("fetching enterprise: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "fetching enterprise")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(enterprise); err != nil { if err := json.NewEncoder(w).Encode(enterprise); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route DELETE /enterprises/{enterpriseID} enterprises DeleteEnterprise
//
// Delete enterprise by ID.
//
// Parameters:
// + name: enterpriseID
// description: ID of the enterprise to delete.
// type: string
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteEnterpriseHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) DeleteEnterpriseHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -104,22 +169,40 @@ func (a *APIController) DeleteEnterpriseHandler(w http.ResponseWriter, r *http.R
Error: "Bad Request", Error: "Bad Request",
Details: "No enterprise ID specified", Details: "No enterprise ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
if err := a.r.DeleteEnterprise(ctx, enterpriseID); err != nil { if err := a.r.DeleteEnterprise(ctx, enterpriseID); err != nil {
log.Printf("removing enterprise: %+v", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing enterprise")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route PUT /enterprises/{enterpriseID} enterprises UpdateEnterprise
//
// Update enterprise with the given parameters.
//
// Parameters:
// + name: enterpriseID
// description: The ID of the enterprise to update.
// type: string
// in: path
// required: true
// + name: Body
// description: Parameters used when updating the enterprise.
// type: UpdateEntityParams
// in: body
// required: true
//
// Responses:
// 200: Enterprise
// default: APIErrorResponse
func (a *APIController) UpdateEnterpriseHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) UpdateEnterpriseHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -131,30 +214,50 @@ func (a *APIController) UpdateEnterpriseHandler(w http.ResponseWriter, r *http.R
Error: "Bad Request", Error: "Bad Request",
Details: "No enterprise ID specified", Details: "No enterprise ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
var updatePayload runnerParams.UpdateRepositoryParams var updatePayload runnerParams.UpdateEntityParams
if err := json.NewDecoder(r.Body).Decode(&updatePayload); err != nil { if err := json.NewDecoder(r.Body).Decode(&updatePayload); err != nil {
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
enterprise, err := a.r.UpdateEnterprise(ctx, enterpriseID, updatePayload) enterprise, err := a.r.UpdateEnterprise(ctx, enterpriseID, updatePayload)
if err != nil { if err != nil {
log.Printf("error updating enterprise: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error updating enterprise: %s")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(enterprise); err != nil { if err := json.NewEncoder(w).Encode(enterprise); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route POST /enterprises/{enterpriseID}/pools enterprises pools CreateEnterprisePool
//
// Create enterprise pool with the parameters given.
//
// Parameters:
// + name: enterpriseID
// description: Enterprise ID.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when creating the enterprise pool.
// type: CreatePoolParams
// in: body
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) CreateEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) CreateEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -166,31 +269,101 @@ func (a *APIController) CreateEnterprisePoolHandler(w http.ResponseWriter, r *ht
Error: "Bad Request", Error: "Bad Request",
Details: "No enterprise ID specified", Details: "No enterprise ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
var poolData runnerParams.CreatePoolParams var poolData runnerParams.CreatePoolParams
if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil { if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil {
log.Printf("failed to decode: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
pool, err := a.r.CreateEnterprisePool(ctx, enterpriseID, poolData) pool, err := a.r.CreateEnterprisePool(ctx, enterpriseID, poolData)
if err != nil { if err != nil {
log.Printf("error creating enterprise pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating enterprise pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route POST /enterprises/{enterpriseID}/scalesets enterprises scalesets CreateEnterpriseScaleSet
//
// Create enterprise pool with the parameters given.
//
// Parameters:
// + name: enterpriseID
// description: Enterprise ID.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when creating the enterprise scale set.
// type: CreateScaleSetParams
// in: body
// required: true
//
// Responses:
// 200: ScaleSet
// default: APIErrorResponse
func (a *APIController) CreateEnterpriseScaleSetHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
enterpriseID, ok := vars["enterpriseID"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No enterprise ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
var scaleSetData runnerParams.CreateScaleSetParams
if err := json.NewDecoder(r.Body).Decode(&scaleSetData); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
scaleSet, err := a.r.CreateEntityScaleSet(ctx, runnerParams.ForgeEntityTypeEnterprise, enterpriseID, scaleSetData)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating enterprise scale set")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(scaleSet); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /enterprises/{enterpriseID}/pools enterprises pools ListEnterprisePools
//
// List enterprise pools.
//
// Parameters:
// + name: enterpriseID
// description: Enterprise ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Pools
// default: APIErrorResponse
func (a *APIController) ListEnterprisePoolsHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListEnterprisePoolsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -201,25 +374,86 @@ func (a *APIController) ListEnterprisePoolsHandler(w http.ResponseWriter, r *htt
Error: "Bad Request", Error: "Bad Request",
Details: "No enterprise ID specified", Details: "No enterprise ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
pools, err := a.r.ListEnterprisePools(ctx, enterpriseID) pools, err := a.r.ListEnterprisePools(ctx, enterpriseID)
if err != nil { if err != nil {
log.Printf("listing pools: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pools); err != nil { if err := json.NewEncoder(w).Encode(pools); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /enterprises/{enterpriseID}/scalesets enterprises scalesets ListEnterpriseScaleSets
//
// List enterprise scale sets.
//
// Parameters:
// + name: enterpriseID
// description: Enterprise ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: ScaleSets
// default: APIErrorResponse
func (a *APIController) ListEnterpriseScaleSetsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
enterpriseID, ok := vars["enterpriseID"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No enterprise ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
scaleSets, err := a.r.ListEntityScaleSets(ctx, runnerParams.ForgeEntityTypeEnterprise, enterpriseID)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing scale sets")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(scaleSets); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /enterprises/{enterpriseID}/pools/{poolID} enterprises pools GetEnterprisePool
//
// Get enterprise pool by ID.
//
// Parameters:
// + name: enterpriseID
// description: Enterprise ID.
// type: string
// in: path
// required: true
//
// + name: poolID
// description: Pool ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) GetEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) GetEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -231,24 +465,43 @@ func (a *APIController) GetEnterprisePoolHandler(w http.ResponseWriter, r *http.
Error: "Bad Request", Error: "Bad Request",
Details: "No enterprise or pool ID specified", Details: "No enterprise or pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
pool, err := a.r.GetEnterprisePoolByID(ctx, enterpriseID, poolID) pool, err := a.r.GetEnterprisePoolByID(ctx, enterpriseID, poolID)
if err != nil { if err != nil {
log.Printf("listing pools: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route DELETE /enterprises/{enterpriseID}/pools/{poolID} enterprises pools DeleteEnterprisePool
//
// Delete enterprise pool by ID.
//
// Parameters:
// + name: enterpriseID
// description: Enterprise ID.
// type: string
// in: path
// required: true
//
// + name: poolID
// description: ID of the enterprise pool to delete.
// type: string
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) DeleteEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -261,22 +514,47 @@ func (a *APIController) DeleteEnterprisePoolHandler(w http.ResponseWriter, r *ht
Error: "Bad Request", Error: "Bad Request",
Details: "No enterprise or pool ID specified", Details: "No enterprise or pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
if err := a.r.DeleteEnterprisePool(ctx, enterpriseID, poolID); err != nil { if err := a.r.DeleteEnterprisePool(ctx, enterpriseID, poolID); err != nil {
log.Printf("removing pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route PUT /enterprises/{enterpriseID}/pools/{poolID} enterprises pools UpdateEnterprisePool
//
// Update enterprise pool with the parameters given.
//
// Parameters:
// + name: enterpriseID
// description: Enterprise ID.
// type: string
// in: path
// required: true
//
// + name: poolID
// description: ID of the enterprise pool to update.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when updating the enterprise pool.
// type: UpdatePoolParams
// in: body
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) UpdateEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) UpdateEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -289,27 +567,27 @@ func (a *APIController) UpdateEnterprisePoolHandler(w http.ResponseWriter, r *ht
Error: "Bad Request", Error: "Bad Request",
Details: "No enterprise or pool ID specified", Details: "No enterprise or pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
var poolData runnerParams.UpdatePoolParams var poolData runnerParams.UpdatePoolParams
if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil { if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil {
log.Printf("failed to decode: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
pool, err := a.r.UpdateEnterprisePool(ctx, enterpriseID, poolID, poolData) pool, err := a.r.UpdateEnterprisePool(ctx, enterpriseID, poolID, poolData)
if err != nil { if err != nil {
log.Printf("error creating enterprise pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating enterprise pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }

View file

@ -0,0 +1,241 @@
// Copyright 2025 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 controllers
import (
"encoding/json"
"log/slog"
"math"
"net/http"
"strconv"
"github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
)
// swagger:route GET /gitea/credentials credentials ListGiteaCredentials
//
// List all credentials.
//
// Responses:
// 200: Credentials
// 400: APIErrorResponse
func (a *APIController) ListGiteaCredentials(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
creds, err := a.r.ListGiteaCredentials(ctx)
if err != nil {
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(creds); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route POST /gitea/credentials credentials CreateGiteaCredentials
//
// Create a Gitea credential.
//
// Parameters:
// + name: Body
// description: Parameters used when creating a Gitea credential.
// type: CreateGiteaCredentialsParams
// in: body
// required: true
//
// Responses:
// 200: ForgeCredentials
// 400: APIErrorResponse
func (a *APIController) CreateGiteaCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var params params.CreateGiteaCredentialsParams
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
cred, err := a.r.CreateGiteaCredentials(ctx, params)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to create Gitea credential")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(cred); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /gitea/credentials/{id} credentials GetGiteaCredentials
//
// Get a Gitea credential.
//
// Parameters:
// + name: id
// description: ID of the Gitea credential.
// type: integer
// in: path
// required: true
//
// Responses:
// 200: ForgeCredentials
// 400: APIErrorResponse
func (a *APIController) GetGiteaCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
idParam, ok := vars["id"]
if !ok {
slog.ErrorContext(ctx, "missing id in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
id, err := strconv.ParseUint(idParam, 10, 64)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if id > math.MaxUint {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "id is too large")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
cred, err := a.r.GetGiteaCredentials(ctx, uint(id))
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to get Gitea credential")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(cred); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route DELETE /gitea/credentials/{id} credentials DeleteGiteaCredentials
//
// Delete a Gitea credential.
//
// Parameters:
// + name: id
// description: ID of the Gitea credential.
// type: integer
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteGiteaCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
idParam, ok := vars["id"]
if !ok {
slog.ErrorContext(ctx, "missing id in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
id, err := strconv.ParseUint(idParam, 10, 64)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if id > math.MaxUint {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "id is too large")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if err := a.r.DeleteGiteaCredentials(ctx, uint(id)); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to delete Gitea credential")
handleError(ctx, w, err)
return
}
w.WriteHeader(http.StatusNoContent)
}
// swagger:route PUT /gitea/credentials/{id} credentials UpdateGiteaCredentials
//
// Update a Gitea credential.
//
// Parameters:
// + name: id
// description: ID of the Gitea credential.
// type: integer
// in: path
// required: true
// + name: Body
// description: Parameters used when updating a Gitea credential.
// type: UpdateGiteaCredentialsParams
// in: body
// required: true
//
// Responses:
// 200: ForgeCredentials
// 400: APIErrorResponse
func (a *APIController) UpdateGiteaCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
idParam, ok := vars["id"]
if !ok {
slog.ErrorContext(ctx, "missing id in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
id, err := strconv.ParseUint(idParam, 10, 64)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if id > math.MaxUint {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "id is too large")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
var params params.UpdateGiteaCredentialsParams
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
cred, err := a.r.UpdateGiteaCredentials(ctx, uint(id), params)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to update Gitea credential")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(cred); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}

View file

@ -0,0 +1,199 @@
// Copyright 2025 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 controllers
import (
"encoding/json"
"log/slog"
"net/http"
"github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
)
// swagger:route POST /gitea/endpoints endpoints CreateGiteaEndpoint
//
// Create a Gitea Endpoint.
//
// Parameters:
// + name: Body
// description: Parameters used when creating a Gitea endpoint.
// type: CreateGiteaEndpointParams
// in: body
// required: true
//
// Responses:
// 200: ForgeEndpoint
// default: APIErrorResponse
func (a *APIController) CreateGiteaEndpoint(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var params params.CreateGiteaEndpointParams
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
endpoint, err := a.r.CreateGiteaEndpoint(ctx, params)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to create Gitea endpoint")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(endpoint); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /gitea/endpoints endpoints ListGiteaEndpoints
//
// List all Gitea Endpoints.
//
// Responses:
// 200: ForgeEndpoints
// default: APIErrorResponse
func (a *APIController) ListGiteaEndpoints(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
endpoints, err := a.r.ListGiteaEndpoints(ctx)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to list Gitea endpoints")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(endpoints); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /gitea/endpoints/{name} endpoints GetGiteaEndpoint
//
// Get a Gitea Endpoint.
//
// Parameters:
// + name: name
// description: The name of the Gitea endpoint.
// type: string
// in: path
// required: true
//
// Responses:
// 200: ForgeEndpoint
// default: APIErrorResponse
func (a *APIController) GetGiteaEndpoint(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
name, ok := vars["name"]
if !ok {
slog.ErrorContext(ctx, "missing name in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
endpoint, err := a.r.GetGiteaEndpoint(ctx, name)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to get Gitea endpoint")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(endpoint); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route DELETE /gitea/endpoints/{name} endpoints DeleteGiteaEndpoint
//
// Delete a Gitea Endpoint.
//
// Parameters:
// + name: name
// description: The name of the Gitea endpoint.
// type: string
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteGiteaEndpoint(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
name, ok := vars["name"]
if !ok {
slog.ErrorContext(ctx, "missing name in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if err := a.r.DeleteGiteaEndpoint(ctx, name); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to delete Gitea endpoint")
handleError(ctx, w, err)
return
}
w.WriteHeader(http.StatusNoContent)
}
// swagger:route PUT /gitea/endpoints/{name} endpoints UpdateGiteaEndpoint
//
// Update a Gitea Endpoint.
//
// Parameters:
// + name: name
// description: The name of the Gitea endpoint.
// type: string
// in: path
// required: true
// + name: Body
// description: Parameters used when updating a Gitea endpoint.
// type: UpdateGiteaEndpointParams
// in: body
// required: true
//
// Responses:
// 200: ForgeEndpoint
// default: APIErrorResponse
func (a *APIController) UpdateGiteaEndpoint(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
name, ok := vars["name"]
if !ok {
slog.ErrorContext(ctx, "missing name in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
var params params.UpdateGiteaEndpointParams
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
endpoint, err := a.r.UpdateGiteaEndpoint(ctx, name, params)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to update GitHub endpoint")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(endpoint); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}

View file

@ -0,0 +1,242 @@
// Copyright 2025 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 controllers
import (
"encoding/json"
"log/slog"
"math"
"net/http"
"strconv"
"github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
)
// swagger:route GET /credentials credentials ListCredentials
// swagger:route GET /github/credentials credentials ListCredentials
//
// List all credentials.
//
// Responses:
// 200: Credentials
// 400: APIErrorResponse
func (a *APIController) ListCredentials(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
creds, err := a.r.ListCredentials(ctx)
if err != nil {
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(creds); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route POST /github/credentials credentials CreateCredentials
//
// Create a GitHub credential.
//
// Parameters:
// + name: Body
// description: Parameters used when creating a GitHub credential.
// type: CreateGithubCredentialsParams
// in: body
// required: true
//
// Responses:
// 200: ForgeCredentials
// 400: APIErrorResponse
func (a *APIController) CreateGithubCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var params params.CreateGithubCredentialsParams
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
cred, err := a.r.CreateGithubCredentials(ctx, params)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to create GitHub credential")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(cred); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /github/credentials/{id} credentials GetCredentials
//
// Get a GitHub credential.
//
// Parameters:
// + name: id
// description: ID of the GitHub credential.
// type: integer
// in: path
// required: true
//
// Responses:
// 200: ForgeCredentials
// 400: APIErrorResponse
func (a *APIController) GetGithubCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
idParam, ok := vars["id"]
if !ok {
slog.ErrorContext(ctx, "missing id in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
id, err := strconv.ParseUint(idParam, 10, 64)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if id > math.MaxUint {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "id is too large")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
cred, err := a.r.GetGithubCredentials(ctx, uint(id))
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to get GitHub credential")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(cred); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route DELETE /github/credentials/{id} credentials DeleteCredentials
//
// Delete a GitHub credential.
//
// Parameters:
// + name: id
// description: ID of the GitHub credential.
// type: integer
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteGithubCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
idParam, ok := vars["id"]
if !ok {
slog.ErrorContext(ctx, "missing id in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
id, err := strconv.ParseUint(idParam, 10, 64)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if id > math.MaxUint {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "id is too large")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if err := a.r.DeleteGithubCredentials(ctx, uint(id)); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to delete GitHub credential")
handleError(ctx, w, err)
return
}
w.WriteHeader(http.StatusNoContent)
}
// swagger:route PUT /github/credentials/{id} credentials UpdateCredentials
//
// Update a GitHub credential.
//
// Parameters:
// + name: id
// description: ID of the GitHub credential.
// type: integer
// in: path
// required: true
// + name: Body
// description: Parameters used when updating a GitHub credential.
// type: UpdateGithubCredentialsParams
// in: body
// required: true
//
// Responses:
// 200: ForgeCredentials
// 400: APIErrorResponse
func (a *APIController) UpdateGithubCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
idParam, ok := vars["id"]
if !ok {
slog.ErrorContext(ctx, "missing id in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
id, err := strconv.ParseUint(idParam, 10, 64)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if id > math.MaxUint {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "id is too large")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
var params params.UpdateGithubCredentialsParams
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
cred, err := a.r.UpdateGithubCredentials(ctx, uint(id), params)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to update GitHub credential")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(cred); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}

View file

@ -0,0 +1,199 @@
// Copyright 2025 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 controllers
import (
"encoding/json"
"log/slog"
"net/http"
"github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
)
// swagger:route POST /github/endpoints endpoints CreateGithubEndpoint
//
// Create a GitHub Endpoint.
//
// Parameters:
// + name: Body
// description: Parameters used when creating a GitHub endpoint.
// type: CreateGithubEndpointParams
// in: body
// required: true
//
// Responses:
// 200: ForgeEndpoint
// default: APIErrorResponse
func (a *APIController) CreateGithubEndpoint(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var params params.CreateGithubEndpointParams
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
endpoint, err := a.r.CreateGithubEndpoint(ctx, params)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to create GitHub endpoint")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(endpoint); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /github/endpoints endpoints ListGithubEndpoints
//
// List all GitHub Endpoints.
//
// Responses:
// 200: ForgeEndpoints
// default: APIErrorResponse
func (a *APIController) ListGithubEndpoints(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
endpoints, err := a.r.ListGithubEndpoints(ctx)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to list GitHub endpoints")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(endpoints); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /github/endpoints/{name} endpoints GetGithubEndpoint
//
// Get a GitHub Endpoint.
//
// Parameters:
// + name: name
// description: The name of the GitHub endpoint.
// type: string
// in: path
// required: true
//
// Responses:
// 200: ForgeEndpoint
// default: APIErrorResponse
func (a *APIController) GetGithubEndpoint(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
name, ok := vars["name"]
if !ok {
slog.ErrorContext(ctx, "missing name in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
endpoint, err := a.r.GetGithubEndpoint(ctx, name)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to get GitHub endpoint")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(endpoint); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route DELETE /github/endpoints/{name} endpoints DeleteGithubEndpoint
//
// Delete a GitHub Endpoint.
//
// Parameters:
// + name: name
// description: The name of the GitHub endpoint.
// type: string
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteGithubEndpoint(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
name, ok := vars["name"]
if !ok {
slog.ErrorContext(ctx, "missing name in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if err := a.r.DeleteGithubEndpoint(ctx, name); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to delete GitHub endpoint")
handleError(ctx, w, err)
return
}
w.WriteHeader(http.StatusNoContent)
}
// swagger:route PUT /github/endpoints/{name} endpoints UpdateGithubEndpoint
//
// Update a GitHub Endpoint.
//
// Parameters:
// + name: name
// description: The name of the GitHub endpoint.
// type: string
// in: path
// required: true
// + name: Body
// description: Parameters used when updating a GitHub endpoint.
// type: UpdateGithubEndpointParams
// in: body
// required: true
//
// Responses:
// 200: ForgeEndpoint
// default: APIErrorResponse
func (a *APIController) UpdateGithubEndpoint(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
name, ok := vars["name"]
if !ok {
slog.ErrorContext(ctx, "missing name in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
var params params.UpdateGithubEndpointParams
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
endpoint, err := a.r.UpdateGithubEndpoint(ctx, name, params)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to update GitHub endpoint")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(endpoint); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}

View file

@ -16,16 +16,31 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"log" "log/slog"
"net/http" "net/http"
"strconv"
"github.com/cloudbase/garm/apiserver/params"
gErrors "github.com/cloudbase/garm/errors"
runnerParams "github.com/cloudbase/garm/params"
"github.com/gorilla/mux" "github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
) )
// swagger:route GET /pools/{poolID}/instances instances ListPoolInstances
//
// List runner instances in a pool.
//
// Parameters:
// + name: poolID
// description: Runner pool ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Instances
// default: APIErrorResponse
func (a *APIController) ListPoolInstancesHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListPoolInstancesHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -36,24 +51,86 @@ func (a *APIController) ListPoolInstancesHandler(w http.ResponseWriter, r *http.
Error: "Bad Request", Error: "Bad Request",
Details: "No pool ID specified", Details: "No pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
instances, err := a.r.ListPoolInstances(ctx, poolID) instances, err := a.r.ListPoolInstances(ctx, poolID)
if err != nil { if err != nil {
log.Printf("listing pool instances: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pool instances")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(instances); err != nil { if err := json.NewEncoder(w).Encode(instances); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /scalesets/{scalesetID}/instances instances ListScaleSetInstances
//
// List runner instances in a scale set.
//
// Parameters:
// + name: scalesetID
// description: Runner scale set ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Instances
// default: APIErrorResponse
func (a *APIController) ListScaleSetInstancesHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
scalesetID, ok := vars["scalesetID"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No pool ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
id, err := strconv.ParseUint(scalesetID, 10, 32)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
instances, err := a.r.ListScaleSetInstances(ctx, uint(id))
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pool instances")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(instances); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /instances/{instanceName} instances GetInstance
//
// Get runner instance by name.
//
// Parameters:
// + name: instanceName
// description: Runner instance name.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Instance
// default: APIErrorResponse
func (a *APIController) GetInstanceHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) GetInstanceHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -64,24 +141,50 @@ func (a *APIController) GetInstanceHandler(w http.ResponseWriter, r *http.Reques
Error: "Bad Request", Error: "Bad Request",
Details: "No runner name specified", Details: "No runner name specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
instance, err := a.r.GetInstance(ctx, instanceName) instance, err := a.r.GetInstance(ctx, instanceName)
if err != nil { if err != nil {
log.Printf("listing instances: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing instances")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(instance); err != nil { if err := json.NewEncoder(w).Encode(instance); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route DELETE /instances/{instanceName} instances DeleteInstance
//
// Delete runner instance by name.
//
// Parameters:
// + name: instanceName
// description: Runner instance name.
// type: string
// in: path
// required: true
//
// + name: forceRemove
// description: If true GARM will ignore any provider error when removing the runner and will continue to remove the runner from github and the GARM database.
// type: boolean
// in: query
// required: false
//
// + name: bypassGHUnauthorized
// description: If true GARM will ignore unauthorized errors returned by GitHub when removing a runner. This is useful if you want to clean up runners and your credentials have expired.
// type: boolean
// in: query
// required: false
//
// Responses:
//
// default: APIErrorResponse
func (a *APIController) DeleteInstanceHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) DeleteInstanceHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -92,14 +195,16 @@ func (a *APIController) DeleteInstanceHandler(w http.ResponseWriter, r *http.Req
Error: "Bad Request", Error: "Bad Request",
Details: "No instance name specified", Details: "No instance name specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
if err := a.r.ForceDeleteRunner(ctx, instanceName); err != nil { forceRemove, _ := strconv.ParseBool(r.URL.Query().Get("forceRemove"))
log.Printf("removing runner: %s", err) bypassGHUnauthorized, _ := strconv.ParseBool(r.URL.Query().Get("bypassGHUnauthorized"))
handleError(w, err) if err := a.r.DeleteRunner(ctx, instanceName, forceRemove, bypassGHUnauthorized); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing runner")
handleError(ctx, w, err)
return return
} }
@ -107,6 +212,20 @@ func (a *APIController) DeleteInstanceHandler(w http.ResponseWriter, r *http.Req
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route GET /repositories/{repoID}/instances repositories instances ListRepoInstances
//
// List repository instances.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Instances
// default: APIErrorResponse
func (a *APIController) ListRepoInstancesHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListRepoInstancesHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -117,24 +236,38 @@ func (a *APIController) ListRepoInstancesHandler(w http.ResponseWriter, r *http.
Error: "Bad Request", Error: "Bad Request",
Details: "No repo ID specified", Details: "No repo ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
instances, err := a.r.ListRepoInstances(ctx, repoID) instances, err := a.r.ListRepoInstances(ctx, repoID)
if err != nil { if err != nil {
log.Printf("listing pools: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(instances); err != nil { if err := json.NewEncoder(w).Encode(instances); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /organizations/{orgID}/instances organizations instances ListOrgInstances
//
// List organization instances.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Instances
// default: APIErrorResponse
func (a *APIController) ListOrgInstancesHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListOrgInstancesHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -145,24 +278,38 @@ func (a *APIController) ListOrgInstancesHandler(w http.ResponseWriter, r *http.R
Error: "Bad Request", Error: "Bad Request",
Details: "No org ID specified", Details: "No org ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
instances, err := a.r.ListOrgInstances(ctx, orgID) instances, err := a.r.ListOrgInstances(ctx, orgID)
if err != nil { if err != nil {
log.Printf("listing instances: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing instances")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(instances); err != nil { if err := json.NewEncoder(w).Encode(instances); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /enterprises/{enterpriseID}/instances enterprises instances ListEnterpriseInstances
//
// List enterprise instances.
//
// Parameters:
// + name: enterpriseID
// description: Enterprise ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Instances
// default: APIErrorResponse
func (a *APIController) ListEnterpriseInstancesHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListEnterpriseInstancesHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -173,37 +320,44 @@ func (a *APIController) ListEnterpriseInstancesHandler(w http.ResponseWriter, r
Error: "Bad Request", Error: "Bad Request",
Details: "No enterprise ID specified", Details: "No enterprise ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
instances, err := a.r.ListEnterpriseInstances(ctx, enterpriseID) instances, err := a.r.ListEnterpriseInstances(ctx, enterpriseID)
if err != nil { if err != nil {
log.Printf("listing instances: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing instances")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(instances); err != nil { if err := json.NewEncoder(w).Encode(instances); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /instances instances ListInstances
//
// Get all runners' instances.
//
// Responses:
// 200: Instances
// default: APIErrorResponse
func (a *APIController) ListAllInstancesHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListAllInstancesHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
instances, err := a.r.ListAllInstances(ctx) instances, err := a.r.ListAllInstances(ctx)
if err != nil { if err != nil {
log.Printf("listing instances: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing instances")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(instances); err != nil { if err := json.NewEncoder(w).Encode(instances); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
@ -212,14 +366,14 @@ func (a *APIController) InstanceStatusMessageHandler(w http.ResponseWriter, r *h
var updateMessage runnerParams.InstanceUpdateMessage var updateMessage runnerParams.InstanceUpdateMessage
if err := json.NewDecoder(r.Body).Decode(&updateMessage); err != nil { if err := json.NewDecoder(r.Body).Decode(&updateMessage); err != nil {
log.Printf("failed to decode: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
if err := a.r.AddInstanceStatusMessage(ctx, updateMessage); err != nil { if err := a.r.AddInstanceStatusMessage(ctx, updateMessage); err != nil {
log.Printf("error saving status message: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error saving status message")
handleError(w, err) handleError(ctx, w, err)
return return
} }
@ -227,18 +381,22 @@ func (a *APIController) InstanceStatusMessageHandler(w http.ResponseWriter, r *h
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
func (a *APIController) InstanceGithubRegistrationTokenHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) InstanceSystemInfoHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
token, err := a.r.GetInstanceGithubRegistrationToken(ctx) var updateMessage runnerParams.UpdateSystemInfoParams
if err != nil { if err := json.NewDecoder(r.Body).Decode(&updateMessage); err != nil {
handleError(w, err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if err := a.r.UpdateSystemInfo(ctx, updateMessage); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "error saving status message")
handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
if _, err := w.Write([]byte(token)); err != nil {
log.Printf("failed to encode response: %q", err)
}
} }

View file

@ -0,0 +1,125 @@
// Copyright 2023 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 controllers
import (
"encoding/json"
"fmt"
"log/slog"
"net/http"
"github.com/gorilla/mux"
"github.com/cloudbase/garm/apiserver/params"
)
func (a *APIController) InstanceGithubRegistrationTokenHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
token, err := a.r.GetInstanceGithubRegistrationToken(ctx)
if err != nil {
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if _, err := w.Write([]byte(token)); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
func (a *APIController) JITCredentialsFileHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
fileName, ok := vars["fileName"]
if !ok {
w.WriteHeader(http.StatusNotFound)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Not Found",
Details: "Not Found",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
dotFileName := fmt.Sprintf(".%s", fileName)
data, err := a.r.GetJITConfigFile(ctx, dotFileName)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "getting JIT config file")
handleError(ctx, w, err)
return
}
// Note the leading dot in the filename
name := fmt.Sprintf("attachment; filename=%s", dotFileName)
w.Header().Set("Content-Disposition", name)
w.Header().Set("Content-Type", "octet-stream")
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(data)))
w.WriteHeader(http.StatusOK)
if _, err := w.Write(data); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
func (a *APIController) SystemdServiceNameHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
serviceName, err := a.r.GetRunnerServiceName(ctx)
if err != nil {
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
if _, err := w.Write([]byte(serviceName)); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
func (a *APIController) SystemdUnitFileHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
runAsUser := r.URL.Query().Get("runAsUser")
data, err := a.r.GenerateSystemdUnitFile(ctx, runAsUser)
if err != nil {
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
if _, err := w.Write(data); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
func (a *APIController) RootCertificateBundleHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
bundle, err := a.r.GetRootCertificateBundle(ctx)
if err != nil {
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(bundle); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}

View file

@ -16,54 +16,107 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"log" "log/slog"
"net/http" "net/http"
"strconv"
"github.com/cloudbase/garm/apiserver/params"
gErrors "github.com/cloudbase/garm/errors"
runnerParams "github.com/cloudbase/garm/params"
"github.com/gorilla/mux" "github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
) )
// swagger:route POST /organizations organizations CreateOrg
//
// Create organization with the parameters given.
//
// Parameters:
// + name: Body
// description: Parameters used when creating the organization.
// type: CreateOrgParams
// in: body
// required: true
//
// Responses:
// 200: Organization
// default: APIErrorResponse
func (a *APIController) CreateOrgHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) CreateOrgHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
var repoData runnerParams.CreateOrgParams var orgData runnerParams.CreateOrgParams
if err := json.NewDecoder(r.Body).Decode(&repoData); err != nil { if err := json.NewDecoder(r.Body).Decode(&orgData); err != nil {
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
repo, err := a.r.CreateOrganization(ctx, repoData) org, err := a.r.CreateOrganization(ctx, orgData)
if err != nil { if err != nil {
log.Printf("error creating repository: %+v", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating organization")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(repo); err != nil { if err := json.NewEncoder(w).Encode(org); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /organizations organizations ListOrgs
//
// List organizations.
//
// Parameters:
// + name: name
// description: Exact organization name to filter by
// type: string
// in: query
// required: false
//
// + name: endpoint
// description: Exact endpoint name to filter by
// type: string
// in: query
// required: false
//
// Responses:
// 200: Organizations
// default: APIErrorResponse
func (a *APIController) ListOrgsHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListOrgsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
orgs, err := a.r.ListOrganizations(ctx) filter := runnerParams.OrganizationFilter{
Name: r.URL.Query().Get("name"),
Endpoint: r.URL.Query().Get("endpoint"),
}
orgs, err := a.r.ListOrganizations(ctx, filter)
if err != nil { if err != nil {
log.Printf("listing orgs: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing orgs")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(orgs); err != nil { if err := json.NewEncoder(w).Encode(orgs); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /organizations/{orgID} organizations GetOrg
//
// Get organization by ID.
//
// Parameters:
// + name: orgID
// description: ID of the organization to fetch.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Organization
// default: APIErrorResponse
func (a *APIController) GetOrgByIDHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) GetOrgByIDHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -75,24 +128,43 @@ func (a *APIController) GetOrgByIDHandler(w http.ResponseWriter, r *http.Request
Error: "Bad Request", Error: "Bad Request",
Details: "No org ID specified", Details: "No org ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
org, err := a.r.GetOrganizationByID(ctx, orgID) org, err := a.r.GetOrganizationByID(ctx, orgID)
if err != nil { if err != nil {
log.Printf("fetching org: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "fetching org")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(org); err != nil { if err := json.NewEncoder(w).Encode(org); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route DELETE /organizations/{orgID} organizations DeleteOrg
//
// Delete organization by ID.
//
// Parameters:
// + name: orgID
// description: ID of the organization to delete.
// type: string
// in: path
// required: true
//
// + name: keepWebhook
// description: If true and a webhook is installed for this organization, it will not be removed.
// type: boolean
// in: query
// required: false
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteOrgHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) DeleteOrgHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -104,22 +176,43 @@ func (a *APIController) DeleteOrgHandler(w http.ResponseWriter, r *http.Request)
Error: "Bad Request", Error: "Bad Request",
Details: "No org ID specified", Details: "No org ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
if err := a.r.DeleteOrganization(ctx, orgID); err != nil { keepWebhook, _ := strconv.ParseBool(r.URL.Query().Get("keepWebhook"))
log.Printf("removing org: %+v", err)
handleError(w, err) if err := a.r.DeleteOrganization(ctx, orgID, keepWebhook); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing org")
handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route PUT /organizations/{orgID} organizations UpdateOrg
//
// Update organization with the parameters given.
//
// Parameters:
// + name: orgID
// description: ID of the organization to update.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when updating the organization.
// type: UpdateEntityParams
// in: body
// required: true
//
// Responses:
// 200: Organization
// default: APIErrorResponse
func (a *APIController) UpdateOrgHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) UpdateOrgHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -131,30 +224,50 @@ func (a *APIController) UpdateOrgHandler(w http.ResponseWriter, r *http.Request)
Error: "Bad Request", Error: "Bad Request",
Details: "No org ID specified", Details: "No org ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
var updatePayload runnerParams.UpdateRepositoryParams var updatePayload runnerParams.UpdateEntityParams
if err := json.NewDecoder(r.Body).Decode(&updatePayload); err != nil { if err := json.NewDecoder(r.Body).Decode(&updatePayload); err != nil {
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
org, err := a.r.UpdateOrganization(ctx, orgID, updatePayload) org, err := a.r.UpdateOrganization(ctx, orgID, updatePayload)
if err != nil { if err != nil {
log.Printf("error updating organization: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error updating organization")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(org); err != nil { if err := json.NewEncoder(w).Encode(org); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route POST /organizations/{orgID}/pools organizations pools CreateOrgPool
//
// Create organization pool with the parameters given.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when creating the organization pool.
// type: CreatePoolParams
// in: body
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) CreateOrgPoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) CreateOrgPoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -166,31 +279,101 @@ func (a *APIController) CreateOrgPoolHandler(w http.ResponseWriter, r *http.Requ
Error: "Bad Request", Error: "Bad Request",
Details: "No org ID specified", Details: "No org ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
var poolData runnerParams.CreatePoolParams var poolData runnerParams.CreatePoolParams
if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil { if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil {
log.Printf("failed to decode: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
pool, err := a.r.CreateOrgPool(ctx, orgID, poolData) pool, err := a.r.CreateOrgPool(ctx, orgID, poolData)
if err != nil { if err != nil {
log.Printf("error creating organization pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating organization pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route POST /organizations/{orgID}/scalesets organizations scalesets CreateOrgScaleSet
//
// Create organization scale set with the parameters given.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when creating the organization scale set.
// type: CreateScaleSetParams
// in: body
// required: true
//
// Responses:
// 200: ScaleSet
// default: APIErrorResponse
func (a *APIController) CreateOrgScaleSetHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
orgID, ok := vars["orgID"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No org ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
var scalesetData runnerParams.CreateScaleSetParams
if err := json.NewDecoder(r.Body).Decode(&scalesetData); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
scaleSet, err := a.r.CreateEntityScaleSet(ctx, runnerParams.ForgeEntityTypeOrganization, orgID, scalesetData)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating organization scale set")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(scaleSet); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /organizations/{orgID}/pools organizations pools ListOrgPools
//
// List organization pools.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Pools
// default: APIErrorResponse
func (a *APIController) ListOrgPoolsHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListOrgPoolsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -201,53 +384,134 @@ func (a *APIController) ListOrgPoolsHandler(w http.ResponseWriter, r *http.Reque
Error: "Bad Request", Error: "Bad Request",
Details: "No org ID specified", Details: "No org ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
pools, err := a.r.ListOrgPools(ctx, orgID) pools, err := a.r.ListOrgPools(ctx, orgID)
if err != nil { if err != nil {
log.Printf("listing pools: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pools); err != nil { if err := json.NewEncoder(w).Encode(pools); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /organizations/{orgID}/scalesets organizations scalesets ListOrgScaleSets
//
// List organization scale sets.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: ScaleSets
// default: APIErrorResponse
func (a *APIController) ListOrgScaleSetsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
orgID, ok := vars["orgID"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No org ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
scaleSets, err := a.r.ListEntityScaleSets(ctx, runnerParams.ForgeEntityTypeOrganization, orgID)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing scale sets")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(scaleSets); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /organizations/{orgID}/pools/{poolID} organizations pools GetOrgPool
//
// Get organization pool by ID.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// + name: poolID
// description: Pool ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) GetOrgPoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) GetOrgPoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
orgID, repoOk := vars["orgID"] orgID, orgOk := vars["orgID"]
poolID, poolOk := vars["poolID"] poolID, poolOk := vars["poolID"]
if !repoOk || !poolOk { if !orgOk || !poolOk {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{ if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request", Error: "Bad Request",
Details: "No org or pool ID specified", Details: "No org or pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
pool, err := a.r.GetOrgPoolByID(ctx, orgID, poolID) pool, err := a.r.GetOrgPoolByID(ctx, orgID, poolID)
if err != nil { if err != nil {
log.Printf("listing pools: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route DELETE /organizations/{orgID}/pools/{poolID} organizations pools DeleteOrgPool
//
// Delete organization pool by ID.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// + name: poolID
// description: ID of the organization pool to delete.
// type: string
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteOrgPoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) DeleteOrgPoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -260,22 +524,47 @@ func (a *APIController) DeleteOrgPoolHandler(w http.ResponseWriter, r *http.Requ
Error: "Bad Request", Error: "Bad Request",
Details: "No org or pool ID specified", Details: "No org or pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
if err := a.r.DeleteOrgPool(ctx, orgID, poolID); err != nil { if err := a.r.DeleteOrgPool(ctx, orgID, poolID); err != nil {
log.Printf("removing pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route PUT /organizations/{orgID}/pools/{poolID} organizations pools UpdateOrgPool
//
// Update organization pool with the parameters given.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// + name: poolID
// description: ID of the organization pool to update.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when updating the organization pool.
// type: UpdatePoolParams
// in: body
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) UpdateOrgPoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) UpdateOrgPoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -288,27 +577,166 @@ func (a *APIController) UpdateOrgPoolHandler(w http.ResponseWriter, r *http.Requ
Error: "Bad Request", Error: "Bad Request",
Details: "No org or pool ID specified", Details: "No org or pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
var poolData runnerParams.UpdatePoolParams var poolData runnerParams.UpdatePoolParams
if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil { if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil {
log.Printf("failed to decode: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
pool, err := a.r.UpdateOrgPool(ctx, orgID, poolID, poolData) pool, err := a.r.UpdateOrgPool(ctx, orgID, poolID, poolData)
if err != nil { if err != nil {
log.Printf("error creating organization pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating organization pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route POST /organizations/{orgID}/webhook organizations hooks InstallOrgWebhook
//
// Install the GARM webhook for an organization. The secret configured on the organization will
// be used to validate the requests.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when creating the organization webhook.
// type: InstallWebhookParams
// in: body
// required: true
//
// Responses:
// 200: HookInfo
// default: APIErrorResponse
func (a *APIController) InstallOrgWebhookHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
orgID, orgOk := vars["orgID"]
if !orgOk {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No org ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
var hookParam runnerParams.InstallWebhookParams
if err := json.NewDecoder(r.Body).Decode(&hookParam); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
info, err := a.r.InstallOrgWebhook(ctx, orgID, hookParam)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "installing webhook")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(info); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route DELETE /organizations/{orgID}/webhook organizations hooks UninstallOrgWebhook
//
// Uninstall organization webhook.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) UninstallOrgWebhookHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
orgID, orgOk := vars["orgID"]
if !orgOk {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No org ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
if err := a.r.UninstallOrgWebhook(ctx, orgID); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing webhook")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route GET /organizations/{orgID}/webhook organizations hooks GetOrgWebhookInfo
//
// Get information about the GARM installed webhook on an organization.
//
// Parameters:
// + name: orgID
// description: Organization ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: HookInfo
// default: APIErrorResponse
func (a *APIController) GetOrgWebhookInfoHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
orgID, orgOk := vars["orgID"]
if !orgOk {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No org ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
info, err := a.r.GetOrgWebhookInfo(ctx, orgID)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "getting webhook info")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(info); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }

View file

@ -16,33 +16,53 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"log" "log/slog"
"net/http" "net/http"
"github.com/cloudbase/garm/apiserver/params"
gErrors "github.com/cloudbase/garm/errors"
runnerParams "github.com/cloudbase/garm/params"
"github.com/gorilla/mux" "github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
) )
// swagger:route GET /pools pools ListPools
//
// List all pools.
//
// Responses:
// 200: Pools
// default: APIErrorResponse
func (a *APIController) ListAllPoolsHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListAllPoolsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
pools, err := a.r.ListAllPools(ctx) pools, err := a.r.ListAllPools(ctx)
if err != nil { if err != nil {
log.Printf("listing pools: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pools); err != nil { if err := json.NewEncoder(w).Encode(pools); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /pools/{poolID} pools GetPool
//
// Get pool by ID.
//
// Parameters:
// + name: poolID
// description: ID of the pool to fetch.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) GetPoolByIDHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) GetPoolByIDHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -54,15 +74,15 @@ func (a *APIController) GetPoolByIDHandler(w http.ResponseWriter, r *http.Reques
Error: "Bad Request", Error: "Bad Request",
Details: "No pool ID specified", Details: "No pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
pool, err := a.r.GetPoolByID(ctx, poolID) pool, err := a.r.GetPoolByID(ctx, poolID)
if err != nil { if err != nil {
log.Printf("fetching pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "fetching pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
@ -70,10 +90,23 @@ func (a *APIController) GetPoolByIDHandler(w http.ResponseWriter, r *http.Reques
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route DELETE /pools/{poolID} pools DeletePool
//
// Delete pool by ID.
//
// Parameters:
// + name: poolID
// description: ID of the pool to delete.
// type: string
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeletePoolByIDHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) DeletePoolByIDHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -85,14 +118,14 @@ func (a *APIController) DeletePoolByIDHandler(w http.ResponseWriter, r *http.Req
Error: "Bad Request", Error: "Bad Request",
Details: "No pool ID specified", Details: "No pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
if err := a.r.DeletePoolByID(ctx, poolID); err != nil { if err := a.r.DeletePoolByID(ctx, poolID); err != nil {
log.Printf("removing pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
@ -100,6 +133,26 @@ func (a *APIController) DeletePoolByIDHandler(w http.ResponseWriter, r *http.Req
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route PUT /pools/{poolID} pools UpdatePool
//
// Update pool by ID.
//
// Parameters:
// + name: poolID
// description: ID of the pool to update.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters to update the pool with.
// type: UpdatePoolParams
// in: body
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) UpdatePoolByIDHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) UpdatePoolByIDHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -111,27 +164,27 @@ func (a *APIController) UpdatePoolByIDHandler(w http.ResponseWriter, r *http.Req
Error: "Bad Request", Error: "Bad Request",
Details: "No pool ID specified", Details: "No pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
var poolData runnerParams.UpdatePoolParams var poolData runnerParams.UpdatePoolParams
if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil { if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil {
log.Printf("failed to decode: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
pool, err := a.r.UpdatePoolByID(ctx, poolID, poolData) pool, err := a.r.UpdatePoolByID(ctx, poolID, poolData)
if err != nil { if err != nil {
log.Printf("fetching pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "fetching pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }

View file

@ -16,54 +16,114 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"log" "log/slog"
"net/http" "net/http"
"strconv"
"github.com/cloudbase/garm/apiserver/params"
gErrors "github.com/cloudbase/garm/errors"
runnerParams "github.com/cloudbase/garm/params"
"github.com/gorilla/mux" "github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
) )
// swagger:route POST /repositories repositories CreateRepo
//
// Create repository with the parameters given.
//
// Parameters:
// + name: Body
// description: Parameters used when creating the repository.
// type: CreateRepoParams
// in: body
// required: true
//
// Responses:
// 200: Repository
// default: APIErrorResponse
func (a *APIController) CreateRepoHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) CreateRepoHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
var repoData runnerParams.CreateRepoParams var repoData runnerParams.CreateRepoParams
if err := json.NewDecoder(r.Body).Decode(&repoData); err != nil { if err := json.NewDecoder(r.Body).Decode(&repoData); err != nil {
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
repo, err := a.r.CreateRepository(ctx, repoData) repo, err := a.r.CreateRepository(ctx, repoData)
if err != nil { if err != nil {
log.Printf("error creating repository: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating repository")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(repo); err != nil { if err := json.NewEncoder(w).Encode(repo); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /repositories repositories ListRepos
//
// List repositories.
//
// Parameters:
// + name: owner
// description: Exact owner name to filter by
// type: string
// in: query
// required: false
//
// + name: name
// description: Exact repository name to filter by
// type: string
// in: query
// required: false
//
// + name: endpoint
// description: Exact endpoint name to filter by
// type: string
// in: query
// required: false
//
// Responses:
// 200: Repositories
// default: APIErrorResponse
func (a *APIController) ListReposHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListReposHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
repos, err := a.r.ListRepositories(ctx) filter := runnerParams.RepositoryFilter{
Name: r.URL.Query().Get("name"),
Owner: r.URL.Query().Get("owner"),
Endpoint: r.URL.Query().Get("endpoint"),
}
repos, err := a.r.ListRepositories(ctx, filter)
if err != nil { if err != nil {
log.Printf("listing repos: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing repositories")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(repos); err != nil { if err := json.NewEncoder(w).Encode(repos); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /repositories/{repoID} repositories GetRepo
//
// Get repository by ID.
//
// Parameters:
// + name: repoID
// description: ID of the repository to fetch.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Repository
// default: APIErrorResponse
func (a *APIController) GetRepoByIDHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) GetRepoByIDHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -75,24 +135,43 @@ func (a *APIController) GetRepoByIDHandler(w http.ResponseWriter, r *http.Reques
Error: "Bad Request", Error: "Bad Request",
Details: "No repo ID specified", Details: "No repo ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
repo, err := a.r.GetRepositoryByID(ctx, repoID) repo, err := a.r.GetRepositoryByID(ctx, repoID)
if err != nil { if err != nil {
log.Printf("fetching repo: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "fetching repository")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(repo); err != nil { if err := json.NewEncoder(w).Encode(repo); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route DELETE /repositories/{repoID} repositories DeleteRepo
//
// Delete repository by ID.
//
// Parameters:
// + name: repoID
// description: ID of the repository to delete.
// type: string
// in: path
// required: true
//
// + name: keepWebhook
// description: If true and a webhook is installed for this repo, it will not be removed.
// type: boolean
// in: query
// required: false
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteRepoHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) DeleteRepoHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -104,22 +183,42 @@ func (a *APIController) DeleteRepoHandler(w http.ResponseWriter, r *http.Request
Error: "Bad Request", Error: "Bad Request",
Details: "No repo ID specified", Details: "No repo ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
if err := a.r.DeleteRepository(ctx, repoID); err != nil { keepWebhook, _ := strconv.ParseBool(r.URL.Query().Get("keepWebhook"))
log.Printf("fetching repo: %s", err) if err := a.r.DeleteRepository(ctx, repoID, keepWebhook); err != nil {
handleError(w, err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "fetching repository")
handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route PUT /repositories/{repoID} repositories UpdateRepo
//
// Update repository with the parameters given.
//
// Parameters:
// + name: repoID
// description: ID of the repository to update.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when updating the repository.
// type: UpdateEntityParams
// in: body
// required: true
//
// Responses:
// 200: Repository
// default: APIErrorResponse
func (a *APIController) UpdateRepoHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) UpdateRepoHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -131,30 +230,50 @@ func (a *APIController) UpdateRepoHandler(w http.ResponseWriter, r *http.Request
Error: "Bad Request", Error: "Bad Request",
Details: "No repo ID specified", Details: "No repo ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
var updatePayload runnerParams.UpdateRepositoryParams var updatePayload runnerParams.UpdateEntityParams
if err := json.NewDecoder(r.Body).Decode(&updatePayload); err != nil { if err := json.NewDecoder(r.Body).Decode(&updatePayload); err != nil {
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
repo, err := a.r.UpdateRepository(ctx, repoID, updatePayload) repo, err := a.r.UpdateRepository(ctx, repoID, updatePayload)
if err != nil { if err != nil {
log.Printf("error updating repository: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error updating repository")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(repo); err != nil { if err := json.NewEncoder(w).Encode(repo); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route POST /repositories/{repoID}/pools repositories pools CreateRepoPool
//
// Create repository pool with the parameters given.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when creating the repository pool.
// type: CreatePoolParams
// in: body
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) CreateRepoPoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) CreateRepoPoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -166,31 +285,101 @@ func (a *APIController) CreateRepoPoolHandler(w http.ResponseWriter, r *http.Req
Error: "Bad Request", Error: "Bad Request",
Details: "No repo ID specified", Details: "No repo ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
var poolData runnerParams.CreatePoolParams var poolData runnerParams.CreatePoolParams
if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil { if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil {
log.Printf("failed to decode: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
pool, err := a.r.CreateRepoPool(ctx, repoID, poolData) pool, err := a.r.CreateRepoPool(ctx, repoID, poolData)
if err != nil { if err != nil {
log.Printf("error creating repository pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating repository pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route POST /repositories/{repoID}/scalesets repositories scalesets CreateRepoScaleSet
//
// Create repository scale set with the parameters given.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when creating the repository scale set.
// type: CreateScaleSetParams
// in: body
// required: true
//
// Responses:
// 200: ScaleSet
// default: APIErrorResponse
func (a *APIController) CreateRepoScaleSetHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
repoID, ok := vars["repoID"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No repo ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
var scaleSetData runnerParams.CreateScaleSetParams
if err := json.NewDecoder(r.Body).Decode(&scaleSetData); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
scaleSet, err := a.r.CreateEntityScaleSet(ctx, runnerParams.ForgeEntityTypeRepository, repoID, scaleSetData)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating repository scale set")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(scaleSet); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /repositories/{repoID}/pools repositories pools ListRepoPools
//
// List repository pools.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Pools
// default: APIErrorResponse
func (a *APIController) ListRepoPoolsHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) ListRepoPoolsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -201,24 +390,86 @@ func (a *APIController) ListRepoPoolsHandler(w http.ResponseWriter, r *http.Requ
Error: "Bad Request", Error: "Bad Request",
Details: "No repo ID specified", Details: "No repo ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
pools, err := a.r.ListRepoPools(ctx, repoID) pools, err := a.r.ListRepoPools(ctx, repoID)
if err != nil { if err != nil {
log.Printf("listing pools: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pools); err != nil { if err := json.NewEncoder(w).Encode(pools); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route GET /repositories/{repoID}/scalesets repositories scalesets ListRepoScaleSets
//
// List repository scale sets.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: ScaleSets
// default: APIErrorResponse
func (a *APIController) ListRepoScaleSetsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
repoID, ok := vars["repoID"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No repo ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
scaleSets, err := a.r.ListEntityScaleSets(ctx, runnerParams.ForgeEntityTypeRepository, repoID)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing scale sets")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(scaleSets); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /repositories/{repoID}/pools/{poolID} repositories pools GetRepoPool
//
// Get repository pool by ID.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// + name: poolID
// description: Pool ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) GetRepoPoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) GetRepoPoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -230,24 +481,43 @@ func (a *APIController) GetRepoPoolHandler(w http.ResponseWriter, r *http.Reques
Error: "Bad Request", Error: "Bad Request",
Details: "No repo or pool ID specified", Details: "No repo or pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
pool, err := a.r.GetRepoPoolByID(ctx, repoID, poolID) pool, err := a.r.GetRepoPoolByID(ctx, repoID, poolID)
if err != nil { if err != nil {
log.Printf("listing pools: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
// swagger:route DELETE /repositories/{repoID}/pools/{poolID} repositories pools DeleteRepoPool
//
// Delete repository pool by ID.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// + name: poolID
// description: ID of the repository pool to delete.
// type: string
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteRepoPoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) DeleteRepoPoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -260,22 +530,47 @@ func (a *APIController) DeleteRepoPoolHandler(w http.ResponseWriter, r *http.Req
Error: "Bad Request", Error: "Bad Request",
Details: "No repo or pool ID specified", Details: "No repo or pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
if err := a.r.DeleteRepoPool(ctx, repoID, poolID); err != nil { if err := a.r.DeleteRepoPool(ctx, repoID, poolID); err != nil {
log.Printf("removing pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// swagger:route PUT /repositories/{repoID}/pools/{poolID} repositories pools UpdateRepoPool
//
// Update repository pool with the parameters given.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// + name: poolID
// description: ID of the repository pool to update.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when updating the repository pool.
// type: UpdatePoolParams
// in: body
// required: true
//
// Responses:
// 200: Pool
// default: APIErrorResponse
func (a *APIController) UpdateRepoPoolHandler(w http.ResponseWriter, r *http.Request) { func (a *APIController) UpdateRepoPoolHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -288,27 +583,166 @@ func (a *APIController) UpdateRepoPoolHandler(w http.ResponseWriter, r *http.Req
Error: "Bad Request", Error: "Bad Request",
Details: "No repo or pool ID specified", Details: "No repo or pool ID specified",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
var poolData runnerParams.UpdatePoolParams var poolData runnerParams.UpdatePoolParams
if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil { if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil {
log.Printf("failed to decode: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(w, gErrors.ErrBadRequest) handleError(ctx, w, gErrors.ErrBadRequest)
return return
} }
pool, err := a.r.UpdateRepoPool(ctx, repoID, poolID, poolData) pool, err := a.r.UpdateRepoPool(ctx, repoID, poolID, poolData)
if err != nil { if err != nil {
log.Printf("error creating repository pool: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "error creating repository pool")
handleError(w, err) handleError(ctx, w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(pool); err != nil { if err := json.NewEncoder(w).Encode(pool); err != nil {
log.Printf("failed to encode response: %q", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route POST /repositories/{repoID}/webhook repositories hooks InstallRepoWebhook
//
// Install the GARM webhook for an organization. The secret configured on the organization will
// be used to validate the requests.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters used when creating the repository webhook.
// type: InstallWebhookParams
// in: body
// required: true
//
// Responses:
// 200: HookInfo
// default: APIErrorResponse
func (a *APIController) InstallRepoWebhookHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
repoID, orgOk := vars["repoID"]
if !orgOk {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No repository ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
var hookParam runnerParams.InstallWebhookParams
if err := json.NewDecoder(r.Body).Decode(&hookParam); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
info, err := a.r.InstallRepoWebhook(ctx, repoID, hookParam)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "installing webhook")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(info); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route DELETE /repositories/{repoID}/webhook repositories hooks UninstallRepoWebhook
//
// Uninstall organization webhook.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) UninstallRepoWebhookHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
repoID, orgOk := vars["repoID"]
if !orgOk {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No repository ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
if err := a.r.UninstallRepoWebhook(ctx, repoID); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing webhook")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route GET /repositories/{repoID}/webhook repositories hooks GetRepoWebhookInfo
//
// Get information about the GARM installed webhook on a repository.
//
// Parameters:
// + name: repoID
// description: Repository ID.
// type: string
// in: path
// required: true
//
// Responses:
// 200: HookInfo
// default: APIErrorResponse
func (a *APIController) GetRepoWebhookInfoHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
repoID, orgOk := vars["repoID"]
if !orgOk {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No repository ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
info, err := a.r.GetRepoWebhookInfo(ctx, repoID)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "getting webhook info")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(info); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }

View file

@ -0,0 +1,211 @@
// 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 controllers
import (
"encoding/json"
"log/slog"
"net/http"
"strconv"
"github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
)
// swagger:route GET /scalesets scalesets ListScalesets
//
// List all scalesets.
//
// Responses:
// 200: ScaleSets
// default: APIErrorResponse
func (a *APIController) ListAllScaleSetsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
scalesets, err := a.r.ListAllScaleSets(ctx)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing scale sets")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(scalesets); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /scalesets/{scalesetID} scalesets GetScaleSet
//
// Get scale set by ID.
//
// Parameters:
// + name: scalesetID
// description: ID of the scale set to fetch.
// type: string
// in: path
// required: true
//
// Responses:
// 200: ScaleSet
// default: APIErrorResponse
func (a *APIController) GetScaleSetByIDHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
scaleSetID, ok := vars["scalesetID"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No scale set ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
id, err := strconv.ParseUint(scaleSetID, 10, 32)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
scaleSet, err := a.r.GetScaleSetByID(ctx, uint(id))
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "fetching scale set")
handleError(ctx, w, err)
return
}
scaleSet.RunnerBootstrapTimeout = scaleSet.RunnerTimeout()
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(scaleSet); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route DELETE /scalesets/{scalesetID} scalesets DeleteScaleSet
//
// Delete scale set by ID.
//
// Parameters:
// + name: scalesetID
// description: ID of the scale set to delete.
// type: string
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteScaleSetByIDHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
scalesetID, ok := vars["scalesetID"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No scale set ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
id, err := strconv.ParseUint(scalesetID, 10, 32)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
if err := a.r.DeleteScaleSetByID(ctx, uint(id)); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "removing scale set")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route PUT /scalesets/{scalesetID} scalesets UpdateScaleSet
//
// Update scale set by ID.
//
// Parameters:
// + name: scalesetID
// description: ID of the scale set to update.
// type: string
// in: path
// required: true
//
// + name: Body
// description: Parameters to update the scale set with.
// type: UpdateScaleSetParams
// in: body
// required: true
//
// Responses:
// 200: ScaleSet
// default: APIErrorResponse
func (a *APIController) UpdateScaleSetByIDHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
scalesetID, ok := vars["scalesetID"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Bad Request",
Details: "No scale set ID specified",
}); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
id, err := strconv.ParseUint(scalesetID, 10, 32)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
var scaleSetData runnerParams.UpdateScaleSetParams
if err := json.NewDecoder(r.Body).Decode(&scaleSetData); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}
scaleSet, err := a.r.UpdateScaleSetByID(ctx, uint(id), scaleSetData)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "updating scale set")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(scaleSet); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}

View file

@ -14,6 +14,7 @@
package params package params
// swagger:model APIErrorResponse
// APIErrorResponse holds information about an error, returned by the API // APIErrorResponse holds information about an error, returned by the API
type APIErrorResponse struct { type APIErrorResponse struct {
Error string `json:"error"` Error string `json:"error"`
@ -36,4 +37,9 @@ var (
Error: "init_required", Error: "init_required",
Details: "Missing superuser", Details: "Missing superuser",
} }
// URLsRequired is returned if the controller does not have the required URLs
URLsRequired = APIErrorResponse{
Error: "urls_required",
Details: "Missing required URLs. Make sure you update the metadata and callback URLs",
}
) )

View file

@ -12,18 +12,53 @@
// License for the specific language governing permissions and limitations // License for the specific language governing permissions and limitations
// under the License. // under the License.
// Package routers Garm API.
//
// The Garm API generated using go-swagger.
//
// BasePath: /api/v1
// Version: 1.0.0
// License: Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// Security:
// - Bearer:
//
// SecurityDefinitions:
// Bearer:
// type: apiKey
// name: Authorization
// in: header
// description: >-
// The token with the `Bearer: ` prefix, e.g. "Bearer abcde12345".
//
// swagger:meta
package routers package routers
import ( //go:generate go run github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 generate spec --input=../swagger-models.yaml --output=../swagger.yaml --include="routers|controllers"
"io" //go:generate go run github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 validate ../swagger.yaml
"net/http" //go:generate rm -rf ../../client
//go:generate go run github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 generate client --target=../../ --spec=../swagger.yaml
import (
_ "expvar" // Register the expvar handlers
"log/slog"
"net/http"
_ "net/http/pprof" //nolint:golangci-lint,gosec // Register the pprof handlers
"github.com/felixge/httpsnoop"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/cloudbase/garm/apiserver/controllers" "github.com/cloudbase/garm/apiserver/controllers"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/util" "github.com/cloudbase/garm/config"
spaAssets "github.com/cloudbase/garm/webapp/assets"
) )
func WithMetricsRouter(parentRouter *mux.Router, disableAuth bool, metricsMiddlerware auth.Middleware) *mux.Router { func WithMetricsRouter(parentRouter *mux.Router, disableAuth bool, metricsMiddlerware auth.Middleware) *mux.Router {
@ -40,15 +75,67 @@ func WithMetricsRouter(parentRouter *mux.Router, disableAuth bool, metricsMiddle
return parentRouter return parentRouter
} }
func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddleware, initMiddleware, instanceMiddleware auth.Middleware) *mux.Router { func WithDebugServer(parentRouter *mux.Router) *mux.Router {
if parentRouter == nil {
return nil
}
parentRouter.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux)
return parentRouter
}
func WithWebUI(parentRouter *mux.Router, apiConfig config.APIServer) *mux.Router {
if parentRouter == nil {
return nil
}
if apiConfig.WebUI.EnableWebUI {
slog.Info("WebUI is enabled, adding webapp routes")
webappPath := apiConfig.WebUI.GetWebappPath()
slog.Info("Using webapp path", "path", webappPath)
// Accessing / should redirect to the UI
parentRouter.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, webappPath, http.StatusMovedPermanently) // 301
})
// Serve the SPA with dynamic path
parentRouter.PathPrefix(webappPath).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
spaAssets.ServeSPAWithPath(w, r, webappPath)
}).Methods("GET")
} else {
slog.Info("WebUI is disabled, skipping webapp routes")
}
return parentRouter
}
func requestLogger(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// gathers metrics from the upstream handlers
metrics := httpsnoop.CaptureMetrics(h, w, r)
slog.Info(
"access_log",
slog.String("method", r.Method),
slog.String("uri", r.URL.RequestURI()),
slog.String("user_agent", r.Header.Get("User-Agent")),
slog.String("ip", r.RemoteAddr),
slog.Int("code", metrics.Code),
slog.Int64("bytes", metrics.Written),
slog.Duration("request_time", metrics.Duration),
)
})
}
func NewAPIRouter(han *controllers.APIController, authMiddleware, initMiddleware, urlsRequiredMiddleware, instanceMiddleware auth.Middleware, manageWebhooks bool) *mux.Router {
router := mux.NewRouter() router := mux.NewRouter()
logMiddleware := util.NewLoggingMiddleware(logWriter) router.Use(requestLogger)
router.Use(logMiddleware)
// Handles github webhooks // Handles github webhooks
webhookRouter := router.PathPrefix("/webhooks").Subrouter() webhookRouter := router.PathPrefix("/webhooks").Subrouter()
webhookRouter.PathPrefix("/").Handler(http.HandlerFunc(han.CatchAll)) webhookRouter.Handle("/", http.HandlerFunc(han.WebhookHandler))
webhookRouter.PathPrefix("").Handler(http.HandlerFunc(han.CatchAll)) webhookRouter.Handle("", http.HandlerFunc(han.WebhookHandler))
webhookRouter.Handle("/{controllerID}/", http.HandlerFunc(han.WebhookHandler))
webhookRouter.Handle("/{controllerID}", http.HandlerFunc(han.WebhookHandler))
// Handles API calls // Handles API calls
apiSubRouter := router.PathPrefix("/api/v1").Subrouter() apiSubRouter := router.PathPrefix("/api/v1").Subrouter()
@ -56,30 +143,84 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
// FirstRunHandler // FirstRunHandler
firstRunRouter := apiSubRouter.PathPrefix("/first-run").Subrouter() firstRunRouter := apiSubRouter.PathPrefix("/first-run").Subrouter()
firstRunRouter.Handle("/", http.HandlerFunc(han.FirstRunHandler)).Methods("POST", "OPTIONS") firstRunRouter.Handle("/", http.HandlerFunc(han.FirstRunHandler)).Methods("POST", "OPTIONS")
firstRunRouter.Handle("", http.HandlerFunc(han.FirstRunHandler)).Methods("POST", "OPTIONS")
// Instance URLs // Instance URLs
callbackRouter := apiSubRouter.PathPrefix("/callbacks").Subrouter() callbackRouter := apiSubRouter.PathPrefix("/callbacks").Subrouter()
callbackRouter.Handle("/status/", http.HandlerFunc(han.InstanceStatusMessageHandler)).Methods("POST", "OPTIONS") callbackRouter.Handle("/status/", http.HandlerFunc(han.InstanceStatusMessageHandler)).Methods("POST", "OPTIONS")
callbackRouter.Handle("/status", http.HandlerFunc(han.InstanceStatusMessageHandler)).Methods("POST", "OPTIONS") callbackRouter.Handle("/status", http.HandlerFunc(han.InstanceStatusMessageHandler)).Methods("POST", "OPTIONS")
callbackRouter.Handle("/system-info/", http.HandlerFunc(han.InstanceSystemInfoHandler)).Methods("POST", "OPTIONS")
callbackRouter.Handle("/system-info", http.HandlerFunc(han.InstanceSystemInfoHandler)).Methods("POST", "OPTIONS")
callbackRouter.Use(instanceMiddleware.Middleware) callbackRouter.Use(instanceMiddleware.Middleware)
///////////////////
// Metadata URLs //
///////////////////
metadataRouter := apiSubRouter.PathPrefix("/metadata").Subrouter() metadataRouter := apiSubRouter.PathPrefix("/metadata").Subrouter()
metadataRouter.Use(instanceMiddleware.Middleware)
// Registration token
metadataRouter.Handle("/runner-registration-token/", http.HandlerFunc(han.InstanceGithubRegistrationTokenHandler)).Methods("GET", "OPTIONS") metadataRouter.Handle("/runner-registration-token/", http.HandlerFunc(han.InstanceGithubRegistrationTokenHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/runner-registration-token", http.HandlerFunc(han.InstanceGithubRegistrationTokenHandler)).Methods("GET", "OPTIONS") metadataRouter.Handle("/runner-registration-token", http.HandlerFunc(han.InstanceGithubRegistrationTokenHandler)).Methods("GET", "OPTIONS")
metadataRouter.Use(instanceMiddleware.Middleware) // JIT credential files
metadataRouter.Handle("/credentials/{fileName}/", http.HandlerFunc(han.JITCredentialsFileHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/credentials/{fileName}", http.HandlerFunc(han.JITCredentialsFileHandler)).Methods("GET", "OPTIONS")
// Systemd files
metadataRouter.Handle("/system/service-name/", http.HandlerFunc(han.SystemdServiceNameHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/system/service-name", http.HandlerFunc(han.SystemdServiceNameHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/systemd/unit-file/", http.HandlerFunc(han.SystemdUnitFileHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/systemd/unit-file", http.HandlerFunc(han.SystemdUnitFileHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/system/cert-bundle/", http.HandlerFunc(han.RootCertificateBundleHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/system/cert-bundle", http.HandlerFunc(han.RootCertificateBundleHandler)).Methods("GET", "OPTIONS")
// Login // Login
authRouter := apiSubRouter.PathPrefix("/auth").Subrouter() authRouter := apiSubRouter.PathPrefix("/auth").Subrouter()
authRouter.Handle("/{login:login\\/?}", http.HandlerFunc(han.LoginHandler)).Methods("POST", "OPTIONS") authRouter.Handle("/{login:login\\/?}", http.HandlerFunc(han.LoginHandler)).Methods("POST", "OPTIONS")
authRouter.Use(initMiddleware.Middleware) authRouter.Use(initMiddleware.Middleware)
//////////////////////////
// Controller endpoints //
//////////////////////////
controllerRouter := apiSubRouter.PathPrefix("/controller").Subrouter()
// The controller endpoints allow us to get information about the controller and update the URL endpoints.
// This endpoint must not be guarded by the urlsRequiredMiddleware as that would prevent the user from
// updating the URLs.
controllerRouter.Use(initMiddleware.Middleware)
controllerRouter.Use(authMiddleware.Middleware)
controllerRouter.Use(auth.AdminRequiredMiddleware)
// Get controller info
controllerRouter.Handle("/", http.HandlerFunc(han.ControllerInfoHandler)).Methods("GET", "OPTIONS")
controllerRouter.Handle("", http.HandlerFunc(han.ControllerInfoHandler)).Methods("GET", "OPTIONS")
// Update controller
controllerRouter.Handle("/", http.HandlerFunc(han.UpdateControllerHandler)).Methods("PUT", "OPTIONS")
controllerRouter.Handle("", http.HandlerFunc(han.UpdateControllerHandler)).Methods("PUT", "OPTIONS")
////////////////////////////////////
// API router for everything else //
////////////////////////////////////
apiRouter := apiSubRouter.PathPrefix("").Subrouter() apiRouter := apiSubRouter.PathPrefix("").Subrouter()
apiRouter.Use(initMiddleware.Middleware) apiRouter.Use(initMiddleware.Middleware)
// all endpoints except the controller endpoint should return an error
// if the required metadata, callback and webhook URLs are not set.
apiRouter.Use(urlsRequiredMiddleware.Middleware)
apiRouter.Use(authMiddleware.Middleware) apiRouter.Use(authMiddleware.Middleware)
apiRouter.Use(auth.AdminRequiredMiddleware)
// Legacy controller path
apiRouter.Handle("/controller-info/", http.HandlerFunc(han.ControllerInfoHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/controller-info", http.HandlerFunc(han.ControllerInfoHandler)).Methods("GET", "OPTIONS")
// Metrics Token // Metrics Token
apiRouter.Handle("/metrics-token/", http.HandlerFunc(han.MetricsTokenHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/metrics-token/", http.HandlerFunc(han.MetricsTokenHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/metrics-token", http.HandlerFunc(han.MetricsTokenHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/metrics-token", http.HandlerFunc(han.MetricsTokenHandler)).Methods("GET", "OPTIONS")
//////////
// Jobs //
//////////
// List all jobs
apiRouter.Handle("/jobs/", http.HandlerFunc(han.ListAllJobs)).Methods("GET", "OPTIONS")
apiRouter.Handle("/jobs", http.HandlerFunc(han.ListAllJobs)).Methods("GET", "OPTIONS")
/////////// ///////////
// Pools // // Pools //
/////////// ///////////
@ -99,6 +240,25 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
apiRouter.Handle("/pools/{poolID}/instances/", http.HandlerFunc(han.ListPoolInstancesHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/pools/{poolID}/instances/", http.HandlerFunc(han.ListPoolInstancesHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/pools/{poolID}/instances", http.HandlerFunc(han.ListPoolInstancesHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/pools/{poolID}/instances", http.HandlerFunc(han.ListPoolInstancesHandler)).Methods("GET", "OPTIONS")
////////////////
// Scale sets //
////////////////
// List all pools
apiRouter.Handle("/scalesets/", http.HandlerFunc(han.ListAllScaleSetsHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/scalesets", http.HandlerFunc(han.ListAllScaleSetsHandler)).Methods("GET", "OPTIONS")
// Get one pool
apiRouter.Handle("/scalesets/{scalesetID}/", http.HandlerFunc(han.GetScaleSetByIDHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/scalesets/{scalesetID}", http.HandlerFunc(han.GetScaleSetByIDHandler)).Methods("GET", "OPTIONS")
// Delete one pool
apiRouter.Handle("/scalesets/{scalesetID}/", http.HandlerFunc(han.DeleteScaleSetByIDHandler)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/scalesets/{scalesetID}", http.HandlerFunc(han.DeleteScaleSetByIDHandler)).Methods("DELETE", "OPTIONS")
// Update one pool
apiRouter.Handle("/scalesets/{scalesetID}/", http.HandlerFunc(han.UpdateScaleSetByIDHandler)).Methods("PUT", "OPTIONS")
apiRouter.Handle("/scalesets/{scalesetID}", http.HandlerFunc(han.UpdateScaleSetByIDHandler)).Methods("PUT", "OPTIONS")
// List pool instances
apiRouter.Handle("/scalesets/{scalesetID}/instances/", http.HandlerFunc(han.ListScaleSetInstancesHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/scalesets/{scalesetID}/instances", http.HandlerFunc(han.ListScaleSetInstancesHandler)).Methods("GET", "OPTIONS")
///////////// /////////////
// Runners // // Runners //
///////////// /////////////
@ -131,6 +291,14 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
apiRouter.Handle("/repositories/{repoID}/pools/", http.HandlerFunc(han.CreateRepoPoolHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/repositories/{repoID}/pools/", http.HandlerFunc(han.CreateRepoPoolHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/pools", http.HandlerFunc(han.CreateRepoPoolHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/repositories/{repoID}/pools", http.HandlerFunc(han.CreateRepoPoolHandler)).Methods("POST", "OPTIONS")
// Create scale set
apiRouter.Handle("/repositories/{repoID}/scalesets/", http.HandlerFunc(han.CreateRepoScaleSetHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/scalesets", http.HandlerFunc(han.CreateRepoScaleSetHandler)).Methods("POST", "OPTIONS")
// List scale sets
apiRouter.Handle("/repositories/{repoID}/scalesets/", http.HandlerFunc(han.ListRepoScaleSetsHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/scalesets", http.HandlerFunc(han.ListRepoScaleSetsHandler)).Methods("GET", "OPTIONS")
// Repo instances list // Repo instances list
apiRouter.Handle("/repositories/{repoID}/instances/", http.HandlerFunc(han.ListRepoInstancesHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/repositories/{repoID}/instances/", http.HandlerFunc(han.ListRepoInstancesHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/instances", http.HandlerFunc(han.ListRepoInstancesHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/repositories/{repoID}/instances", http.HandlerFunc(han.ListRepoInstancesHandler)).Methods("GET", "OPTIONS")
@ -151,6 +319,17 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
apiRouter.Handle("/repositories/", http.HandlerFunc(han.CreateRepoHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/repositories/", http.HandlerFunc(han.CreateRepoHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/repositories", http.HandlerFunc(han.CreateRepoHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/repositories", http.HandlerFunc(han.CreateRepoHandler)).Methods("POST", "OPTIONS")
if manageWebhooks {
// Install Webhook
apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.InstallRepoWebhookHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.InstallRepoWebhookHandler)).Methods("POST", "OPTIONS")
// Uninstall Webhook
apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.UninstallRepoWebhookHandler)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.UninstallRepoWebhookHandler)).Methods("DELETE", "OPTIONS")
// Get webhook info
apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.GetRepoWebhookInfoHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.GetRepoWebhookInfoHandler)).Methods("GET", "OPTIONS")
}
///////////////////////////// /////////////////////////////
// Organizations and pools // // Organizations and pools //
///////////////////////////// /////////////////////////////
@ -170,7 +349,15 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
apiRouter.Handle("/organizations/{orgID}/pools/", http.HandlerFunc(han.CreateOrgPoolHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/organizations/{orgID}/pools/", http.HandlerFunc(han.CreateOrgPoolHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/pools", http.HandlerFunc(han.CreateOrgPoolHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/organizations/{orgID}/pools", http.HandlerFunc(han.CreateOrgPoolHandler)).Methods("POST", "OPTIONS")
// Repo instances list // Create org scale set
apiRouter.Handle("/organizations/{orgID}/scalesets/", http.HandlerFunc(han.CreateOrgScaleSetHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/scalesets", http.HandlerFunc(han.CreateOrgScaleSetHandler)).Methods("POST", "OPTIONS")
// List org scale sets
apiRouter.Handle("/organizations/{orgID}/scalesets/", http.HandlerFunc(han.ListOrgScaleSetsHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/scalesets", http.HandlerFunc(han.ListOrgScaleSetsHandler)).Methods("GET", "OPTIONS")
// Org instances list
apiRouter.Handle("/organizations/{orgID}/instances/", http.HandlerFunc(han.ListOrgInstancesHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/organizations/{orgID}/instances/", http.HandlerFunc(han.ListOrgInstancesHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/instances", http.HandlerFunc(han.ListOrgInstancesHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/organizations/{orgID}/instances", http.HandlerFunc(han.ListOrgInstancesHandler)).Methods("GET", "OPTIONS")
@ -190,6 +377,17 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
apiRouter.Handle("/organizations/", http.HandlerFunc(han.CreateOrgHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/organizations/", http.HandlerFunc(han.CreateOrgHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/organizations", http.HandlerFunc(han.CreateOrgHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/organizations", http.HandlerFunc(han.CreateOrgHandler)).Methods("POST", "OPTIONS")
if manageWebhooks {
// Install Webhook
apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.InstallOrgWebhookHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.InstallOrgWebhookHandler)).Methods("POST", "OPTIONS")
// Uninstall Webhook
apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.UninstallOrgWebhookHandler)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.UninstallOrgWebhookHandler)).Methods("DELETE", "OPTIONS")
// Get webhook info
apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.GetOrgWebhookInfoHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.GetOrgWebhookInfoHandler)).Methods("GET", "OPTIONS")
}
///////////////////////////// /////////////////////////////
// Enterprises and pools // // Enterprises and pools //
///////////////////////////// /////////////////////////////
@ -209,33 +407,131 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
apiRouter.Handle("/enterprises/{enterpriseID}/pools/", http.HandlerFunc(han.CreateEnterprisePoolHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/enterprises/{enterpriseID}/pools/", http.HandlerFunc(han.CreateEnterprisePoolHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/enterprises/{enterpriseID}/pools", http.HandlerFunc(han.CreateEnterprisePoolHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/enterprises/{enterpriseID}/pools", http.HandlerFunc(han.CreateEnterprisePoolHandler)).Methods("POST", "OPTIONS")
// Repo instances list // Create enterprise scale sets
apiRouter.Handle("/enterprises/{enterpriseID}/scalesets/", http.HandlerFunc(han.CreateEnterpriseScaleSetHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/enterprises/{enterpriseID}/scalesets", http.HandlerFunc(han.CreateEnterpriseScaleSetHandler)).Methods("POST", "OPTIONS")
// List enterprise scale sets
apiRouter.Handle("/enterprises/{enterpriseID}/scalesets/", http.HandlerFunc(han.ListEnterpriseScaleSetsHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/enterprises/{enterpriseID}/scalesets", http.HandlerFunc(han.ListEnterpriseScaleSetsHandler)).Methods("GET", "OPTIONS")
// Enterprise instances list
apiRouter.Handle("/enterprises/{enterpriseID}/instances/", http.HandlerFunc(han.ListEnterpriseInstancesHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/enterprises/{enterpriseID}/instances/", http.HandlerFunc(han.ListEnterpriseInstancesHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/enterprises/{enterpriseID}/instances", http.HandlerFunc(han.ListEnterpriseInstancesHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/enterprises/{enterpriseID}/instances", http.HandlerFunc(han.ListEnterpriseInstancesHandler)).Methods("GET", "OPTIONS")
// Get org // Get enterprise
apiRouter.Handle("/enterprises/{enterpriseID}/", http.HandlerFunc(han.GetEnterpriseByIDHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/enterprises/{enterpriseID}/", http.HandlerFunc(han.GetEnterpriseByIDHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/enterprises/{enterpriseID}", http.HandlerFunc(han.GetEnterpriseByIDHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/enterprises/{enterpriseID}", http.HandlerFunc(han.GetEnterpriseByIDHandler)).Methods("GET", "OPTIONS")
// Update org // Update enterprise
apiRouter.Handle("/enterprises/{enterpriseID}/", http.HandlerFunc(han.UpdateEnterpriseHandler)).Methods("PUT", "OPTIONS") apiRouter.Handle("/enterprises/{enterpriseID}/", http.HandlerFunc(han.UpdateEnterpriseHandler)).Methods("PUT", "OPTIONS")
apiRouter.Handle("/enterprises/{enterpriseID}", http.HandlerFunc(han.UpdateEnterpriseHandler)).Methods("PUT", "OPTIONS") apiRouter.Handle("/enterprises/{enterpriseID}", http.HandlerFunc(han.UpdateEnterpriseHandler)).Methods("PUT", "OPTIONS")
// Delete org // Delete enterprise
apiRouter.Handle("/enterprises/{enterpriseID}/", http.HandlerFunc(han.DeleteEnterpriseHandler)).Methods("DELETE", "OPTIONS") apiRouter.Handle("/enterprises/{enterpriseID}/", http.HandlerFunc(han.DeleteEnterpriseHandler)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/enterprises/{enterpriseID}", http.HandlerFunc(han.DeleteEnterpriseHandler)).Methods("DELETE", "OPTIONS") apiRouter.Handle("/enterprises/{enterpriseID}", http.HandlerFunc(han.DeleteEnterpriseHandler)).Methods("DELETE", "OPTIONS")
// List orgs // List enterprises
apiRouter.Handle("/enterprises/", http.HandlerFunc(han.ListEnterprisesHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/enterprises/", http.HandlerFunc(han.ListEnterprisesHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/enterprises", http.HandlerFunc(han.ListEnterprisesHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/enterprises", http.HandlerFunc(han.ListEnterprisesHandler)).Methods("GET", "OPTIONS")
// Create org // Create enterprise
apiRouter.Handle("/enterprises/", http.HandlerFunc(han.CreateEnterpriseHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/enterprises/", http.HandlerFunc(han.CreateEnterpriseHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/enterprises", http.HandlerFunc(han.CreateEnterpriseHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/enterprises", http.HandlerFunc(han.CreateEnterpriseHandler)).Methods("POST", "OPTIONS")
// Credentials and providers // Providers
apiRouter.Handle("/credentials/", http.HandlerFunc(han.ListCredentials)).Methods("GET", "OPTIONS")
apiRouter.Handle("/credentials", http.HandlerFunc(han.ListCredentials)).Methods("GET", "OPTIONS")
apiRouter.Handle("/providers/", http.HandlerFunc(han.ListProviders)).Methods("GET", "OPTIONS") apiRouter.Handle("/providers/", http.HandlerFunc(han.ListProviders)).Methods("GET", "OPTIONS")
apiRouter.Handle("/providers", http.HandlerFunc(han.ListProviders)).Methods("GET", "OPTIONS") apiRouter.Handle("/providers", http.HandlerFunc(han.ListProviders)).Methods("GET", "OPTIONS")
// Websocket log writer //////////////////////
apiRouter.Handle("/{ws:ws\\/?}", http.HandlerFunc(han.WSHandler)).Methods("GET") // Github Endpoints //
//////////////////////
// Create Github Endpoint
apiRouter.Handle("/github/endpoints/", http.HandlerFunc(han.CreateGithubEndpoint)).Methods("POST", "OPTIONS")
apiRouter.Handle("/github/endpoints", http.HandlerFunc(han.CreateGithubEndpoint)).Methods("POST", "OPTIONS")
// List Github Endpoints
apiRouter.Handle("/github/endpoints/", http.HandlerFunc(han.ListGithubEndpoints)).Methods("GET", "OPTIONS")
apiRouter.Handle("/github/endpoints", http.HandlerFunc(han.ListGithubEndpoints)).Methods("GET", "OPTIONS")
// Get Github Endpoint
apiRouter.Handle("/github/endpoints/{name}/", http.HandlerFunc(han.GetGithubEndpoint)).Methods("GET", "OPTIONS")
apiRouter.Handle("/github/endpoints/{name}", http.HandlerFunc(han.GetGithubEndpoint)).Methods("GET", "OPTIONS")
// Delete Github Endpoint
apiRouter.Handle("/github/endpoints/{name}/", http.HandlerFunc(han.DeleteGithubEndpoint)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/github/endpoints/{name}", http.HandlerFunc(han.DeleteGithubEndpoint)).Methods("DELETE", "OPTIONS")
// Update Github Endpoint
apiRouter.Handle("/github/endpoints/{name}/", http.HandlerFunc(han.UpdateGithubEndpoint)).Methods("PUT", "OPTIONS")
apiRouter.Handle("/github/endpoints/{name}", http.HandlerFunc(han.UpdateGithubEndpoint)).Methods("PUT", "OPTIONS")
////////////////////////
// Github credentials //
////////////////////////
// Legacy credentials path
apiRouter.Handle("/credentials/", http.HandlerFunc(han.ListCredentials)).Methods("GET", "OPTIONS")
apiRouter.Handle("/credentials", http.HandlerFunc(han.ListCredentials)).Methods("GET", "OPTIONS")
// List Github Credentials
apiRouter.Handle("/github/credentials/", http.HandlerFunc(han.ListCredentials)).Methods("GET", "OPTIONS")
apiRouter.Handle("/github/credentials", http.HandlerFunc(han.ListCredentials)).Methods("GET", "OPTIONS")
// Create Github Credentials
apiRouter.Handle("/github/credentials/", http.HandlerFunc(han.CreateGithubCredential)).Methods("POST", "OPTIONS")
apiRouter.Handle("/github/credentials", http.HandlerFunc(han.CreateGithubCredential)).Methods("POST", "OPTIONS")
// Get Github Credential
apiRouter.Handle("/github/credentials/{id}/", http.HandlerFunc(han.GetGithubCredential)).Methods("GET", "OPTIONS")
apiRouter.Handle("/github/credentials/{id}", http.HandlerFunc(han.GetGithubCredential)).Methods("GET", "OPTIONS")
// Delete Github Credential
apiRouter.Handle("/github/credentials/{id}/", http.HandlerFunc(han.DeleteGithubCredential)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/github/credentials/{id}", http.HandlerFunc(han.DeleteGithubCredential)).Methods("DELETE", "OPTIONS")
// Update Github Credential
apiRouter.Handle("/github/credentials/{id}/", http.HandlerFunc(han.UpdateGithubCredential)).Methods("PUT", "OPTIONS")
apiRouter.Handle("/github/credentials/{id}", http.HandlerFunc(han.UpdateGithubCredential)).Methods("PUT", "OPTIONS")
//////////////////////
// Gitea Endpoints //
//////////////////////
// Create Gitea Endpoint
apiRouter.Handle("/gitea/endpoints/", http.HandlerFunc(han.CreateGiteaEndpoint)).Methods("POST", "OPTIONS")
apiRouter.Handle("/gitea/endpoints", http.HandlerFunc(han.CreateGiteaEndpoint)).Methods("POST", "OPTIONS")
// List Gitea Endpoints
apiRouter.Handle("/gitea/endpoints/", http.HandlerFunc(han.ListGiteaEndpoints)).Methods("GET", "OPTIONS")
apiRouter.Handle("/gitea/endpoints", http.HandlerFunc(han.ListGiteaEndpoints)).Methods("GET", "OPTIONS")
// Get Gitea Endpoint
apiRouter.Handle("/gitea/endpoints/{name}/", http.HandlerFunc(han.GetGiteaEndpoint)).Methods("GET", "OPTIONS")
apiRouter.Handle("/gitea/endpoints/{name}", http.HandlerFunc(han.GetGiteaEndpoint)).Methods("GET", "OPTIONS")
// Delete Gitea Endpoint
apiRouter.Handle("/gitea/endpoints/{name}/", http.HandlerFunc(han.DeleteGiteaEndpoint)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/gitea/endpoints/{name}", http.HandlerFunc(han.DeleteGiteaEndpoint)).Methods("DELETE", "OPTIONS")
// Update Gitea Endpoint
apiRouter.Handle("/gitea/endpoints/{name}/", http.HandlerFunc(han.UpdateGiteaEndpoint)).Methods("PUT", "OPTIONS")
apiRouter.Handle("/gitea/endpoints/{name}", http.HandlerFunc(han.UpdateGiteaEndpoint)).Methods("PUT", "OPTIONS")
////////////////////////
// Gitea credentials //
////////////////////////
// List Gitea Credentials
apiRouter.Handle("/gitea/credentials/", http.HandlerFunc(han.ListGiteaCredentials)).Methods("GET", "OPTIONS")
apiRouter.Handle("/gitea/credentials", http.HandlerFunc(han.ListGiteaCredentials)).Methods("GET", "OPTIONS")
// Create Gitea Credentials
apiRouter.Handle("/gitea/credentials/", http.HandlerFunc(han.CreateGiteaCredential)).Methods("POST", "OPTIONS")
apiRouter.Handle("/gitea/credentials", http.HandlerFunc(han.CreateGiteaCredential)).Methods("POST", "OPTIONS")
// Get Gitea Credential
apiRouter.Handle("/gitea/credentials/{id}/", http.HandlerFunc(han.GetGiteaCredential)).Methods("GET", "OPTIONS")
apiRouter.Handle("/gitea/credentials/{id}", http.HandlerFunc(han.GetGiteaCredential)).Methods("GET", "OPTIONS")
// Delete Gitea Credential
apiRouter.Handle("/gitea/credentials/{id}/", http.HandlerFunc(han.DeleteGiteaCredential)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/gitea/credentials/{id}", http.HandlerFunc(han.DeleteGiteaCredential)).Methods("DELETE", "OPTIONS")
// Update Gitea Credential
apiRouter.Handle("/gitea/credentials/{id}/", http.HandlerFunc(han.UpdateGiteaCredential)).Methods("PUT", "OPTIONS")
apiRouter.Handle("/gitea/credentials/{id}", http.HandlerFunc(han.UpdateGiteaCredential)).Methods("PUT", "OPTIONS")
/////////////////////////
// Websocket endpoints //
/////////////////////////
// Legacy log websocket path
apiRouter.Handle("/ws/", http.HandlerFunc(han.WSHandler)).Methods("GET")
apiRouter.Handle("/ws", http.HandlerFunc(han.WSHandler)).Methods("GET")
// Log websocket endpoint
apiRouter.Handle("/ws/logs/", http.HandlerFunc(han.WSHandler)).Methods("GET")
apiRouter.Handle("/ws/logs", http.HandlerFunc(han.WSHandler)).Methods("GET")
// DB watcher websocket endpoint
apiRouter.Handle("/ws/events/", http.HandlerFunc(han.EventsHandler)).Methods("GET")
apiRouter.Handle("/ws/events", http.HandlerFunc(han.EventsHandler)).Methods("GET")
// NotFound handler - this should be last
apiRouter.PathPrefix("/").HandlerFunc(han.NotFoundHandler).Methods("GET", "POST", "PUT", "DELETE", "OPTIONS")
return router return router
} }

View file

@ -0,0 +1,345 @@
# NOTE: The purpose of these definitions is to reuse the existing golang
# types from GARM packages.
definitions:
User:
type: object
x-go-type:
type: User
import:
package: github.com/cloudbase/garm/params
alias: garm_params
HookInfo:
type: object
x-go-type:
type: HookInfo
import:
package: github.com/cloudbase/garm/params
alias: garm_params
ControllerInfo:
type: object
x-go-type:
type: ControllerInfo
import:
package: github.com/cloudbase/garm/params
alias: garm_params
InstallWebhookParams:
type: object
x-go-type:
type: InstallWebhookParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
NewUserParams:
type: object
x-go-type:
type: NewUserParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
PasswordLoginParams:
type: object
x-go-type:
type: PasswordLoginParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
JWTResponse:
type: object
x-go-type:
type: JWTResponse
import:
package: github.com/cloudbase/garm/params
alias: garm_params
Jobs:
type: array
x-go-type:
type: Jobs
import:
package: github.com/cloudbase/garm/params
alias: garm_params
items:
$ref: '#/definitions/Job'
Job:
type: object
x-go-type:
type: Job
import:
package: github.com/cloudbase/garm/params
alias: garm_params
Credentials:
type: array
x-go-type:
type: Credentials
import:
package: github.com/cloudbase/garm/params
alias: garm_params
items:
$ref: '#/definitions/ForgeCredentials'
ForgeCredentials:
type: object
x-go-type:
type: ForgeCredentials
import:
package: github.com/cloudbase/garm/params
alias: garm_params
Providers:
type: array
x-go-type:
type: Providers
import:
package: github.com/cloudbase/garm/params
alias: garm_params
items:
$ref: '#/definitions/Provider'
Provider:
type: object
x-go-type:
type: Provider
import:
package: github.com/cloudbase/garm/params
alias: garm_params
Instances:
type: array
x-go-type:
type: Instances
import:
package: github.com/cloudbase/garm/params
alias: garm_params
items:
$ref: '#/definitions/Instance'
Instance:
type: object
x-go-type:
type: Instance
import:
package: github.com/cloudbase/garm/params
alias: garm_params
Pools:
type: array
x-go-type:
type: Pools
import:
package: github.com/cloudbase/garm/params
alias: garm_params
items:
$ref: '#/definitions/Pool'
Pool:
type: object
x-go-type:
type: Pool
import:
package: github.com/cloudbase/garm/params
alias: garm_params
ScaleSets:
type: array
x-go-type:
type: ScaleSets
import:
package: github.com/cloudbase/garm/params
alias: garm_params
items:
$ref: '#/definitions/ScaleSet'
ScaleSet:
type: object
x-go-type:
type: ScaleSet
import:
package: github.com/cloudbase/garm/params
alias: garm_params
Repositories:
type: array
x-go-type:
type: Repositories
import:
package: github.com/cloudbase/garm/params
alias: garm_params
items:
$ref: '#/definitions/Repository'
Repository:
type: object
x-go-type:
type: Repository
import:
package: github.com/cloudbase/garm/params
alias: garm_params
CreateRepoParams:
type: object
x-go-type:
type: CreateRepoParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
Organizations:
type: array
x-go-type:
type: Organizations
import:
package: github.com/cloudbase/garm/params
alias: garm_params
items:
$ref: '#/definitions/Organization'
Organization:
type: object
x-go-type:
type: Organization
import:
package: github.com/cloudbase/garm/params
alias: garm_params
CreateOrgParams:
type: object
x-go-type:
type: CreateOrgParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
Enterprises:
type: array
x-go-type:
type: Enterprises
import:
package: github.com/cloudbase/garm/params
alias: garm_params
items:
$ref: '#/definitions/Enterprise'
Enterprise:
type: object
x-go-type:
type: Enterprise
import:
package: github.com/cloudbase/garm/params
alias: garm_params
CreateEnterpriseParams:
type: object
x-go-type:
type: CreateEnterpriseParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
UpdateEntityParams:
type: object
x-go-type:
type: UpdateEntityParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
CreatePoolParams:
type: object
x-go-type:
type: CreatePoolParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
CreateScaleSetParams:
type: object
x-go-type:
type: CreateScaleSetParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
UpdatePoolParams:
type: object
x-go-type:
type: UpdatePoolParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
UpdateScaleSetParams:
type: object
x-go-type:
type: UpdateScaleSetParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
APIErrorResponse:
type: object
x-go-type:
type: APIErrorResponse
import:
package: github.com/cloudbase/garm/apiserver/params
alias: apiserver_params
CreateInstanceParams:
type: object
x-go-type:
type: CreateInstanceParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
UpdateGithubEndpointParams:
type: object
x-go-type:
type: UpdateGithubEndpointParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
UpdateGiteaEndpointParams:
type: object
x-go-type:
type: UpdateGiteaEndpointParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
ForgeEndpoint:
type: object
x-go-type:
type: ForgeEndpoint
import:
package: github.com/cloudbase/garm/params
alias: garm_params
ForgeEndpoints:
type: array
x-go-type:
type: ForgeEndpoints
import:
package: github.com/cloudbase/garm/params
alias: garm_params
items:
$ref: '#/definitions/ForgeEndpoint'
CreateGithubEndpointParams:
type: object
x-go-type:
type: CreateGithubEndpointParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
CreateGiteaEndpointParams:
type: object
x-go-type:
type: CreateGiteaEndpointParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
CreateGithubCredentialsParams:
type: object
x-go-type:
type: CreateGithubCredentialsParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
CreateGiteaCredentialsParams:
type: object
x-go-type:
type: CreateGiteaCredentialsParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
UpdateGithubCredentialsParams:
type: object
x-go-type:
type: UpdateGithubCredentialsParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
UpdateGiteaCredentialsParams:
type: object
x-go-type:
type: UpdateGiteaCredentialsParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params
UpdateControllerParams:
type: object
x-go-type:
type: UpdateControllerParams
import:
package: github.com/cloudbase/garm/params
alias: garm_params

2280
apiserver/swagger.yaml Normal file

File diff suppressed because it is too large Load diff

27
auth/admin_required.go Normal file
View file

@ -0,0 +1,27 @@
// Copyright 2025 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 auth
import "net/http"
func AdminRequiredMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if !IsAdmin(ctx) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}

View file

@ -16,18 +16,19 @@ package auth
import ( import (
"context" "context"
"errors"
"fmt"
"time" "time"
jwt "github.com/golang-jwt/jwt/v5"
"github.com/nbutton23/zxcvbn-go"
"golang.org/x/crypto/bcrypt"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/config" "github.com/cloudbase/garm/config"
"github.com/cloudbase/garm/database/common" "github.com/cloudbase/garm/database/common"
runnerErrors "github.com/cloudbase/garm/errors"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/util"
"github.com/golang-jwt/jwt"
"github.com/nbutton23/zxcvbn-go"
"github.com/pkg/errors"
"golang.org/x/crypto/bcrypt"
) )
func NewAuthenticator(cfg config.JWTAuth, store common.Store) *Authenticator { func NewAuthenticator(cfg config.JWTAuth, store common.Store) *Authenticator {
@ -49,24 +50,30 @@ func (a *Authenticator) IsInitialized() bool {
func (a *Authenticator) GetJWTToken(ctx context.Context) (string, error) { func (a *Authenticator) GetJWTToken(ctx context.Context) (string, error) {
tokenID, err := util.GetRandomString(16) tokenID, err := util.GetRandomString(16)
if err != nil { if err != nil {
return "", errors.Wrap(err, "generating random string") return "", fmt.Errorf("error generating random string: %w", err)
} }
expireToken := time.Now().Add(a.cfg.TimeToLive.Duration()).Unix() expireToken := time.Now().Add(a.cfg.TimeToLive.Duration())
expires := &jwt.NumericDate{
Time: expireToken,
}
generation := PasswordGeneration(ctx)
claims := JWTClaims{ claims := JWTClaims{
StandardClaims: jwt.StandardClaims{ RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: expireToken, ExpiresAt: expires,
// nolint:golangci-lint,godox
// TODO: make this configurable // TODO: make this configurable
Issuer: "garm", Issuer: "garm",
}, },
UserID: UserID(ctx), UserID: UserID(ctx),
TokenID: tokenID, TokenID: tokenID,
IsAdmin: IsAdmin(ctx), IsAdmin: IsAdmin(ctx),
FullName: FullName(ctx), FullName: FullName(ctx),
Generation: generation,
} }
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(a.cfg.Secret)) tokenString, err := token.SignedString([]byte(a.cfg.Secret))
if err != nil { if err != nil {
return "", errors.Wrap(err, "fetching token string") return "", fmt.Errorf("error fetching token string: %w", err)
} }
return tokenString, nil return tokenString, nil
@ -75,22 +82,26 @@ func (a *Authenticator) GetJWTToken(ctx context.Context) (string, error) {
// GetJWTMetricsToken returns a JWT token that can be used to read metrics. // GetJWTMetricsToken returns a JWT token that can be used to read metrics.
// This token is not tied to a user, no user is stored in the db. // This token is not tied to a user, no user is stored in the db.
func (a *Authenticator) GetJWTMetricsToken(ctx context.Context) (string, error) { func (a *Authenticator) GetJWTMetricsToken(ctx context.Context) (string, error) {
if !IsAdmin(ctx) { if !IsAdmin(ctx) {
return "", runnerErrors.ErrUnauthorized return "", runnerErrors.ErrUnauthorized
} }
tokenID, err := util.GetRandomString(16) tokenID, err := util.GetRandomString(16)
if err != nil { if err != nil {
return "", errors.Wrap(err, "generating random string") return "", fmt.Errorf("error generating random string: %w", err)
} }
// nolint:golangci-lint,godox
// TODO: currently this is the same TTL as the normal Token // TODO: currently this is the same TTL as the normal Token
// maybe we should make this configurable // maybe we should make this configurable
// it's usually pretty nasty if the monitoring fails because the token expired // it's usually pretty nasty if the monitoring fails because the token expired
expireToken := time.Now().Add(a.cfg.TimeToLive.Duration()).Unix() expireToken := time.Now().Add(a.cfg.TimeToLive.Duration())
expires := &jwt.NumericDate{
Time: expireToken,
}
claims := JWTClaims{ claims := JWTClaims{
StandardClaims: jwt.StandardClaims{ RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: expireToken, ExpiresAt: expires,
// nolint:golangci-lint,godox
// TODO: make this configurable // TODO: make this configurable
Issuer: "garm", Issuer: "garm",
}, },
@ -101,7 +112,7 @@ func (a *Authenticator) GetJWTMetricsToken(ctx context.Context) (string, error)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(a.cfg.Secret)) tokenString, err := token.SignedString([]byte(a.cfg.Secret))
if err != nil { if err != nil {
return "", errors.Wrap(err, "fetching token string") return "", fmt.Errorf("error fetching token string: %w", err)
} }
return tokenString, nil return tokenString, nil
@ -111,7 +122,7 @@ func (a *Authenticator) InitController(ctx context.Context, param params.NewUser
_, err := a.store.ControllerInfo() _, err := a.store.ControllerInfo()
if err != nil { if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) { if !errors.Is(err, runnerErrors.ErrNotFound) {
return params.User{}, errors.Wrap(err, "initializing controller") return params.User{}, fmt.Errorf("error initializing controller: %w", err)
} }
} }
if a.store.HasAdminUser(ctx) { if a.store.HasAdminUser(ctx) {
@ -141,7 +152,7 @@ func (a *Authenticator) InitController(ctx context.Context, param params.NewUser
hashed, err := util.PaswsordToBcrypt(param.Password) hashed, err := util.PaswsordToBcrypt(param.Password)
if err != nil { if err != nil {
return params.User{}, errors.Wrap(err, "creating user") return params.User{}, fmt.Errorf("error creating user: %w", err)
} }
param.Password = hashed param.Password = hashed
@ -159,7 +170,7 @@ func (a *Authenticator) AuthenticateUser(ctx context.Context, info params.Passwo
if errors.Is(err, runnerErrors.ErrNotFound) { if errors.Is(err, runnerErrors.ErrNotFound) {
return ctx, runnerErrors.ErrUnauthorized return ctx, runnerErrors.ErrUnauthorized
} }
return ctx, errors.Wrap(err, "authenticating") return ctx, fmt.Errorf("error authenticating: %w", err)
} }
if !user.Enabled { if !user.Enabled {
@ -174,5 +185,5 @@ func (a *Authenticator) AuthenticateUser(ctx context.Context, info params.Passwo
return ctx, runnerErrors.ErrUnauthorized return ctx, runnerErrors.ErrUnauthorized
} }
return PopulateContext(ctx, user), nil return PopulateContext(ctx, user, nil), nil
} }

View file

@ -16,9 +16,10 @@ package auth
import ( import (
"context" "context"
"time"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/providers/common"
) )
type contextFlags string type contextFlags string
@ -28,9 +29,11 @@ const (
fullNameKey contextFlags = "full_name" fullNameKey contextFlags = "full_name"
readMetricsKey contextFlags = "read_metrics" readMetricsKey contextFlags = "read_metrics"
// UserIDFlag is the User ID flag we set in the context // UserIDFlag is the User ID flag we set in the context
UserIDFlag contextFlags = "user_id" UserIDFlag contextFlags = "user_id"
isEnabledFlag contextFlags = "is_enabled" isEnabledFlag contextFlags = "is_enabled"
jwtTokenFlag contextFlags = "jwt_token" jwtTokenFlag contextFlags = "jwt_token"
authExpiresFlag contextFlags = "auth_expires"
passwordGenerationFlag contextFlags = "password_generation"
instanceIDKey contextFlags = "id" instanceIDKey contextFlags = "id"
instanceNameKey contextFlags = "name" instanceNameKey contextFlags = "name"
@ -39,8 +42,23 @@ const (
instanceEntityKey contextFlags = "entity" instanceEntityKey contextFlags = "entity"
instanceRunnerStatus contextFlags = "status" instanceRunnerStatus contextFlags = "status"
instanceTokenFetched contextFlags = "tokenFetched" instanceTokenFetched contextFlags = "tokenFetched"
instanceHasJITConfig contextFlags = "hasJITConfig"
instanceParams contextFlags = "instanceParams"
instanceForgeTypeKey contextFlags = "forge_type"
) )
func SetInstanceForgeType(ctx context.Context, val string) context.Context {
return context.WithValue(ctx, instanceForgeTypeKey, val)
}
func InstanceForgeType(ctx context.Context) params.EndpointType {
elem := ctx.Value(instanceForgeTypeKey)
if elem == nil {
return ""
}
return elem.(params.EndpointType)
}
func SetInstanceID(ctx context.Context, id string) context.Context { func SetInstanceID(ctx context.Context, id string) context.Context {
return context.WithValue(ctx, instanceIDKey, id) return context.WithValue(ctx, instanceIDKey, id)
} }
@ -65,16 +83,45 @@ func InstanceTokenFetched(ctx context.Context) bool {
return elem.(bool) return elem.(bool)
} }
func SetInstanceRunnerStatus(ctx context.Context, val common.RunnerStatus) context.Context { func SetInstanceHasJITConfig(ctx context.Context, cfg map[string]string) context.Context {
return context.WithValue(ctx, instanceHasJITConfig, len(cfg) > 0)
}
func InstanceHasJITConfig(ctx context.Context) bool {
elem := ctx.Value(instanceHasJITConfig)
if elem == nil {
return false
}
return elem.(bool)
}
func SetInstanceParams(ctx context.Context, instance params.Instance) context.Context {
return context.WithValue(ctx, instanceParams, instance)
}
func InstanceParams(ctx context.Context) (params.Instance, error) {
elem := ctx.Value(instanceParams)
if elem == nil {
return params.Instance{}, runnerErrors.ErrNotFound
}
instanceParams, ok := elem.(params.Instance)
if !ok {
return params.Instance{}, runnerErrors.ErrNotFound
}
return instanceParams, nil
}
func SetInstanceRunnerStatus(ctx context.Context, val params.RunnerStatus) context.Context {
return context.WithValue(ctx, instanceRunnerStatus, val) return context.WithValue(ctx, instanceRunnerStatus, val)
} }
func InstanceRunnerStatus(ctx context.Context) common.RunnerStatus { func InstanceRunnerStatus(ctx context.Context) params.RunnerStatus {
elem := ctx.Value(instanceRunnerStatus) elem := ctx.Value(instanceRunnerStatus)
if elem == nil { if elem == nil {
return common.RunnerPending return params.RunnerPending
} }
return elem.(common.RunnerStatus) return elem.(params.RunnerStatus)
} }
func SetInstanceName(ctx context.Context, val string) context.Context { func SetInstanceName(ctx context.Context, val string) context.Context {
@ -125,25 +172,57 @@ func InstanceEntity(ctx context.Context) string {
return elem.(string) return elem.(string)
} }
func PopulateInstanceContext(ctx context.Context, instance params.Instance) context.Context { func PopulateInstanceContext(ctx context.Context, instance params.Instance, claims *InstanceJWTClaims) context.Context {
ctx = SetInstanceID(ctx, instance.ID) ctx = SetInstanceID(ctx, instance.ID)
ctx = SetInstanceName(ctx, instance.Name) ctx = SetInstanceName(ctx, instance.Name)
ctx = SetInstancePoolID(ctx, instance.PoolID) ctx = SetInstancePoolID(ctx, instance.PoolID)
ctx = SetInstanceRunnerStatus(ctx, instance.RunnerStatus) ctx = SetInstanceRunnerStatus(ctx, instance.RunnerStatus)
ctx = SetInstanceTokenFetched(ctx, instance.TokenFetched) ctx = SetInstanceTokenFetched(ctx, instance.TokenFetched)
ctx = SetInstanceHasJITConfig(ctx, instance.JitConfiguration)
ctx = SetInstanceParams(ctx, instance)
ctx = SetInstanceForgeType(ctx, claims.ForgeType)
return ctx return ctx
} }
// PopulateContext sets the appropriate fields in the context, based on // PopulateContext sets the appropriate fields in the context, based on
// the user object // the user object
func PopulateContext(ctx context.Context, user params.User) context.Context { func PopulateContext(ctx context.Context, user params.User, authExpires *time.Time) context.Context {
ctx = SetUserID(ctx, user.ID) ctx = SetUserID(ctx, user.ID)
ctx = SetAdmin(ctx, user.IsAdmin) ctx = SetAdmin(ctx, user.IsAdmin)
ctx = SetIsEnabled(ctx, user.Enabled) ctx = SetIsEnabled(ctx, user.Enabled)
ctx = SetFullName(ctx, user.FullName) ctx = SetFullName(ctx, user.FullName)
ctx = SetExpires(ctx, authExpires)
ctx = SetPasswordGeneration(ctx, user.Generation)
return ctx return ctx
} }
func SetExpires(ctx context.Context, expires *time.Time) context.Context {
if expires == nil {
return ctx
}
return context.WithValue(ctx, authExpiresFlag, expires)
}
func Expires(ctx context.Context) *time.Time {
elem := ctx.Value(authExpiresFlag)
if elem == nil {
return nil
}
return elem.(*time.Time)
}
func SetPasswordGeneration(ctx context.Context, val uint) context.Context {
return context.WithValue(ctx, passwordGenerationFlag, val)
}
func PasswordGeneration(ctx context.Context) uint {
elem := ctx.Value(passwordGenerationFlag)
if elem == nil {
return 0
}
return elem.(uint)
}
// SetFullName sets the user full name in the context // SetFullName sets the user full name in the context
func SetFullName(ctx context.Context, fullName string) context.Context { func SetFullName(ctx context.Context, fullName string) context.Context {
return context.WithValue(ctx, fullNameKey, fullName) return context.WithValue(ctx, fullNameKey, fullName)
@ -205,8 +284,10 @@ func UserID(ctx context.Context) string {
// GetAdminContext will return an admin context. This can be used internally // GetAdminContext will return an admin context. This can be used internally
// when fetching users. // when fetching users.
func GetAdminContext() context.Context { func GetAdminContext(ctx context.Context) context.Context {
ctx := context.Background() if ctx == nil {
ctx = context.Background()
}
ctx = SetUserID(ctx, "") ctx = SetUserID(ctx, "")
ctx = SetAdmin(ctx, true) ctx = SetAdmin(ctx, true)
ctx = SetIsEnabled(ctx, true) ctx = SetIsEnabled(ctx, true)

View file

@ -16,7 +16,7 @@ package auth
import ( import (
"encoding/json" "encoding/json"
"log" "log/slog"
"net/http" "net/http"
"github.com/cloudbase/garm/apiserver/params" "github.com/cloudbase/garm/apiserver/params"
@ -37,16 +37,44 @@ type initRequired struct {
// Middleware implements the middleware interface // Middleware implements the middleware interface
func (i *initRequired) Middleware(next http.Handler) http.Handler { func (i *initRequired) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctrlInfo, err := i.store.ControllerInfo() ctx := r.Context()
if err != nil || ctrlInfo.ControllerID.String() == "" {
if !i.store.HasAdminUser(ctx) {
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusConflict) w.WriteHeader(http.StatusConflict)
if err := json.NewEncoder(w).Encode(params.InitializationRequired); err != nil { if err := json.NewEncoder(w).Encode(params.InitializationRequired); err != nil {
log.Printf("failed to encode response: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
return return
} }
ctx := r.Context()
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func NewUrlsRequiredMiddleware(store common.Store) (Middleware, error) {
return &urlsRequired{
store: store,
}, nil
}
type urlsRequired struct {
store common.Store
}
func (u *urlsRequired) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctrlInfo, err := u.store.ControllerInfo()
if err != nil || ctrlInfo.MetadataURL == "" || ctrlInfo.CallbackURL == "" {
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusConflict)
if err := json.NewEncoder(w).Encode(params.URLsRequired); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
return
}
next.ServeHTTP(w, r.WithContext(ctx)) next.ServeHTTP(w, r.WithContext(ctx))
}) })
} }

View file

@ -17,19 +17,20 @@ package auth
import ( import (
"context" "context"
"fmt" "fmt"
"log/slog"
"math"
"net/http" "net/http"
"strings" "strings"
"time" "time"
jwt "github.com/golang-jwt/jwt/v5"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm/config" "github.com/cloudbase/garm/config"
dbCommon "github.com/cloudbase/garm/database/common" dbCommon "github.com/cloudbase/garm/database/common"
runnerErrors "github.com/cloudbase/garm/errors"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common" "github.com/cloudbase/garm/runner/common"
providerCommon "github.com/cloudbase/garm/runner/providers/common"
"github.com/golang-jwt/jwt"
"github.com/pkg/errors"
) )
// InstanceJWTClaims holds JWT claims // InstanceJWTClaims holds JWT claims
@ -38,32 +39,58 @@ type InstanceJWTClaims struct {
Name string `json:"name"` Name string `json:"name"`
PoolID string `json:"provider_id"` PoolID string `json:"provider_id"`
// Scope is either repository or organization // Scope is either repository or organization
Scope params.PoolType `json:"scope"` Scope params.ForgeEntityType `json:"scope"`
// Entity is the repo or org name // Entity is the repo or org name
Entity string `json:"entity"` Entity string `json:"entity"`
jwt.StandardClaims CreateAttempt int `json:"create_attempt"`
ForgeType string `json:"forge_type"`
jwt.RegisteredClaims
} }
func NewInstanceJWTToken(instance params.Instance, secret, entity string, poolType params.PoolType, ttlMinutes uint) (string, error) { func NewInstanceTokenGetter(jwtSecret string) (InstanceTokenGetter, error) {
if jwtSecret == "" {
return nil, fmt.Errorf("jwt secret is required")
}
return &instanceToken{
jwtSecret: jwtSecret,
}, nil
}
type instanceToken struct {
jwtSecret string
}
func (i *instanceToken) NewInstanceJWTToken(instance params.Instance, entity params.ForgeEntity, entityType params.ForgeEntityType, ttlMinutes uint) (string, error) {
// Token expiration is equal to the bootstrap timeout set on the pool plus the polling // Token expiration is equal to the bootstrap timeout set on the pool plus the polling
// interval garm uses to check for timed out runners. Runners that have not sent their info // interval garm uses to check for timed out runners. Runners that have not sent their info
// by the end of this interval are most likely failed and will be reaped by garm anyway. // by the end of this interval are most likely failed and will be reaped by garm anyway.
expireToken := time.Now().Add(time.Duration(ttlMinutes)*time.Minute + common.PoolReapTimeoutInterval).Unix() var ttl int
if ttlMinutes > math.MaxInt {
ttl = math.MaxInt
} else {
ttl = int(ttlMinutes)
}
expireToken := time.Now().Add(time.Duration(ttl)*time.Minute + common.PoolReapTimeoutInterval)
expires := &jwt.NumericDate{
Time: expireToken,
}
claims := InstanceJWTClaims{ claims := InstanceJWTClaims{
StandardClaims: jwt.StandardClaims{ RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: expireToken, ExpiresAt: expires,
Issuer: "garm", Issuer: "garm",
}, },
ID: instance.ID, ID: instance.ID,
Name: instance.Name, Name: instance.Name,
PoolID: instance.PoolID, PoolID: instance.PoolID,
Scope: poolType, Scope: entityType,
Entity: entity, Entity: entity.String(),
ForgeType: string(entity.Credentials.ForgeType),
CreateAttempt: instance.CreateAttempt,
} }
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(secret)) tokenString, err := token.SignedString([]byte(i.jwtSecret))
if err != nil { if err != nil {
return "", errors.Wrap(err, "signing token") return "", fmt.Errorf("error signing token: %w", err)
} }
return tokenString, nil return tokenString, nil
@ -93,29 +120,30 @@ func (amw *instanceMiddleware) claimsToContext(ctx context.Context, claims *Inst
return nil, runnerErrors.ErrUnauthorized return nil, runnerErrors.ErrUnauthorized
} }
instanceInfo, err := amw.store.GetInstanceByName(ctx, claims.Name) instanceInfo, err := amw.store.GetInstance(ctx, claims.Name)
if err != nil { if err != nil {
return ctx, runnerErrors.ErrUnauthorized return ctx, runnerErrors.ErrUnauthorized
} }
ctx = PopulateInstanceContext(ctx, instanceInfo) ctx = PopulateInstanceContext(ctx, instanceInfo, claims)
return ctx, nil return ctx, nil
} }
// Middleware implements the middleware interface // Middleware implements the middleware interface
func (amw *instanceMiddleware) Middleware(next http.Handler) http.Handler { func (amw *instanceMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// nolint:golangci-lint,godox
// TODO: Log error details when authentication fails // TODO: Log error details when authentication fails
ctx := r.Context() ctx := r.Context()
authorizationHeader := r.Header.Get("authorization") authorizationHeader := r.Header.Get("authorization")
if authorizationHeader == "" { if authorizationHeader == "" {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
bearerToken := strings.Split(authorizationHeader, " ") bearerToken := strings.Split(authorizationHeader, " ")
if len(bearerToken) != 2 { if len(bearerToken) != 2 {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
@ -126,32 +154,61 @@ func (amw *instanceMiddleware) Middleware(next http.Handler) http.Handler {
} }
return []byte(amw.cfg.Secret), nil return []byte(amw.cfg.Secret), nil
}) })
if err != nil { if err != nil {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
if !token.Valid { if !token.Valid {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
ctx, err = amw.claimsToContext(ctx, claims) ctx, err = amw.claimsToContext(ctx, claims)
if err != nil { if err != nil {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
if InstanceID(ctx) == "" { if InstanceID(ctx) == "" {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
runnerStatus := InstanceRunnerStatus(ctx) runnerStatus := InstanceRunnerStatus(ctx)
if runnerStatus != providerCommon.RunnerInstalling && runnerStatus != providerCommon.RunnerPending { if runnerStatus != params.RunnerInstalling && runnerStatus != params.RunnerPending {
// Instances that have finished installing can no longer authenticate to the API // Instances that have finished installing can no longer authenticate to the API
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return
}
instanceParams, err := InstanceParams(ctx)
if err != nil {
slog.InfoContext(
ctx, "could not find instance params",
"runner_name", InstanceName(ctx))
invalidAuthResponse(ctx, w)
return
}
// Token was generated for a previous attempt at creating this instance.
if claims.CreateAttempt != instanceParams.CreateAttempt {
slog.InfoContext(
ctx, "invalid token create attempt",
"runner_name", InstanceName(ctx),
"token_create_attempt", claims.CreateAttempt,
"instance_create_attempt", instanceParams.CreateAttempt)
invalidAuthResponse(ctx, w)
return
}
// Only allow instances that are in the creating or running state to authenticate.
if instanceParams.Status != commonParams.InstanceCreating && instanceParams.Status != commonParams.InstanceRunning {
slog.InfoContext(
ctx, "invalid instance status",
"runner_name", InstanceName(ctx),
"status", instanceParams.Status)
invalidAuthResponse(ctx, w)
return return
} }

View file

@ -14,9 +14,17 @@
package auth package auth
import "net/http" import (
"net/http"
"github.com/cloudbase/garm/params"
)
// Middleware defines an authentication middleware // Middleware defines an authentication middleware
type Middleware interface { type Middleware interface {
Middleware(next http.Handler) http.Handler Middleware(next http.Handler) http.Handler
} }
type InstanceTokenGetter interface {
NewInstanceJWTToken(instance params.Instance, entity params.ForgeEntity, poolType params.ForgeEntityType, ttlMinutes uint) (string, error)
}

View file

@ -18,16 +18,17 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log" "log/slog"
"net/http" "net/http"
"strings" "strings"
"time"
jwt "github.com/golang-jwt/jwt/v5"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
apiParams "github.com/cloudbase/garm/apiserver/params" apiParams "github.com/cloudbase/garm/apiserver/params"
"github.com/cloudbase/garm/config" "github.com/cloudbase/garm/config"
dbCommon "github.com/cloudbase/garm/database/common" dbCommon "github.com/cloudbase/garm/database/common"
runnerErrors "github.com/cloudbase/garm/errors"
"github.com/golang-jwt/jwt"
) )
// JWTClaims holds JWT claims // JWTClaims holds JWT claims
@ -37,7 +38,8 @@ type JWTClaims struct {
FullName string `json:"full_name"` FullName string `json:"full_name"`
IsAdmin bool `json:"is_admin"` IsAdmin bool `json:"is_admin"`
ReadMetrics bool `json:"read_metrics"` ReadMetrics bool `json:"read_metrics"`
jwt.StandardClaims Generation uint `json:"generation"`
jwt.RegisteredClaims
} }
// jwtMiddleware is the authentication middleware // jwtMiddleware is the authentication middleware
@ -69,63 +71,85 @@ func (amw *jwtMiddleware) claimsToContext(ctx context.Context, claims *JWTClaims
return ctx, runnerErrors.ErrUnauthorized return ctx, runnerErrors.ErrUnauthorized
} }
ctx = PopulateContext(ctx, userInfo) var expiresAt *time.Time
if claims.ExpiresAt != nil {
expires := claims.ExpiresAt.Time.UTC()
expiresAt = &expires
}
if userInfo.Generation != claims.Generation {
// Password was reset since token was issued. Invalidate.
return ctx, runnerErrors.ErrUnauthorized
}
ctx = PopulateContext(ctx, userInfo, expiresAt)
return ctx, nil return ctx, nil
} }
func invalidAuthResponse(w http.ResponseWriter) { func invalidAuthResponse(ctx context.Context, w http.ResponseWriter) {
w.WriteHeader(http.StatusUnauthorized)
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
if err := json.NewEncoder(w).Encode( if err := json.NewEncoder(w).Encode(
apiParams.APIErrorResponse{ apiParams.APIErrorResponse{
Error: "Authentication failed", Error: "Authentication failed",
}); err != nil { }); err != nil {
log.Printf("failed to encode response: %s", err) slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
} }
} }
func (amw *jwtMiddleware) getTokenFromRequest(r *http.Request) (string, error) {
authorizationHeader := r.Header.Get("authorization")
if authorizationHeader == "" {
cookie, err := r.Cookie("garm_token")
if err != nil {
return "", fmt.Errorf("failed to get cookie: %w", err)
}
return cookie.Value, nil
}
bearerToken := strings.Split(authorizationHeader, " ")
if len(bearerToken) != 2 {
return "", fmt.Errorf("invalid auth header")
}
return bearerToken[1], nil
}
// Middleware implements the middleware interface // Middleware implements the middleware interface
func (amw *jwtMiddleware) Middleware(next http.Handler) http.Handler { func (amw *jwtMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// nolint:golangci-lint,godox
// TODO: Log error details when authentication fails // TODO: Log error details when authentication fails
ctx := r.Context() ctx := r.Context()
authorizationHeader := r.Header.Get("authorization") authToken, err := amw.getTokenFromRequest(r)
if authorizationHeader == "" { if err != nil {
invalidAuthResponse(w) slog.ErrorContext(ctx, "failed to get auth token", "error", err)
invalidAuthResponse(ctx, w)
return return
} }
bearerToken := strings.Split(authorizationHeader, " ")
if len(bearerToken) != 2 {
invalidAuthResponse(w)
return
}
claims := &JWTClaims{} claims := &JWTClaims{}
token, err := jwt.ParseWithClaims(bearerToken[1], claims, func(token *jwt.Token) (interface{}, error) { token, err := jwt.ParseWithClaims(authToken, claims, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("invalid signing method") return nil, fmt.Errorf("invalid signing method")
} }
return []byte(amw.cfg.Secret), nil return []byte(amw.cfg.Secret), nil
}) })
if err != nil { if err != nil {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
if !token.Valid { if !token.Valid {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
ctx, err = amw.claimsToContext(ctx, claims) ctx, err = amw.claimsToContext(ctx, claims)
if err != nil { if err != nil {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
if !IsEnabled(ctx) { if !IsEnabled(ctx) {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }

View file

@ -1,3 +1,16 @@
// Copyright 2025 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 auth package auth
import ( import (
@ -6,9 +19,9 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/cloudbase/garm/config" jwt "github.com/golang-jwt/jwt/v5"
"github.com/golang-jwt/jwt" "github.com/cloudbase/garm/config"
) )
type MetricsMiddleware struct { type MetricsMiddleware struct {
@ -23,17 +36,16 @@ func NewMetricsMiddleware(cfg config.JWTAuth) (*MetricsMiddleware, error) {
func (m *MetricsMiddleware) Middleware(next http.Handler) http.Handler { func (m *MetricsMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
authorizationHeader := r.Header.Get("authorization") authorizationHeader := r.Header.Get("authorization")
if authorizationHeader == "" { if authorizationHeader == "" {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
bearerToken := strings.Split(authorizationHeader, " ") bearerToken := strings.Split(authorizationHeader, " ")
if len(bearerToken) != 2 { if len(bearerToken) != 2 {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
@ -44,20 +56,19 @@ func (m *MetricsMiddleware) Middleware(next http.Handler) http.Handler {
} }
return []byte(m.cfg.Secret), nil return []byte(m.cfg.Secret), nil
}) })
if err != nil { if err != nil {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
if !token.Valid { if !token.Valid {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }
// we fully trust the claims // we fully trust the claims
if !claims.ReadMetrics { if !claims.ReadMetrics {
invalidAuthResponse(w) invalidAuthResponse(ctx, w)
return return
} }

16
build-webapp.sh Executable file
View file

@ -0,0 +1,16 @@
#!/bin/bash
set -e
echo "Building GARM SPA (SvelteKit)..."
# Navigate to webapp directory
cd webapp
# Install dependencies if node_modules doesn't exist
npm install
# Build the SPA
echo "Building SPA..."
npm run build
echo "SPA built successfully!"

1040
cache/cache_test.go vendored Normal file

File diff suppressed because it is too large Load diff

148
cache/credentials_cache.go vendored Normal file
View file

@ -0,0 +1,148 @@
// Copyright 2025 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 cache
import (
"sync"
"github.com/cloudbase/garm/params"
)
var (
credentialsCache *CredentialCache
giteaCredentialsCache *CredentialCache
)
func init() {
ghCredentialsCache := &CredentialCache{
cache: make(map[uint]params.ForgeCredentials),
}
gtCredentialsCache := &CredentialCache{
cache: make(map[uint]params.ForgeCredentials),
}
credentialsCache = ghCredentialsCache
giteaCredentialsCache = gtCredentialsCache
}
type CredentialCache struct {
mux sync.Mutex
cache map[uint]params.ForgeCredentials
}
func (g *CredentialCache) SetCredentialsRateLimit(credsID uint, rateLimit params.GithubRateLimit) {
g.mux.Lock()
defer g.mux.Unlock()
if creds, ok := g.cache[credsID]; ok {
creds.RateLimit = &rateLimit
g.cache[credsID] = creds
}
}
func (g *CredentialCache) SetCredentials(credentials params.ForgeCredentials) {
g.mux.Lock()
defer g.mux.Unlock()
g.cache[credentials.ID] = credentials
UpdateCredentialsInAffectedEntities(credentials)
}
func (g *CredentialCache) GetCredentials(id uint) (params.ForgeCredentials, bool) {
g.mux.Lock()
defer g.mux.Unlock()
if creds, ok := g.cache[id]; ok {
return creds, true
}
return params.ForgeCredentials{}, false
}
func (g *CredentialCache) DeleteCredentials(id uint) {
g.mux.Lock()
defer g.mux.Unlock()
delete(g.cache, id)
}
func (g *CredentialCache) GetAllCredentials() []params.ForgeCredentials {
g.mux.Lock()
defer g.mux.Unlock()
creds := make([]params.ForgeCredentials, 0, len(g.cache))
for _, cred := range g.cache {
creds = append(creds, cred)
}
// Sort the credentials by ID
sortByID(creds)
return creds
}
func (g *CredentialCache) GetAllCredentialsAsMap() map[uint]params.ForgeCredentials {
g.mux.Lock()
defer g.mux.Unlock()
creds := make(map[uint]params.ForgeCredentials, len(g.cache))
for id, cred := range g.cache {
creds[id] = cred
}
return creds
}
func SetGithubCredentials(credentials params.ForgeCredentials) {
credentialsCache.SetCredentials(credentials)
}
func GetGithubCredentials(id uint) (params.ForgeCredentials, bool) {
return credentialsCache.GetCredentials(id)
}
func DeleteGithubCredentials(id uint) {
credentialsCache.DeleteCredentials(id)
}
func GetAllGithubCredentials() []params.ForgeCredentials {
return credentialsCache.GetAllCredentials()
}
func SetCredentialsRateLimit(credsID uint, rateLimit params.GithubRateLimit) {
credentialsCache.SetCredentialsRateLimit(credsID, rateLimit)
}
func GetAllGithubCredentialsAsMap() map[uint]params.ForgeCredentials {
return credentialsCache.GetAllCredentialsAsMap()
}
func SetGiteaCredentials(credentials params.ForgeCredentials) {
giteaCredentialsCache.SetCredentials(credentials)
}
func GetGiteaCredentials(id uint) (params.ForgeCredentials, bool) {
return giteaCredentialsCache.GetCredentials(id)
}
func DeleteGiteaCredentials(id uint) {
giteaCredentialsCache.DeleteCredentials(id)
}
func GetAllGiteaCredentials() []params.ForgeCredentials {
return giteaCredentialsCache.GetAllCredentials()
}
func GetAllGiteaCredentialsAsMap() map[uint]params.ForgeCredentials {
return giteaCredentialsCache.GetAllCredentialsAsMap()
}

435
cache/entity_cache.go vendored Normal file
View file

@ -0,0 +1,435 @@
// Copyright 2025 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 cache
import (
"sync"
"time"
"github.com/cloudbase/garm/params"
)
var entityCache *EntityCache
func init() {
ghEntityCache := &EntityCache{
entities: make(map[string]EntityItem),
}
entityCache = ghEntityCache
}
type RunnerGroupEntry struct {
RunnerGroupID int64
time time.Time
}
type EntityItem struct {
Entity params.ForgeEntity
Pools map[string]params.Pool
ScaleSets map[uint]params.ScaleSet
RunnerGroups map[string]RunnerGroupEntry
}
type EntityCache struct {
mux sync.Mutex
// entity IDs are UUID4s. It is highly unlikely they will collide (🤞).
entities map[string]EntityItem
}
func (e *EntityCache) UpdateCredentialsInAffectedEntities(creds params.ForgeCredentials) {
e.mux.Lock()
defer e.mux.Unlock()
for entityID, cache := range e.entities {
if cache.Entity.Credentials.GetID() == creds.GetID() {
cache.Entity.Credentials = creds
e.entities[entityID] = cache
}
}
}
func (e *EntityCache) GetEntity(entityID string) (params.ForgeEntity, bool) {
e.mux.Lock()
defer e.mux.Unlock()
if cache, ok := e.entities[entityID]; ok {
var creds params.ForgeCredentials
var ok bool
switch cache.Entity.Credentials.ForgeType {
case params.GithubEndpointType:
creds, ok = GetGithubCredentials(cache.Entity.Credentials.ID)
case params.GiteaEndpointType:
creds, ok = GetGiteaCredentials(cache.Entity.Credentials.ID)
}
if ok {
cache.Entity.Credentials = creds
}
return cache.Entity, true
}
return params.ForgeEntity{}, false
}
func (e *EntityCache) SetEntity(entity params.ForgeEntity) {
e.mux.Lock()
defer e.mux.Unlock()
cache, ok := e.entities[entity.ID]
if !ok {
e.entities[entity.ID] = EntityItem{
Entity: entity,
Pools: make(map[string]params.Pool),
ScaleSets: make(map[uint]params.ScaleSet),
RunnerGroups: make(map[string]RunnerGroupEntry),
}
return
}
cache.Entity = entity
e.entities[entity.ID] = cache
}
func (e *EntityCache) ReplaceEntityPools(entityID string, pools []params.Pool) {
e.mux.Lock()
defer e.mux.Unlock()
cache, ok := e.entities[entityID]
if !ok {
return
}
poolsByID := map[string]params.Pool{}
for _, pool := range pools {
poolsByID[pool.ID] = pool
}
cache.Pools = poolsByID
e.entities[entityID] = cache
}
func (e *EntityCache) ReplaceEntityScaleSets(entityID string, scaleSets []params.ScaleSet) {
e.mux.Lock()
defer e.mux.Unlock()
cache, ok := e.entities[entityID]
if !ok {
return
}
scaleSetsByID := map[uint]params.ScaleSet{}
for _, scaleSet := range scaleSets {
scaleSetsByID[scaleSet.ID] = scaleSet
}
cache.ScaleSets = scaleSetsByID
e.entities[entityID] = cache
}
func (e *EntityCache) DeleteEntity(entityID string) {
e.mux.Lock()
defer e.mux.Unlock()
delete(e.entities, entityID)
}
func (e *EntityCache) SetEntityPool(entityID string, pool params.Pool) {
e.mux.Lock()
defer e.mux.Unlock()
if cache, ok := e.entities[entityID]; ok {
cache.Pools[pool.ID] = pool
e.entities[entityID] = cache
}
}
func (e *EntityCache) SetEntityScaleSet(entityID string, scaleSet params.ScaleSet) {
e.mux.Lock()
defer e.mux.Unlock()
if cache, ok := e.entities[entityID]; ok {
cache.ScaleSets[scaleSet.ID] = scaleSet
e.entities[entityID] = cache
}
}
func (e *EntityCache) DeleteEntityPool(entityID string, poolID string) {
e.mux.Lock()
defer e.mux.Unlock()
if cache, ok := e.entities[entityID]; ok {
delete(cache.Pools, poolID)
e.entities[entityID] = cache
}
}
func (e *EntityCache) DeleteEntityScaleSet(entityID string, scaleSetID uint) {
e.mux.Lock()
defer e.mux.Unlock()
if cache, ok := e.entities[entityID]; ok {
delete(cache.ScaleSets, scaleSetID)
e.entities[entityID] = cache
}
}
func (e *EntityCache) GetEntityPool(entityID string, poolID string) (params.Pool, bool) {
e.mux.Lock()
defer e.mux.Unlock()
if cache, ok := e.entities[entityID]; ok {
if pool, ok := cache.Pools[poolID]; ok {
return pool, true
}
}
return params.Pool{}, false
}
func (e *EntityCache) GetEntityScaleSet(entityID string, scaleSetID uint) (params.ScaleSet, bool) {
e.mux.Lock()
defer e.mux.Unlock()
if cache, ok := e.entities[entityID]; ok {
if scaleSet, ok := cache.ScaleSets[scaleSetID]; ok {
return scaleSet, true
}
}
return params.ScaleSet{}, false
}
func (e *EntityCache) FindPoolsMatchingAllTags(entityID string, tags []string) []params.Pool {
e.mux.Lock()
defer e.mux.Unlock()
if cache, ok := e.entities[entityID]; ok {
var pools []params.Pool
for _, pool := range cache.Pools {
if pool.HasRequiredLabels(tags) {
pools = append(pools, pool)
}
}
// Sort the pools by creation date.
sortByCreationDate(pools)
return pools
}
return nil
}
func (e *EntityCache) GetEntityPools(entityID string) []params.Pool {
e.mux.Lock()
defer e.mux.Unlock()
if cache, ok := e.entities[entityID]; ok {
var pools []params.Pool
for _, pool := range cache.Pools {
pools = append(pools, pool)
}
// Sort the pools by creation date.
sortByCreationDate(pools)
return pools
}
return nil
}
func (e *EntityCache) GetEntityScaleSets(entityID string) []params.ScaleSet {
e.mux.Lock()
defer e.mux.Unlock()
if cache, ok := e.entities[entityID]; ok {
var scaleSets []params.ScaleSet
for _, scaleSet := range cache.ScaleSets {
scaleSets = append(scaleSets, scaleSet)
}
// Sort the scale sets by creation date.
sortByID(scaleSets)
return scaleSets
}
return nil
}
func (e *EntityCache) GetEntitiesUsingCredentials(creds params.ForgeCredentials) []params.ForgeEntity {
e.mux.Lock()
defer e.mux.Unlock()
var entities []params.ForgeEntity
for _, cache := range e.entities {
if cache.Entity.Credentials.ForgeType != creds.ForgeType {
continue
}
if cache.Entity.Credentials.GetID() == creds.GetID() {
entities = append(entities, cache.Entity)
}
}
sortByCreationDate(entities)
return entities
}
func (e *EntityCache) GetAllEntities() []params.ForgeEntity {
e.mux.Lock()
defer e.mux.Unlock()
var entities []params.ForgeEntity
for _, cache := range e.entities {
// Get the credentials from the credentials cache.
var creds params.ForgeCredentials
var ok bool
switch cache.Entity.Credentials.ForgeType {
case params.GithubEndpointType:
creds, ok = GetGithubCredentials(cache.Entity.Credentials.ID)
case params.GiteaEndpointType:
creds, ok = GetGiteaCredentials(cache.Entity.Credentials.ID)
}
if ok {
cache.Entity.Credentials = creds
}
entities = append(entities, cache.Entity)
}
sortByCreationDate(entities)
return entities
}
func (e *EntityCache) GetAllPools() []params.Pool {
e.mux.Lock()
defer e.mux.Unlock()
var pools []params.Pool
for _, cache := range e.entities {
for _, pool := range cache.Pools {
pools = append(pools, pool)
}
}
sortByCreationDate(pools)
return pools
}
func (e *EntityCache) GetAllScaleSets() []params.ScaleSet {
e.mux.Lock()
defer e.mux.Unlock()
var scaleSets []params.ScaleSet
for _, cache := range e.entities {
for _, scaleSet := range cache.ScaleSets {
scaleSets = append(scaleSets, scaleSet)
}
}
sortByID(scaleSets)
return scaleSets
}
func (e *EntityCache) SetEntityRunnerGroup(entityID, runnerGroupName string, runnerGroupID int64) {
e.mux.Lock()
defer e.mux.Unlock()
if _, ok := e.entities[entityID]; ok {
e.entities[entityID].RunnerGroups[runnerGroupName] = RunnerGroupEntry{
RunnerGroupID: runnerGroupID,
time: time.Now().UTC(),
}
}
}
func (e *EntityCache) GetEntityRunnerGroup(entityID, runnerGroupName string) (int64, bool) {
e.mux.Lock()
defer e.mux.Unlock()
if _, ok := e.entities[entityID]; ok {
if runnerGroup, ok := e.entities[entityID].RunnerGroups[runnerGroupName]; ok {
if time.Now().UTC().After(runnerGroup.time.Add(1 * time.Hour)) {
delete(e.entities[entityID].RunnerGroups, runnerGroupName)
return 0, false
}
return runnerGroup.RunnerGroupID, true
}
}
return 0, false
}
func SetEntityRunnerGroup(entityID, runnerGroupName string, runnerGroupID int64) {
entityCache.SetEntityRunnerGroup(entityID, runnerGroupName, runnerGroupID)
}
func GetEntityRunnerGroup(entityID, runnerGroupName string) (int64, bool) {
return entityCache.GetEntityRunnerGroup(entityID, runnerGroupName)
}
func GetEntity(entityID string) (params.ForgeEntity, bool) {
return entityCache.GetEntity(entityID)
}
func SetEntity(entity params.ForgeEntity) {
entityCache.SetEntity(entity)
}
func ReplaceEntityPools(entityID string, pools []params.Pool) {
entityCache.ReplaceEntityPools(entityID, pools)
}
func ReplaceEntityScaleSets(entityID string, scaleSets []params.ScaleSet) {
entityCache.ReplaceEntityScaleSets(entityID, scaleSets)
}
func DeleteEntity(entityID string) {
entityCache.DeleteEntity(entityID)
}
func SetEntityPool(entityID string, pool params.Pool) {
entityCache.SetEntityPool(entityID, pool)
}
func SetEntityScaleSet(entityID string, scaleSet params.ScaleSet) {
entityCache.SetEntityScaleSet(entityID, scaleSet)
}
func DeleteEntityPool(entityID string, poolID string) {
entityCache.DeleteEntityPool(entityID, poolID)
}
func DeleteEntityScaleSet(entityID string, scaleSetID uint) {
entityCache.DeleteEntityScaleSet(entityID, scaleSetID)
}
func GetEntityPool(entityID string, poolID string) (params.Pool, bool) {
return entityCache.GetEntityPool(entityID, poolID)
}
func GetEntityScaleSet(entityID string, scaleSetID uint) (params.ScaleSet, bool) {
return entityCache.GetEntityScaleSet(entityID, scaleSetID)
}
func FindPoolsMatchingAllTags(entityID string, tags []string) []params.Pool {
return entityCache.FindPoolsMatchingAllTags(entityID, tags)
}
func GetEntityPools(entityID string) []params.Pool {
return entityCache.GetEntityPools(entityID)
}
func GetEntityScaleSets(entityID string) []params.ScaleSet {
return entityCache.GetEntityScaleSets(entityID)
}
func UpdateCredentialsInAffectedEntities(creds params.ForgeCredentials) {
entityCache.UpdateCredentialsInAffectedEntities(creds)
}
func GetEntitiesUsingCredentials(creds params.ForgeCredentials) []params.ForgeEntity {
return entityCache.GetEntitiesUsingCredentials(creds)
}
func GetAllEntities() []params.ForgeEntity {
return entityCache.GetAllEntities()
}
func GetAllPools() []params.Pool {
return entityCache.GetAllPools()
}
func GetAllScaleSets() []params.ScaleSet {
return entityCache.GetAllScaleSets()
}

60
cache/github_client.go vendored Normal file
View file

@ -0,0 +1,60 @@
// Copyright 2025 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 cache
import (
"sync"
"github.com/cloudbase/garm/runner/common"
)
var ghClientCache *GithubClientCache
type GithubClientCache struct {
mux sync.Mutex
cache map[string]common.GithubClient
}
func init() {
clientCache := &GithubClientCache{
cache: make(map[string]common.GithubClient),
}
ghClientCache = clientCache
}
func (g *GithubClientCache) SetClient(entityID string, client common.GithubClient) {
g.mux.Lock()
defer g.mux.Unlock()
g.cache[entityID] = client
}
func (g *GithubClientCache) GetClient(entityID string) (common.GithubClient, bool) {
g.mux.Lock()
defer g.mux.Unlock()
if client, ok := g.cache[entityID]; ok {
return client, true
}
return nil, false
}
func SetGithubClient(entityID string, client common.GithubClient) {
ghClientCache.SetClient(entityID, client)
}
func GetGithubClient(entityID string) (common.GithubClient, bool) {
return ghClientCache.GetClient(entityID)
}

143
cache/instance_cache.go vendored Normal file
View file

@ -0,0 +1,143 @@
// Copyright 2025 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 cache
import (
"sync"
"github.com/cloudbase/garm/params"
)
var instanceCache *InstanceCache
func init() {
cache := &InstanceCache{
cache: make(map[string]params.Instance),
}
instanceCache = cache
}
type InstanceCache struct {
mux sync.Mutex
cache map[string]params.Instance
}
func (i *InstanceCache) SetInstance(instance params.Instance) {
i.mux.Lock()
defer i.mux.Unlock()
i.cache[instance.Name] = instance
}
func (i *InstanceCache) GetInstance(name string) (params.Instance, bool) {
i.mux.Lock()
defer i.mux.Unlock()
if instance, ok := i.cache[name]; ok {
return instance, true
}
return params.Instance{}, false
}
func (i *InstanceCache) DeleteInstance(name string) {
i.mux.Lock()
defer i.mux.Unlock()
delete(i.cache, name)
}
func (i *InstanceCache) GetAllInstances() []params.Instance {
i.mux.Lock()
defer i.mux.Unlock()
instances := make([]params.Instance, 0, len(i.cache))
for _, instance := range i.cache {
instances = append(instances, instance)
}
sortByCreationDate(instances)
return instances
}
func (i *InstanceCache) GetInstancesForPool(poolID string) []params.Instance {
i.mux.Lock()
defer i.mux.Unlock()
var filteredInstances []params.Instance
for _, instance := range i.cache {
if instance.PoolID == poolID {
filteredInstances = append(filteredInstances, instance)
}
}
sortByCreationDate(filteredInstances)
return filteredInstances
}
func (i *InstanceCache) GetInstancesForScaleSet(scaleSetID uint) []params.Instance {
i.mux.Lock()
defer i.mux.Unlock()
var filteredInstances []params.Instance
for _, instance := range i.cache {
if instance.ScaleSetID == scaleSetID {
filteredInstances = append(filteredInstances, instance)
}
}
sortByCreationDate(filteredInstances)
return filteredInstances
}
func (i *InstanceCache) GetEntityInstances(entityID string) []params.Instance {
pools := GetEntityPools(entityID)
poolsAsMap := map[string]bool{}
for _, pool := range pools {
poolsAsMap[pool.ID] = true
}
ret := []params.Instance{}
for _, val := range i.GetAllInstances() {
if _, ok := poolsAsMap[val.PoolID]; ok {
ret = append(ret, val)
}
}
return ret
}
func SetInstanceCache(instance params.Instance) {
instanceCache.SetInstance(instance)
}
func GetInstanceCache(name string) (params.Instance, bool) {
return instanceCache.GetInstance(name)
}
func DeleteInstanceCache(name string) {
instanceCache.DeleteInstance(name)
}
func GetAllInstancesCache() []params.Instance {
return instanceCache.GetAllInstances()
}
func GetInstancesForPool(poolID string) []params.Instance {
return instanceCache.GetInstancesForPool(poolID)
}
func GetInstancesForScaleSet(scaleSetID uint) []params.Instance {
return instanceCache.GetInstancesForScaleSet(scaleSetID)
}
func GetEntityInstances(entityID string) []params.Instance {
return instanceCache.GetEntityInstances(entityID)
}

116
cache/tools_cache.go vendored Normal file
View file

@ -0,0 +1,116 @@
// Copyright 2025 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 cache
import (
"fmt"
"sync"
"time"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm/params"
)
var githubToolsCache *GithubToolsCache
func init() {
ghToolsCache := &GithubToolsCache{
entities: make(map[string]GithubEntityTools),
}
githubToolsCache = ghToolsCache
}
type GithubEntityTools struct {
updatedAt time.Time
expiresAt time.Time
err error
entity params.ForgeEntity
tools []commonParams.RunnerApplicationDownload
}
type GithubToolsCache struct {
mux sync.Mutex
// entity IDs are UUID4s. It is highly unlikely they will collide (🤞).
entities map[string]GithubEntityTools
}
func (g *GithubToolsCache) Get(entityID string) ([]commonParams.RunnerApplicationDownload, error) {
g.mux.Lock()
defer g.mux.Unlock()
if cache, ok := g.entities[entityID]; ok {
if cache.entity.Credentials.ForgeType == params.GithubEndpointType {
if time.Now().UTC().After(cache.expiresAt.Add(-5 * time.Minute)) {
// Stale cache, remove it.
delete(g.entities, entityID)
return nil, fmt.Errorf("cache expired for entity %s", entityID)
}
}
if cache.err != nil {
return nil, cache.err
}
return cache.tools, nil
}
return nil, fmt.Errorf("no cache found for entity %s", entityID)
}
func (g *GithubToolsCache) Set(entity params.ForgeEntity, tools []commonParams.RunnerApplicationDownload) {
g.mux.Lock()
defer g.mux.Unlock()
forgeTools := GithubEntityTools{
updatedAt: time.Now(),
entity: entity,
tools: tools,
err: nil,
}
if entity.Credentials.ForgeType == params.GithubEndpointType {
forgeTools.expiresAt = time.Now().Add(1 * time.Hour)
}
g.entities[entity.ID] = forgeTools
}
func (g *GithubToolsCache) SetToolsError(entity params.ForgeEntity, err error) {
g.mux.Lock()
defer g.mux.Unlock()
// If the entity is not in the cache, add it with the error.
cache, ok := g.entities[entity.ID]
if !ok {
g.entities[entity.ID] = GithubEntityTools{
updatedAt: time.Now(),
entity: entity,
err: err,
}
return
}
// Update the error for the existing entity.
cache.err = err
g.entities[entity.ID] = cache
}
func SetGithubToolsCache(entity params.ForgeEntity, tools []commonParams.RunnerApplicationDownload) {
githubToolsCache.Set(entity, tools)
}
func GetGithubToolsCache(entityID string) ([]commonParams.RunnerApplicationDownload, error) {
return githubToolsCache.Get(entityID)
}
func SetGithubToolsCacheError(entity params.ForgeEntity, err error) {
githubToolsCache.SetToolsError(entity, err)
}

32
cache/util.go vendored Normal file
View file

@ -0,0 +1,32 @@
// Copyright 2025 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 cache
import (
"sort"
"github.com/cloudbase/garm/params"
)
func sortByID[T params.IDGetter](s []T) {
sort.Slice(s, func(i, j int) bool {
return s[i].GetID() < s[j].GetID()
})
}
func sortByCreationDate[T params.CreationDateGetter](s []T) {
sort.Slice(s, func(i, j int) bool {
return s[i].GetCreatedAt().Before(s[j].GetCreatedAt())
})
}

View file

@ -0,0 +1,106 @@
// Code generated by go-swagger; DO NOT EDIT.
package controller
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"fmt"
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// New creates a new controller API client.
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
return &Client{transport: transport, formats: formats}
}
// New creates a new controller API client with basic auth credentials.
// It takes the following parameters:
// - host: http host (github.com).
// - basePath: any base path for the API client ("/v1", "/v3").
// - scheme: http scheme ("http", "https").
// - user: user for basic authentication header.
// - password: password for basic authentication header.
func NewClientWithBasicAuth(host, basePath, scheme, user, password string) ClientService {
transport := httptransport.New(host, basePath, []string{scheme})
transport.DefaultAuthentication = httptransport.BasicAuth(user, password)
return &Client{transport: transport, formats: strfmt.Default}
}
// New creates a new controller API client with a bearer token for authentication.
// It takes the following parameters:
// - host: http host (github.com).
// - basePath: any base path for the API client ("/v1", "/v3").
// - scheme: http scheme ("http", "https").
// - bearerToken: bearer token for Bearer authentication header.
func NewClientWithBearerToken(host, basePath, scheme, bearerToken string) ClientService {
transport := httptransport.New(host, basePath, []string{scheme})
transport.DefaultAuthentication = httptransport.BearerToken(bearerToken)
return &Client{transport: transport, formats: strfmt.Default}
}
/*
Client for controller API
*/
type Client struct {
transport runtime.ClientTransport
formats strfmt.Registry
}
// ClientOption may be used to customize the behavior of Client methods.
type ClientOption func(*runtime.ClientOperation)
// ClientService is the interface for Client methods
type ClientService interface {
UpdateController(params *UpdateControllerParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateControllerOK, error)
SetTransport(transport runtime.ClientTransport)
}
/*
UpdateController updates controller
*/
func (a *Client) UpdateController(params *UpdateControllerParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateControllerOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewUpdateControllerParams()
}
op := &runtime.ClientOperation{
ID: "UpdateController",
Method: "PUT",
PathPattern: "/controller",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &UpdateControllerReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*UpdateControllerOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for UpdateController: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
// SetTransport changes the transport on the client
func (a *Client) SetTransport(transport runtime.ClientTransport) {
a.transport = transport
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package controller
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
garm_params "github.com/cloudbase/garm/params"
)
// NewUpdateControllerParams creates a new UpdateControllerParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewUpdateControllerParams() *UpdateControllerParams {
return &UpdateControllerParams{
timeout: cr.DefaultTimeout,
}
}
// NewUpdateControllerParamsWithTimeout creates a new UpdateControllerParams object
// with the ability to set a timeout on a request.
func NewUpdateControllerParamsWithTimeout(timeout time.Duration) *UpdateControllerParams {
return &UpdateControllerParams{
timeout: timeout,
}
}
// NewUpdateControllerParamsWithContext creates a new UpdateControllerParams object
// with the ability to set a context for a request.
func NewUpdateControllerParamsWithContext(ctx context.Context) *UpdateControllerParams {
return &UpdateControllerParams{
Context: ctx,
}
}
// NewUpdateControllerParamsWithHTTPClient creates a new UpdateControllerParams object
// with the ability to set a custom HTTPClient for a request.
func NewUpdateControllerParamsWithHTTPClient(client *http.Client) *UpdateControllerParams {
return &UpdateControllerParams{
HTTPClient: client,
}
}
/*
UpdateControllerParams contains all the parameters to send to the API endpoint
for the update controller operation.
Typically these are written to a http.Request.
*/
type UpdateControllerParams struct {
/* Body.
Parameters used when updating the controller.
*/
Body garm_params.UpdateControllerParams
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the update controller params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *UpdateControllerParams) WithDefaults() *UpdateControllerParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the update controller params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *UpdateControllerParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the update controller params
func (o *UpdateControllerParams) WithTimeout(timeout time.Duration) *UpdateControllerParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the update controller params
func (o *UpdateControllerParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the update controller params
func (o *UpdateControllerParams) WithContext(ctx context.Context) *UpdateControllerParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the update controller params
func (o *UpdateControllerParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the update controller params
func (o *UpdateControllerParams) WithHTTPClient(client *http.Client) *UpdateControllerParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the update controller params
func (o *UpdateControllerParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the update controller params
func (o *UpdateControllerParams) WithBody(body garm_params.UpdateControllerParams) *UpdateControllerParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the update controller params
func (o *UpdateControllerParams) SetBody(body garm_params.UpdateControllerParams) {
o.Body = body
}
// WriteToRequest writes these params to a swagger request
func (o *UpdateControllerParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package controller
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// UpdateControllerReader is a Reader for the UpdateController structure.
type UpdateControllerReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *UpdateControllerReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewUpdateControllerOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewUpdateControllerBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[PUT /controller] UpdateController", response, response.Code())
}
}
// NewUpdateControllerOK creates a UpdateControllerOK with default headers values
func NewUpdateControllerOK() *UpdateControllerOK {
return &UpdateControllerOK{}
}
/*
UpdateControllerOK describes a response with status code 200, with default header values.
ControllerInfo
*/
type UpdateControllerOK struct {
Payload garm_params.ControllerInfo
}
// IsSuccess returns true when this update controller o k response has a 2xx status code
func (o *UpdateControllerOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this update controller o k response has a 3xx status code
func (o *UpdateControllerOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this update controller o k response has a 4xx status code
func (o *UpdateControllerOK) IsClientError() bool {
return false
}
// IsServerError returns true when this update controller o k response has a 5xx status code
func (o *UpdateControllerOK) IsServerError() bool {
return false
}
// IsCode returns true when this update controller o k response a status code equal to that given
func (o *UpdateControllerOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the update controller o k response
func (o *UpdateControllerOK) Code() int {
return 200
}
func (o *UpdateControllerOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /controller][%d] updateControllerOK %s", 200, payload)
}
func (o *UpdateControllerOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /controller][%d] updateControllerOK %s", 200, payload)
}
func (o *UpdateControllerOK) GetPayload() garm_params.ControllerInfo {
return o.Payload
}
func (o *UpdateControllerOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewUpdateControllerBadRequest creates a UpdateControllerBadRequest with default headers values
func NewUpdateControllerBadRequest() *UpdateControllerBadRequest {
return &UpdateControllerBadRequest{}
}
/*
UpdateControllerBadRequest describes a response with status code 400, with default header values.
APIErrorResponse
*/
type UpdateControllerBadRequest struct {
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this update controller bad request response has a 2xx status code
func (o *UpdateControllerBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this update controller bad request response has a 3xx status code
func (o *UpdateControllerBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this update controller bad request response has a 4xx status code
func (o *UpdateControllerBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this update controller bad request response has a 5xx status code
func (o *UpdateControllerBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this update controller bad request response a status code equal to that given
func (o *UpdateControllerBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the update controller bad request response
func (o *UpdateControllerBadRequest) Code() int {
return 400
}
func (o *UpdateControllerBadRequest) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /controller][%d] updateControllerBadRequest %s", 400, payload)
}
func (o *UpdateControllerBadRequest) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /controller][%d] updateControllerBadRequest %s", 400, payload)
}
func (o *UpdateControllerBadRequest) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *UpdateControllerBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,106 @@
// Code generated by go-swagger; DO NOT EDIT.
package controller_info
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"fmt"
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// New creates a new controller info API client.
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
return &Client{transport: transport, formats: formats}
}
// New creates a new controller info API client with basic auth credentials.
// It takes the following parameters:
// - host: http host (github.com).
// - basePath: any base path for the API client ("/v1", "/v3").
// - scheme: http scheme ("http", "https").
// - user: user for basic authentication header.
// - password: password for basic authentication header.
func NewClientWithBasicAuth(host, basePath, scheme, user, password string) ClientService {
transport := httptransport.New(host, basePath, []string{scheme})
transport.DefaultAuthentication = httptransport.BasicAuth(user, password)
return &Client{transport: transport, formats: strfmt.Default}
}
// New creates a new controller info API client with a bearer token for authentication.
// It takes the following parameters:
// - host: http host (github.com).
// - basePath: any base path for the API client ("/v1", "/v3").
// - scheme: http scheme ("http", "https").
// - bearerToken: bearer token for Bearer authentication header.
func NewClientWithBearerToken(host, basePath, scheme, bearerToken string) ClientService {
transport := httptransport.New(host, basePath, []string{scheme})
transport.DefaultAuthentication = httptransport.BearerToken(bearerToken)
return &Client{transport: transport, formats: strfmt.Default}
}
/*
Client for controller info API
*/
type Client struct {
transport runtime.ClientTransport
formats strfmt.Registry
}
// ClientOption may be used to customize the behavior of Client methods.
type ClientOption func(*runtime.ClientOperation)
// ClientService is the interface for Client methods
type ClientService interface {
ControllerInfo(params *ControllerInfoParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ControllerInfoOK, error)
SetTransport(transport runtime.ClientTransport)
}
/*
ControllerInfo gets controller info
*/
func (a *Client) ControllerInfo(params *ControllerInfoParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ControllerInfoOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewControllerInfoParams()
}
op := &runtime.ClientOperation{
ID: "ControllerInfo",
Method: "GET",
PathPattern: "/controller-info",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &ControllerInfoReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*ControllerInfoOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for ControllerInfo: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
// SetTransport changes the transport on the client
func (a *Client) SetTransport(transport runtime.ClientTransport) {
a.transport = transport
}

View file

@ -0,0 +1,128 @@
// Code generated by go-swagger; DO NOT EDIT.
package controller_info
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewControllerInfoParams creates a new ControllerInfoParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewControllerInfoParams() *ControllerInfoParams {
return &ControllerInfoParams{
timeout: cr.DefaultTimeout,
}
}
// NewControllerInfoParamsWithTimeout creates a new ControllerInfoParams object
// with the ability to set a timeout on a request.
func NewControllerInfoParamsWithTimeout(timeout time.Duration) *ControllerInfoParams {
return &ControllerInfoParams{
timeout: timeout,
}
}
// NewControllerInfoParamsWithContext creates a new ControllerInfoParams object
// with the ability to set a context for a request.
func NewControllerInfoParamsWithContext(ctx context.Context) *ControllerInfoParams {
return &ControllerInfoParams{
Context: ctx,
}
}
// NewControllerInfoParamsWithHTTPClient creates a new ControllerInfoParams object
// with the ability to set a custom HTTPClient for a request.
func NewControllerInfoParamsWithHTTPClient(client *http.Client) *ControllerInfoParams {
return &ControllerInfoParams{
HTTPClient: client,
}
}
/*
ControllerInfoParams contains all the parameters to send to the API endpoint
for the controller info operation.
Typically these are written to a http.Request.
*/
type ControllerInfoParams struct {
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the controller info params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ControllerInfoParams) WithDefaults() *ControllerInfoParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the controller info params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ControllerInfoParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the controller info params
func (o *ControllerInfoParams) WithTimeout(timeout time.Duration) *ControllerInfoParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the controller info params
func (o *ControllerInfoParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the controller info params
func (o *ControllerInfoParams) WithContext(ctx context.Context) *ControllerInfoParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the controller info params
func (o *ControllerInfoParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the controller info params
func (o *ControllerInfoParams) WithHTTPClient(client *http.Client) *ControllerInfoParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the controller info params
func (o *ControllerInfoParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WriteToRequest writes these params to a swagger request
func (o *ControllerInfoParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package controller_info
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// ControllerInfoReader is a Reader for the ControllerInfo structure.
type ControllerInfoReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *ControllerInfoReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewControllerInfoOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 409:
result := NewControllerInfoConflict()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[GET /controller-info] ControllerInfo", response, response.Code())
}
}
// NewControllerInfoOK creates a ControllerInfoOK with default headers values
func NewControllerInfoOK() *ControllerInfoOK {
return &ControllerInfoOK{}
}
/*
ControllerInfoOK describes a response with status code 200, with default header values.
ControllerInfo
*/
type ControllerInfoOK struct {
Payload garm_params.ControllerInfo
}
// IsSuccess returns true when this controller info o k response has a 2xx status code
func (o *ControllerInfoOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this controller info o k response has a 3xx status code
func (o *ControllerInfoOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this controller info o k response has a 4xx status code
func (o *ControllerInfoOK) IsClientError() bool {
return false
}
// IsServerError returns true when this controller info o k response has a 5xx status code
func (o *ControllerInfoOK) IsServerError() bool {
return false
}
// IsCode returns true when this controller info o k response a status code equal to that given
func (o *ControllerInfoOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the controller info o k response
func (o *ControllerInfoOK) Code() int {
return 200
}
func (o *ControllerInfoOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /controller-info][%d] controllerInfoOK %s", 200, payload)
}
func (o *ControllerInfoOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /controller-info][%d] controllerInfoOK %s", 200, payload)
}
func (o *ControllerInfoOK) GetPayload() garm_params.ControllerInfo {
return o.Payload
}
func (o *ControllerInfoOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewControllerInfoConflict creates a ControllerInfoConflict with default headers values
func NewControllerInfoConflict() *ControllerInfoConflict {
return &ControllerInfoConflict{}
}
/*
ControllerInfoConflict describes a response with status code 409, with default header values.
APIErrorResponse
*/
type ControllerInfoConflict struct {
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this controller info conflict response has a 2xx status code
func (o *ControllerInfoConflict) IsSuccess() bool {
return false
}
// IsRedirect returns true when this controller info conflict response has a 3xx status code
func (o *ControllerInfoConflict) IsRedirect() bool {
return false
}
// IsClientError returns true when this controller info conflict response has a 4xx status code
func (o *ControllerInfoConflict) IsClientError() bool {
return true
}
// IsServerError returns true when this controller info conflict response has a 5xx status code
func (o *ControllerInfoConflict) IsServerError() bool {
return false
}
// IsCode returns true when this controller info conflict response a status code equal to that given
func (o *ControllerInfoConflict) IsCode(code int) bool {
return code == 409
}
// Code gets the status code for the controller info conflict response
func (o *ControllerInfoConflict) Code() int {
return 409
}
func (o *ControllerInfoConflict) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /controller-info][%d] controllerInfoConflict %s", 409, payload)
}
func (o *ControllerInfoConflict) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /controller-info][%d] controllerInfoConflict %s", 409, payload)
}
func (o *ControllerInfoConflict) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *ControllerInfoConflict) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
garm_params "github.com/cloudbase/garm/params"
)
// NewCreateCredentialsParams creates a new CreateCredentialsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewCreateCredentialsParams() *CreateCredentialsParams {
return &CreateCredentialsParams{
timeout: cr.DefaultTimeout,
}
}
// NewCreateCredentialsParamsWithTimeout creates a new CreateCredentialsParams object
// with the ability to set a timeout on a request.
func NewCreateCredentialsParamsWithTimeout(timeout time.Duration) *CreateCredentialsParams {
return &CreateCredentialsParams{
timeout: timeout,
}
}
// NewCreateCredentialsParamsWithContext creates a new CreateCredentialsParams object
// with the ability to set a context for a request.
func NewCreateCredentialsParamsWithContext(ctx context.Context) *CreateCredentialsParams {
return &CreateCredentialsParams{
Context: ctx,
}
}
// NewCreateCredentialsParamsWithHTTPClient creates a new CreateCredentialsParams object
// with the ability to set a custom HTTPClient for a request.
func NewCreateCredentialsParamsWithHTTPClient(client *http.Client) *CreateCredentialsParams {
return &CreateCredentialsParams{
HTTPClient: client,
}
}
/*
CreateCredentialsParams contains all the parameters to send to the API endpoint
for the create credentials operation.
Typically these are written to a http.Request.
*/
type CreateCredentialsParams struct {
/* Body.
Parameters used when creating a GitHub credential.
*/
Body garm_params.CreateGithubCredentialsParams
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the create credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateCredentialsParams) WithDefaults() *CreateCredentialsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the create credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateCredentialsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the create credentials params
func (o *CreateCredentialsParams) WithTimeout(timeout time.Duration) *CreateCredentialsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the create credentials params
func (o *CreateCredentialsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the create credentials params
func (o *CreateCredentialsParams) WithContext(ctx context.Context) *CreateCredentialsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the create credentials params
func (o *CreateCredentialsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the create credentials params
func (o *CreateCredentialsParams) WithHTTPClient(client *http.Client) *CreateCredentialsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the create credentials params
func (o *CreateCredentialsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the create credentials params
func (o *CreateCredentialsParams) WithBody(body garm_params.CreateGithubCredentialsParams) *CreateCredentialsParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the create credentials params
func (o *CreateCredentialsParams) SetBody(body garm_params.CreateGithubCredentialsParams) {
o.Body = body
}
// WriteToRequest writes these params to a swagger request
func (o *CreateCredentialsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// CreateCredentialsReader is a Reader for the CreateCredentials structure.
type CreateCredentialsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *CreateCredentialsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewCreateCredentialsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewCreateCredentialsBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[POST /github/credentials] CreateCredentials", response, response.Code())
}
}
// NewCreateCredentialsOK creates a CreateCredentialsOK with default headers values
func NewCreateCredentialsOK() *CreateCredentialsOK {
return &CreateCredentialsOK{}
}
/*
CreateCredentialsOK describes a response with status code 200, with default header values.
ForgeCredentials
*/
type CreateCredentialsOK struct {
Payload garm_params.ForgeCredentials
}
// IsSuccess returns true when this create credentials o k response has a 2xx status code
func (o *CreateCredentialsOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this create credentials o k response has a 3xx status code
func (o *CreateCredentialsOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this create credentials o k response has a 4xx status code
func (o *CreateCredentialsOK) IsClientError() bool {
return false
}
// IsServerError returns true when this create credentials o k response has a 5xx status code
func (o *CreateCredentialsOK) IsServerError() bool {
return false
}
// IsCode returns true when this create credentials o k response a status code equal to that given
func (o *CreateCredentialsOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the create credentials o k response
func (o *CreateCredentialsOK) Code() int {
return 200
}
func (o *CreateCredentialsOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /github/credentials][%d] createCredentialsOK %s", 200, payload)
}
func (o *CreateCredentialsOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /github/credentials][%d] createCredentialsOK %s", 200, payload)
}
func (o *CreateCredentialsOK) GetPayload() garm_params.ForgeCredentials {
return o.Payload
}
func (o *CreateCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewCreateCredentialsBadRequest creates a CreateCredentialsBadRequest with default headers values
func NewCreateCredentialsBadRequest() *CreateCredentialsBadRequest {
return &CreateCredentialsBadRequest{}
}
/*
CreateCredentialsBadRequest describes a response with status code 400, with default header values.
APIErrorResponse
*/
type CreateCredentialsBadRequest struct {
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this create credentials bad request response has a 2xx status code
func (o *CreateCredentialsBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this create credentials bad request response has a 3xx status code
func (o *CreateCredentialsBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this create credentials bad request response has a 4xx status code
func (o *CreateCredentialsBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this create credentials bad request response has a 5xx status code
func (o *CreateCredentialsBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this create credentials bad request response a status code equal to that given
func (o *CreateCredentialsBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the create credentials bad request response
func (o *CreateCredentialsBadRequest) Code() int {
return 400
}
func (o *CreateCredentialsBadRequest) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /github/credentials][%d] createCredentialsBadRequest %s", 400, payload)
}
func (o *CreateCredentialsBadRequest) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /github/credentials][%d] createCredentialsBadRequest %s", 400, payload)
}
func (o *CreateCredentialsBadRequest) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *CreateCredentialsBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
garm_params "github.com/cloudbase/garm/params"
)
// NewCreateGiteaCredentialsParams creates a new CreateGiteaCredentialsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewCreateGiteaCredentialsParams() *CreateGiteaCredentialsParams {
return &CreateGiteaCredentialsParams{
timeout: cr.DefaultTimeout,
}
}
// NewCreateGiteaCredentialsParamsWithTimeout creates a new CreateGiteaCredentialsParams object
// with the ability to set a timeout on a request.
func NewCreateGiteaCredentialsParamsWithTimeout(timeout time.Duration) *CreateGiteaCredentialsParams {
return &CreateGiteaCredentialsParams{
timeout: timeout,
}
}
// NewCreateGiteaCredentialsParamsWithContext creates a new CreateGiteaCredentialsParams object
// with the ability to set a context for a request.
func NewCreateGiteaCredentialsParamsWithContext(ctx context.Context) *CreateGiteaCredentialsParams {
return &CreateGiteaCredentialsParams{
Context: ctx,
}
}
// NewCreateGiteaCredentialsParamsWithHTTPClient creates a new CreateGiteaCredentialsParams object
// with the ability to set a custom HTTPClient for a request.
func NewCreateGiteaCredentialsParamsWithHTTPClient(client *http.Client) *CreateGiteaCredentialsParams {
return &CreateGiteaCredentialsParams{
HTTPClient: client,
}
}
/*
CreateGiteaCredentialsParams contains all the parameters to send to the API endpoint
for the create gitea credentials operation.
Typically these are written to a http.Request.
*/
type CreateGiteaCredentialsParams struct {
/* Body.
Parameters used when creating a Gitea credential.
*/
Body garm_params.CreateGiteaCredentialsParams
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the create gitea credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateGiteaCredentialsParams) WithDefaults() *CreateGiteaCredentialsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the create gitea credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateGiteaCredentialsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the create gitea credentials params
func (o *CreateGiteaCredentialsParams) WithTimeout(timeout time.Duration) *CreateGiteaCredentialsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the create gitea credentials params
func (o *CreateGiteaCredentialsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the create gitea credentials params
func (o *CreateGiteaCredentialsParams) WithContext(ctx context.Context) *CreateGiteaCredentialsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the create gitea credentials params
func (o *CreateGiteaCredentialsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the create gitea credentials params
func (o *CreateGiteaCredentialsParams) WithHTTPClient(client *http.Client) *CreateGiteaCredentialsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the create gitea credentials params
func (o *CreateGiteaCredentialsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the create gitea credentials params
func (o *CreateGiteaCredentialsParams) WithBody(body garm_params.CreateGiteaCredentialsParams) *CreateGiteaCredentialsParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the create gitea credentials params
func (o *CreateGiteaCredentialsParams) SetBody(body garm_params.CreateGiteaCredentialsParams) {
o.Body = body
}
// WriteToRequest writes these params to a swagger request
func (o *CreateGiteaCredentialsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// CreateGiteaCredentialsReader is a Reader for the CreateGiteaCredentials structure.
type CreateGiteaCredentialsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *CreateGiteaCredentialsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewCreateGiteaCredentialsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewCreateGiteaCredentialsBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[POST /gitea/credentials] CreateGiteaCredentials", response, response.Code())
}
}
// NewCreateGiteaCredentialsOK creates a CreateGiteaCredentialsOK with default headers values
func NewCreateGiteaCredentialsOK() *CreateGiteaCredentialsOK {
return &CreateGiteaCredentialsOK{}
}
/*
CreateGiteaCredentialsOK describes a response with status code 200, with default header values.
ForgeCredentials
*/
type CreateGiteaCredentialsOK struct {
Payload garm_params.ForgeCredentials
}
// IsSuccess returns true when this create gitea credentials o k response has a 2xx status code
func (o *CreateGiteaCredentialsOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this create gitea credentials o k response has a 3xx status code
func (o *CreateGiteaCredentialsOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this create gitea credentials o k response has a 4xx status code
func (o *CreateGiteaCredentialsOK) IsClientError() bool {
return false
}
// IsServerError returns true when this create gitea credentials o k response has a 5xx status code
func (o *CreateGiteaCredentialsOK) IsServerError() bool {
return false
}
// IsCode returns true when this create gitea credentials o k response a status code equal to that given
func (o *CreateGiteaCredentialsOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the create gitea credentials o k response
func (o *CreateGiteaCredentialsOK) Code() int {
return 200
}
func (o *CreateGiteaCredentialsOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /gitea/credentials][%d] createGiteaCredentialsOK %s", 200, payload)
}
func (o *CreateGiteaCredentialsOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /gitea/credentials][%d] createGiteaCredentialsOK %s", 200, payload)
}
func (o *CreateGiteaCredentialsOK) GetPayload() garm_params.ForgeCredentials {
return o.Payload
}
func (o *CreateGiteaCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewCreateGiteaCredentialsBadRequest creates a CreateGiteaCredentialsBadRequest with default headers values
func NewCreateGiteaCredentialsBadRequest() *CreateGiteaCredentialsBadRequest {
return &CreateGiteaCredentialsBadRequest{}
}
/*
CreateGiteaCredentialsBadRequest describes a response with status code 400, with default header values.
APIErrorResponse
*/
type CreateGiteaCredentialsBadRequest struct {
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this create gitea credentials bad request response has a 2xx status code
func (o *CreateGiteaCredentialsBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this create gitea credentials bad request response has a 3xx status code
func (o *CreateGiteaCredentialsBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this create gitea credentials bad request response has a 4xx status code
func (o *CreateGiteaCredentialsBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this create gitea credentials bad request response has a 5xx status code
func (o *CreateGiteaCredentialsBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this create gitea credentials bad request response a status code equal to that given
func (o *CreateGiteaCredentialsBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the create gitea credentials bad request response
func (o *CreateGiteaCredentialsBadRequest) Code() int {
return 400
}
func (o *CreateGiteaCredentialsBadRequest) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /gitea/credentials][%d] createGiteaCredentialsBadRequest %s", 400, payload)
}
func (o *CreateGiteaCredentialsBadRequest) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /gitea/credentials][%d] createGiteaCredentialsBadRequest %s", 400, payload)
}
func (o *CreateGiteaCredentialsBadRequest) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *CreateGiteaCredentialsBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,461 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"fmt"
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// New creates a new credentials API client.
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
return &Client{transport: transport, formats: formats}
}
// New creates a new credentials API client with basic auth credentials.
// It takes the following parameters:
// - host: http host (github.com).
// - basePath: any base path for the API client ("/v1", "/v3").
// - scheme: http scheme ("http", "https").
// - user: user for basic authentication header.
// - password: password for basic authentication header.
func NewClientWithBasicAuth(host, basePath, scheme, user, password string) ClientService {
transport := httptransport.New(host, basePath, []string{scheme})
transport.DefaultAuthentication = httptransport.BasicAuth(user, password)
return &Client{transport: transport, formats: strfmt.Default}
}
// New creates a new credentials API client with a bearer token for authentication.
// It takes the following parameters:
// - host: http host (github.com).
// - basePath: any base path for the API client ("/v1", "/v3").
// - scheme: http scheme ("http", "https").
// - bearerToken: bearer token for Bearer authentication header.
func NewClientWithBearerToken(host, basePath, scheme, bearerToken string) ClientService {
transport := httptransport.New(host, basePath, []string{scheme})
transport.DefaultAuthentication = httptransport.BearerToken(bearerToken)
return &Client{transport: transport, formats: strfmt.Default}
}
/*
Client for credentials API
*/
type Client struct {
transport runtime.ClientTransport
formats strfmt.Registry
}
// ClientOption may be used to customize the behavior of Client methods.
type ClientOption func(*runtime.ClientOperation)
// ClientService is the interface for Client methods
type ClientService interface {
CreateCredentials(params *CreateCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateCredentialsOK, error)
CreateGiteaCredentials(params *CreateGiteaCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateGiteaCredentialsOK, error)
DeleteCredentials(params *DeleteCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error
DeleteGiteaCredentials(params *DeleteGiteaCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error
GetCredentials(params *GetCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetCredentialsOK, error)
GetGiteaCredentials(params *GetGiteaCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetGiteaCredentialsOK, error)
ListCredentials(params *ListCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListCredentialsOK, error)
ListGiteaCredentials(params *ListGiteaCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListGiteaCredentialsOK, error)
UpdateCredentials(params *UpdateCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateCredentialsOK, error)
UpdateGiteaCredentials(params *UpdateGiteaCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateGiteaCredentialsOK, error)
SetTransport(transport runtime.ClientTransport)
}
/*
CreateCredentials creates a git hub credential
*/
func (a *Client) CreateCredentials(params *CreateCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateCredentialsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewCreateCredentialsParams()
}
op := &runtime.ClientOperation{
ID: "CreateCredentials",
Method: "POST",
PathPattern: "/github/credentials",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &CreateCredentialsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*CreateCredentialsOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for CreateCredentials: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
CreateGiteaCredentials creates a gitea credential
*/
func (a *Client) CreateGiteaCredentials(params *CreateGiteaCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateGiteaCredentialsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewCreateGiteaCredentialsParams()
}
op := &runtime.ClientOperation{
ID: "CreateGiteaCredentials",
Method: "POST",
PathPattern: "/gitea/credentials",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &CreateGiteaCredentialsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*CreateGiteaCredentialsOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for CreateGiteaCredentials: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
DeleteCredentials deletes a git hub credential
*/
func (a *Client) DeleteCredentials(params *DeleteCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error {
// TODO: Validate the params before sending
if params == nil {
params = NewDeleteCredentialsParams()
}
op := &runtime.ClientOperation{
ID: "DeleteCredentials",
Method: "DELETE",
PathPattern: "/github/credentials/{id}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &DeleteCredentialsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
_, err := a.transport.Submit(op)
if err != nil {
return err
}
return nil
}
/*
DeleteGiteaCredentials deletes a gitea credential
*/
func (a *Client) DeleteGiteaCredentials(params *DeleteGiteaCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error {
// TODO: Validate the params before sending
if params == nil {
params = NewDeleteGiteaCredentialsParams()
}
op := &runtime.ClientOperation{
ID: "DeleteGiteaCredentials",
Method: "DELETE",
PathPattern: "/gitea/credentials/{id}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &DeleteGiteaCredentialsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
_, err := a.transport.Submit(op)
if err != nil {
return err
}
return nil
}
/*
GetCredentials gets a git hub credential
*/
func (a *Client) GetCredentials(params *GetCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetCredentialsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewGetCredentialsParams()
}
op := &runtime.ClientOperation{
ID: "GetCredentials",
Method: "GET",
PathPattern: "/github/credentials/{id}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &GetCredentialsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*GetCredentialsOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for GetCredentials: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
GetGiteaCredentials gets a gitea credential
*/
func (a *Client) GetGiteaCredentials(params *GetGiteaCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetGiteaCredentialsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewGetGiteaCredentialsParams()
}
op := &runtime.ClientOperation{
ID: "GetGiteaCredentials",
Method: "GET",
PathPattern: "/gitea/credentials/{id}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &GetGiteaCredentialsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*GetGiteaCredentialsOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for GetGiteaCredentials: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
ListCredentials lists all credentials
*/
func (a *Client) ListCredentials(params *ListCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListCredentialsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewListCredentialsParams()
}
op := &runtime.ClientOperation{
ID: "ListCredentials",
Method: "GET",
PathPattern: "/github/credentials",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &ListCredentialsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*ListCredentialsOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for ListCredentials: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
ListGiteaCredentials lists all credentials
*/
func (a *Client) ListGiteaCredentials(params *ListGiteaCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListGiteaCredentialsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewListGiteaCredentialsParams()
}
op := &runtime.ClientOperation{
ID: "ListGiteaCredentials",
Method: "GET",
PathPattern: "/gitea/credentials",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &ListGiteaCredentialsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*ListGiteaCredentialsOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for ListGiteaCredentials: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
UpdateCredentials updates a git hub credential
*/
func (a *Client) UpdateCredentials(params *UpdateCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateCredentialsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewUpdateCredentialsParams()
}
op := &runtime.ClientOperation{
ID: "UpdateCredentials",
Method: "PUT",
PathPattern: "/github/credentials/{id}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &UpdateCredentialsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*UpdateCredentialsOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for UpdateCredentials: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
UpdateGiteaCredentials updates a gitea credential
*/
func (a *Client) UpdateGiteaCredentials(params *UpdateGiteaCredentialsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateGiteaCredentialsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewUpdateGiteaCredentialsParams()
}
op := &runtime.ClientOperation{
ID: "UpdateGiteaCredentials",
Method: "PUT",
PathPattern: "/gitea/credentials/{id}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &UpdateGiteaCredentialsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*UpdateGiteaCredentialsOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for UpdateGiteaCredentials: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
// SetTransport changes the transport on the client
func (a *Client) SetTransport(transport runtime.ClientTransport) {
a.transport = transport
}

View file

@ -0,0 +1,152 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// NewDeleteCredentialsParams creates a new DeleteCredentialsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewDeleteCredentialsParams() *DeleteCredentialsParams {
return &DeleteCredentialsParams{
timeout: cr.DefaultTimeout,
}
}
// NewDeleteCredentialsParamsWithTimeout creates a new DeleteCredentialsParams object
// with the ability to set a timeout on a request.
func NewDeleteCredentialsParamsWithTimeout(timeout time.Duration) *DeleteCredentialsParams {
return &DeleteCredentialsParams{
timeout: timeout,
}
}
// NewDeleteCredentialsParamsWithContext creates a new DeleteCredentialsParams object
// with the ability to set a context for a request.
func NewDeleteCredentialsParamsWithContext(ctx context.Context) *DeleteCredentialsParams {
return &DeleteCredentialsParams{
Context: ctx,
}
}
// NewDeleteCredentialsParamsWithHTTPClient creates a new DeleteCredentialsParams object
// with the ability to set a custom HTTPClient for a request.
func NewDeleteCredentialsParamsWithHTTPClient(client *http.Client) *DeleteCredentialsParams {
return &DeleteCredentialsParams{
HTTPClient: client,
}
}
/*
DeleteCredentialsParams contains all the parameters to send to the API endpoint
for the delete credentials operation.
Typically these are written to a http.Request.
*/
type DeleteCredentialsParams struct {
/* ID.
ID of the GitHub credential.
*/
ID int64
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the delete credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *DeleteCredentialsParams) WithDefaults() *DeleteCredentialsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the delete credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *DeleteCredentialsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the delete credentials params
func (o *DeleteCredentialsParams) WithTimeout(timeout time.Duration) *DeleteCredentialsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the delete credentials params
func (o *DeleteCredentialsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the delete credentials params
func (o *DeleteCredentialsParams) WithContext(ctx context.Context) *DeleteCredentialsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the delete credentials params
func (o *DeleteCredentialsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the delete credentials params
func (o *DeleteCredentialsParams) WithHTTPClient(client *http.Client) *DeleteCredentialsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the delete credentials params
func (o *DeleteCredentialsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithID adds the id to the delete credentials params
func (o *DeleteCredentialsParams) WithID(id int64) *DeleteCredentialsParams {
o.SetID(id)
return o
}
// SetID adds the id to the delete credentials params
func (o *DeleteCredentialsParams) SetID(id int64) {
o.ID = id
}
// WriteToRequest writes these params to a swagger request
func (o *DeleteCredentialsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param id
if err := r.SetPathParam("id", swag.FormatInt64(o.ID)); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,106 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
)
// DeleteCredentialsReader is a Reader for the DeleteCredentials structure.
type DeleteCredentialsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *DeleteCredentialsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
result := NewDeleteCredentialsDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
// NewDeleteCredentialsDefault creates a DeleteCredentialsDefault with default headers values
func NewDeleteCredentialsDefault(code int) *DeleteCredentialsDefault {
return &DeleteCredentialsDefault{
_statusCode: code,
}
}
/*
DeleteCredentialsDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type DeleteCredentialsDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this delete credentials default response has a 2xx status code
func (o *DeleteCredentialsDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this delete credentials default response has a 3xx status code
func (o *DeleteCredentialsDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this delete credentials default response has a 4xx status code
func (o *DeleteCredentialsDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this delete credentials default response has a 5xx status code
func (o *DeleteCredentialsDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this delete credentials default response a status code equal to that given
func (o *DeleteCredentialsDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the delete credentials default response
func (o *DeleteCredentialsDefault) Code() int {
return o._statusCode
}
func (o *DeleteCredentialsDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[DELETE /github/credentials/{id}][%d] DeleteCredentials default %s", o._statusCode, payload)
}
func (o *DeleteCredentialsDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[DELETE /github/credentials/{id}][%d] DeleteCredentials default %s", o._statusCode, payload)
}
func (o *DeleteCredentialsDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *DeleteCredentialsDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,152 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// NewDeleteGiteaCredentialsParams creates a new DeleteGiteaCredentialsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewDeleteGiteaCredentialsParams() *DeleteGiteaCredentialsParams {
return &DeleteGiteaCredentialsParams{
timeout: cr.DefaultTimeout,
}
}
// NewDeleteGiteaCredentialsParamsWithTimeout creates a new DeleteGiteaCredentialsParams object
// with the ability to set a timeout on a request.
func NewDeleteGiteaCredentialsParamsWithTimeout(timeout time.Duration) *DeleteGiteaCredentialsParams {
return &DeleteGiteaCredentialsParams{
timeout: timeout,
}
}
// NewDeleteGiteaCredentialsParamsWithContext creates a new DeleteGiteaCredentialsParams object
// with the ability to set a context for a request.
func NewDeleteGiteaCredentialsParamsWithContext(ctx context.Context) *DeleteGiteaCredentialsParams {
return &DeleteGiteaCredentialsParams{
Context: ctx,
}
}
// NewDeleteGiteaCredentialsParamsWithHTTPClient creates a new DeleteGiteaCredentialsParams object
// with the ability to set a custom HTTPClient for a request.
func NewDeleteGiteaCredentialsParamsWithHTTPClient(client *http.Client) *DeleteGiteaCredentialsParams {
return &DeleteGiteaCredentialsParams{
HTTPClient: client,
}
}
/*
DeleteGiteaCredentialsParams contains all the parameters to send to the API endpoint
for the delete gitea credentials operation.
Typically these are written to a http.Request.
*/
type DeleteGiteaCredentialsParams struct {
/* ID.
ID of the Gitea credential.
*/
ID int64
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the delete gitea credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *DeleteGiteaCredentialsParams) WithDefaults() *DeleteGiteaCredentialsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the delete gitea credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *DeleteGiteaCredentialsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the delete gitea credentials params
func (o *DeleteGiteaCredentialsParams) WithTimeout(timeout time.Duration) *DeleteGiteaCredentialsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the delete gitea credentials params
func (o *DeleteGiteaCredentialsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the delete gitea credentials params
func (o *DeleteGiteaCredentialsParams) WithContext(ctx context.Context) *DeleteGiteaCredentialsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the delete gitea credentials params
func (o *DeleteGiteaCredentialsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the delete gitea credentials params
func (o *DeleteGiteaCredentialsParams) WithHTTPClient(client *http.Client) *DeleteGiteaCredentialsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the delete gitea credentials params
func (o *DeleteGiteaCredentialsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithID adds the id to the delete gitea credentials params
func (o *DeleteGiteaCredentialsParams) WithID(id int64) *DeleteGiteaCredentialsParams {
o.SetID(id)
return o
}
// SetID adds the id to the delete gitea credentials params
func (o *DeleteGiteaCredentialsParams) SetID(id int64) {
o.ID = id
}
// WriteToRequest writes these params to a swagger request
func (o *DeleteGiteaCredentialsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param id
if err := r.SetPathParam("id", swag.FormatInt64(o.ID)); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,106 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
)
// DeleteGiteaCredentialsReader is a Reader for the DeleteGiteaCredentials structure.
type DeleteGiteaCredentialsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *DeleteGiteaCredentialsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
result := NewDeleteGiteaCredentialsDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
// NewDeleteGiteaCredentialsDefault creates a DeleteGiteaCredentialsDefault with default headers values
func NewDeleteGiteaCredentialsDefault(code int) *DeleteGiteaCredentialsDefault {
return &DeleteGiteaCredentialsDefault{
_statusCode: code,
}
}
/*
DeleteGiteaCredentialsDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type DeleteGiteaCredentialsDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this delete gitea credentials default response has a 2xx status code
func (o *DeleteGiteaCredentialsDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this delete gitea credentials default response has a 3xx status code
func (o *DeleteGiteaCredentialsDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this delete gitea credentials default response has a 4xx status code
func (o *DeleteGiteaCredentialsDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this delete gitea credentials default response has a 5xx status code
func (o *DeleteGiteaCredentialsDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this delete gitea credentials default response a status code equal to that given
func (o *DeleteGiteaCredentialsDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the delete gitea credentials default response
func (o *DeleteGiteaCredentialsDefault) Code() int {
return o._statusCode
}
func (o *DeleteGiteaCredentialsDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[DELETE /gitea/credentials/{id}][%d] DeleteGiteaCredentials default %s", o._statusCode, payload)
}
func (o *DeleteGiteaCredentialsDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[DELETE /gitea/credentials/{id}][%d] DeleteGiteaCredentials default %s", o._statusCode, payload)
}
func (o *DeleteGiteaCredentialsDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *DeleteGiteaCredentialsDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,152 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// NewGetCredentialsParams creates a new GetCredentialsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewGetCredentialsParams() *GetCredentialsParams {
return &GetCredentialsParams{
timeout: cr.DefaultTimeout,
}
}
// NewGetCredentialsParamsWithTimeout creates a new GetCredentialsParams object
// with the ability to set a timeout on a request.
func NewGetCredentialsParamsWithTimeout(timeout time.Duration) *GetCredentialsParams {
return &GetCredentialsParams{
timeout: timeout,
}
}
// NewGetCredentialsParamsWithContext creates a new GetCredentialsParams object
// with the ability to set a context for a request.
func NewGetCredentialsParamsWithContext(ctx context.Context) *GetCredentialsParams {
return &GetCredentialsParams{
Context: ctx,
}
}
// NewGetCredentialsParamsWithHTTPClient creates a new GetCredentialsParams object
// with the ability to set a custom HTTPClient for a request.
func NewGetCredentialsParamsWithHTTPClient(client *http.Client) *GetCredentialsParams {
return &GetCredentialsParams{
HTTPClient: client,
}
}
/*
GetCredentialsParams contains all the parameters to send to the API endpoint
for the get credentials operation.
Typically these are written to a http.Request.
*/
type GetCredentialsParams struct {
/* ID.
ID of the GitHub credential.
*/
ID int64
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the get credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetCredentialsParams) WithDefaults() *GetCredentialsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the get credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetCredentialsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the get credentials params
func (o *GetCredentialsParams) WithTimeout(timeout time.Duration) *GetCredentialsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the get credentials params
func (o *GetCredentialsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the get credentials params
func (o *GetCredentialsParams) WithContext(ctx context.Context) *GetCredentialsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the get credentials params
func (o *GetCredentialsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the get credentials params
func (o *GetCredentialsParams) WithHTTPClient(client *http.Client) *GetCredentialsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the get credentials params
func (o *GetCredentialsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithID adds the id to the get credentials params
func (o *GetCredentialsParams) WithID(id int64) *GetCredentialsParams {
o.SetID(id)
return o
}
// SetID adds the id to the get credentials params
func (o *GetCredentialsParams) SetID(id int64) {
o.ID = id
}
// WriteToRequest writes these params to a swagger request
func (o *GetCredentialsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param id
if err := r.SetPathParam("id", swag.FormatInt64(o.ID)); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// GetCredentialsReader is a Reader for the GetCredentials structure.
type GetCredentialsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *GetCredentialsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewGetCredentialsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewGetCredentialsBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[GET /github/credentials/{id}] GetCredentials", response, response.Code())
}
}
// NewGetCredentialsOK creates a GetCredentialsOK with default headers values
func NewGetCredentialsOK() *GetCredentialsOK {
return &GetCredentialsOK{}
}
/*
GetCredentialsOK describes a response with status code 200, with default header values.
ForgeCredentials
*/
type GetCredentialsOK struct {
Payload garm_params.ForgeCredentials
}
// IsSuccess returns true when this get credentials o k response has a 2xx status code
func (o *GetCredentialsOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this get credentials o k response has a 3xx status code
func (o *GetCredentialsOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this get credentials o k response has a 4xx status code
func (o *GetCredentialsOK) IsClientError() bool {
return false
}
// IsServerError returns true when this get credentials o k response has a 5xx status code
func (o *GetCredentialsOK) IsServerError() bool {
return false
}
// IsCode returns true when this get credentials o k response a status code equal to that given
func (o *GetCredentialsOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the get credentials o k response
func (o *GetCredentialsOK) Code() int {
return 200
}
func (o *GetCredentialsOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/credentials/{id}][%d] getCredentialsOK %s", 200, payload)
}
func (o *GetCredentialsOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/credentials/{id}][%d] getCredentialsOK %s", 200, payload)
}
func (o *GetCredentialsOK) GetPayload() garm_params.ForgeCredentials {
return o.Payload
}
func (o *GetCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewGetCredentialsBadRequest creates a GetCredentialsBadRequest with default headers values
func NewGetCredentialsBadRequest() *GetCredentialsBadRequest {
return &GetCredentialsBadRequest{}
}
/*
GetCredentialsBadRequest describes a response with status code 400, with default header values.
APIErrorResponse
*/
type GetCredentialsBadRequest struct {
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this get credentials bad request response has a 2xx status code
func (o *GetCredentialsBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this get credentials bad request response has a 3xx status code
func (o *GetCredentialsBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this get credentials bad request response has a 4xx status code
func (o *GetCredentialsBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this get credentials bad request response has a 5xx status code
func (o *GetCredentialsBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this get credentials bad request response a status code equal to that given
func (o *GetCredentialsBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the get credentials bad request response
func (o *GetCredentialsBadRequest) Code() int {
return 400
}
func (o *GetCredentialsBadRequest) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/credentials/{id}][%d] getCredentialsBadRequest %s", 400, payload)
}
func (o *GetCredentialsBadRequest) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/credentials/{id}][%d] getCredentialsBadRequest %s", 400, payload)
}
func (o *GetCredentialsBadRequest) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *GetCredentialsBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,152 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// NewGetGiteaCredentialsParams creates a new GetGiteaCredentialsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewGetGiteaCredentialsParams() *GetGiteaCredentialsParams {
return &GetGiteaCredentialsParams{
timeout: cr.DefaultTimeout,
}
}
// NewGetGiteaCredentialsParamsWithTimeout creates a new GetGiteaCredentialsParams object
// with the ability to set a timeout on a request.
func NewGetGiteaCredentialsParamsWithTimeout(timeout time.Duration) *GetGiteaCredentialsParams {
return &GetGiteaCredentialsParams{
timeout: timeout,
}
}
// NewGetGiteaCredentialsParamsWithContext creates a new GetGiteaCredentialsParams object
// with the ability to set a context for a request.
func NewGetGiteaCredentialsParamsWithContext(ctx context.Context) *GetGiteaCredentialsParams {
return &GetGiteaCredentialsParams{
Context: ctx,
}
}
// NewGetGiteaCredentialsParamsWithHTTPClient creates a new GetGiteaCredentialsParams object
// with the ability to set a custom HTTPClient for a request.
func NewGetGiteaCredentialsParamsWithHTTPClient(client *http.Client) *GetGiteaCredentialsParams {
return &GetGiteaCredentialsParams{
HTTPClient: client,
}
}
/*
GetGiteaCredentialsParams contains all the parameters to send to the API endpoint
for the get gitea credentials operation.
Typically these are written to a http.Request.
*/
type GetGiteaCredentialsParams struct {
/* ID.
ID of the Gitea credential.
*/
ID int64
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the get gitea credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetGiteaCredentialsParams) WithDefaults() *GetGiteaCredentialsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the get gitea credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetGiteaCredentialsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the get gitea credentials params
func (o *GetGiteaCredentialsParams) WithTimeout(timeout time.Duration) *GetGiteaCredentialsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the get gitea credentials params
func (o *GetGiteaCredentialsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the get gitea credentials params
func (o *GetGiteaCredentialsParams) WithContext(ctx context.Context) *GetGiteaCredentialsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the get gitea credentials params
func (o *GetGiteaCredentialsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the get gitea credentials params
func (o *GetGiteaCredentialsParams) WithHTTPClient(client *http.Client) *GetGiteaCredentialsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the get gitea credentials params
func (o *GetGiteaCredentialsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithID adds the id to the get gitea credentials params
func (o *GetGiteaCredentialsParams) WithID(id int64) *GetGiteaCredentialsParams {
o.SetID(id)
return o
}
// SetID adds the id to the get gitea credentials params
func (o *GetGiteaCredentialsParams) SetID(id int64) {
o.ID = id
}
// WriteToRequest writes these params to a swagger request
func (o *GetGiteaCredentialsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param id
if err := r.SetPathParam("id", swag.FormatInt64(o.ID)); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// GetGiteaCredentialsReader is a Reader for the GetGiteaCredentials structure.
type GetGiteaCredentialsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *GetGiteaCredentialsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewGetGiteaCredentialsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewGetGiteaCredentialsBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[GET /gitea/credentials/{id}] GetGiteaCredentials", response, response.Code())
}
}
// NewGetGiteaCredentialsOK creates a GetGiteaCredentialsOK with default headers values
func NewGetGiteaCredentialsOK() *GetGiteaCredentialsOK {
return &GetGiteaCredentialsOK{}
}
/*
GetGiteaCredentialsOK describes a response with status code 200, with default header values.
ForgeCredentials
*/
type GetGiteaCredentialsOK struct {
Payload garm_params.ForgeCredentials
}
// IsSuccess returns true when this get gitea credentials o k response has a 2xx status code
func (o *GetGiteaCredentialsOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this get gitea credentials o k response has a 3xx status code
func (o *GetGiteaCredentialsOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this get gitea credentials o k response has a 4xx status code
func (o *GetGiteaCredentialsOK) IsClientError() bool {
return false
}
// IsServerError returns true when this get gitea credentials o k response has a 5xx status code
func (o *GetGiteaCredentialsOK) IsServerError() bool {
return false
}
// IsCode returns true when this get gitea credentials o k response a status code equal to that given
func (o *GetGiteaCredentialsOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the get gitea credentials o k response
func (o *GetGiteaCredentialsOK) Code() int {
return 200
}
func (o *GetGiteaCredentialsOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/credentials/{id}][%d] getGiteaCredentialsOK %s", 200, payload)
}
func (o *GetGiteaCredentialsOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/credentials/{id}][%d] getGiteaCredentialsOK %s", 200, payload)
}
func (o *GetGiteaCredentialsOK) GetPayload() garm_params.ForgeCredentials {
return o.Payload
}
func (o *GetGiteaCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewGetGiteaCredentialsBadRequest creates a GetGiteaCredentialsBadRequest with default headers values
func NewGetGiteaCredentialsBadRequest() *GetGiteaCredentialsBadRequest {
return &GetGiteaCredentialsBadRequest{}
}
/*
GetGiteaCredentialsBadRequest describes a response with status code 400, with default header values.
APIErrorResponse
*/
type GetGiteaCredentialsBadRequest struct {
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this get gitea credentials bad request response has a 2xx status code
func (o *GetGiteaCredentialsBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this get gitea credentials bad request response has a 3xx status code
func (o *GetGiteaCredentialsBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this get gitea credentials bad request response has a 4xx status code
func (o *GetGiteaCredentialsBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this get gitea credentials bad request response has a 5xx status code
func (o *GetGiteaCredentialsBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this get gitea credentials bad request response a status code equal to that given
func (o *GetGiteaCredentialsBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the get gitea credentials bad request response
func (o *GetGiteaCredentialsBadRequest) Code() int {
return 400
}
func (o *GetGiteaCredentialsBadRequest) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/credentials/{id}][%d] getGiteaCredentialsBadRequest %s", 400, payload)
}
func (o *GetGiteaCredentialsBadRequest) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/credentials/{id}][%d] getGiteaCredentialsBadRequest %s", 400, payload)
}
func (o *GetGiteaCredentialsBadRequest) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *GetGiteaCredentialsBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,128 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewListCredentialsParams creates a new ListCredentialsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewListCredentialsParams() *ListCredentialsParams {
return &ListCredentialsParams{
timeout: cr.DefaultTimeout,
}
}
// NewListCredentialsParamsWithTimeout creates a new ListCredentialsParams object
// with the ability to set a timeout on a request.
func NewListCredentialsParamsWithTimeout(timeout time.Duration) *ListCredentialsParams {
return &ListCredentialsParams{
timeout: timeout,
}
}
// NewListCredentialsParamsWithContext creates a new ListCredentialsParams object
// with the ability to set a context for a request.
func NewListCredentialsParamsWithContext(ctx context.Context) *ListCredentialsParams {
return &ListCredentialsParams{
Context: ctx,
}
}
// NewListCredentialsParamsWithHTTPClient creates a new ListCredentialsParams object
// with the ability to set a custom HTTPClient for a request.
func NewListCredentialsParamsWithHTTPClient(client *http.Client) *ListCredentialsParams {
return &ListCredentialsParams{
HTTPClient: client,
}
}
/*
ListCredentialsParams contains all the parameters to send to the API endpoint
for the list credentials operation.
Typically these are written to a http.Request.
*/
type ListCredentialsParams struct {
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the list credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ListCredentialsParams) WithDefaults() *ListCredentialsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the list credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ListCredentialsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the list credentials params
func (o *ListCredentialsParams) WithTimeout(timeout time.Duration) *ListCredentialsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the list credentials params
func (o *ListCredentialsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the list credentials params
func (o *ListCredentialsParams) WithContext(ctx context.Context) *ListCredentialsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the list credentials params
func (o *ListCredentialsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the list credentials params
func (o *ListCredentialsParams) WithHTTPClient(client *http.Client) *ListCredentialsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the list credentials params
func (o *ListCredentialsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WriteToRequest writes these params to a swagger request
func (o *ListCredentialsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// ListCredentialsReader is a Reader for the ListCredentials structure.
type ListCredentialsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *ListCredentialsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewListCredentialsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewListCredentialsBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[GET /github/credentials] ListCredentials", response, response.Code())
}
}
// NewListCredentialsOK creates a ListCredentialsOK with default headers values
func NewListCredentialsOK() *ListCredentialsOK {
return &ListCredentialsOK{}
}
/*
ListCredentialsOK describes a response with status code 200, with default header values.
Credentials
*/
type ListCredentialsOK struct {
Payload garm_params.Credentials
}
// IsSuccess returns true when this list credentials o k response has a 2xx status code
func (o *ListCredentialsOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this list credentials o k response has a 3xx status code
func (o *ListCredentialsOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this list credentials o k response has a 4xx status code
func (o *ListCredentialsOK) IsClientError() bool {
return false
}
// IsServerError returns true when this list credentials o k response has a 5xx status code
func (o *ListCredentialsOK) IsServerError() bool {
return false
}
// IsCode returns true when this list credentials o k response a status code equal to that given
func (o *ListCredentialsOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the list credentials o k response
func (o *ListCredentialsOK) Code() int {
return 200
}
func (o *ListCredentialsOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/credentials][%d] listCredentialsOK %s", 200, payload)
}
func (o *ListCredentialsOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/credentials][%d] listCredentialsOK %s", 200, payload)
}
func (o *ListCredentialsOK) GetPayload() garm_params.Credentials {
return o.Payload
}
func (o *ListCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewListCredentialsBadRequest creates a ListCredentialsBadRequest with default headers values
func NewListCredentialsBadRequest() *ListCredentialsBadRequest {
return &ListCredentialsBadRequest{}
}
/*
ListCredentialsBadRequest describes a response with status code 400, with default header values.
APIErrorResponse
*/
type ListCredentialsBadRequest struct {
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this list credentials bad request response has a 2xx status code
func (o *ListCredentialsBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this list credentials bad request response has a 3xx status code
func (o *ListCredentialsBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this list credentials bad request response has a 4xx status code
func (o *ListCredentialsBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this list credentials bad request response has a 5xx status code
func (o *ListCredentialsBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this list credentials bad request response a status code equal to that given
func (o *ListCredentialsBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the list credentials bad request response
func (o *ListCredentialsBadRequest) Code() int {
return 400
}
func (o *ListCredentialsBadRequest) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/credentials][%d] listCredentialsBadRequest %s", 400, payload)
}
func (o *ListCredentialsBadRequest) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/credentials][%d] listCredentialsBadRequest %s", 400, payload)
}
func (o *ListCredentialsBadRequest) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *ListCredentialsBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,128 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewListGiteaCredentialsParams creates a new ListGiteaCredentialsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewListGiteaCredentialsParams() *ListGiteaCredentialsParams {
return &ListGiteaCredentialsParams{
timeout: cr.DefaultTimeout,
}
}
// NewListGiteaCredentialsParamsWithTimeout creates a new ListGiteaCredentialsParams object
// with the ability to set a timeout on a request.
func NewListGiteaCredentialsParamsWithTimeout(timeout time.Duration) *ListGiteaCredentialsParams {
return &ListGiteaCredentialsParams{
timeout: timeout,
}
}
// NewListGiteaCredentialsParamsWithContext creates a new ListGiteaCredentialsParams object
// with the ability to set a context for a request.
func NewListGiteaCredentialsParamsWithContext(ctx context.Context) *ListGiteaCredentialsParams {
return &ListGiteaCredentialsParams{
Context: ctx,
}
}
// NewListGiteaCredentialsParamsWithHTTPClient creates a new ListGiteaCredentialsParams object
// with the ability to set a custom HTTPClient for a request.
func NewListGiteaCredentialsParamsWithHTTPClient(client *http.Client) *ListGiteaCredentialsParams {
return &ListGiteaCredentialsParams{
HTTPClient: client,
}
}
/*
ListGiteaCredentialsParams contains all the parameters to send to the API endpoint
for the list gitea credentials operation.
Typically these are written to a http.Request.
*/
type ListGiteaCredentialsParams struct {
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the list gitea credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ListGiteaCredentialsParams) WithDefaults() *ListGiteaCredentialsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the list gitea credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ListGiteaCredentialsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the list gitea credentials params
func (o *ListGiteaCredentialsParams) WithTimeout(timeout time.Duration) *ListGiteaCredentialsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the list gitea credentials params
func (o *ListGiteaCredentialsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the list gitea credentials params
func (o *ListGiteaCredentialsParams) WithContext(ctx context.Context) *ListGiteaCredentialsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the list gitea credentials params
func (o *ListGiteaCredentialsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the list gitea credentials params
func (o *ListGiteaCredentialsParams) WithHTTPClient(client *http.Client) *ListGiteaCredentialsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the list gitea credentials params
func (o *ListGiteaCredentialsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WriteToRequest writes these params to a swagger request
func (o *ListGiteaCredentialsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// ListGiteaCredentialsReader is a Reader for the ListGiteaCredentials structure.
type ListGiteaCredentialsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *ListGiteaCredentialsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewListGiteaCredentialsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewListGiteaCredentialsBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[GET /gitea/credentials] ListGiteaCredentials", response, response.Code())
}
}
// NewListGiteaCredentialsOK creates a ListGiteaCredentialsOK with default headers values
func NewListGiteaCredentialsOK() *ListGiteaCredentialsOK {
return &ListGiteaCredentialsOK{}
}
/*
ListGiteaCredentialsOK describes a response with status code 200, with default header values.
Credentials
*/
type ListGiteaCredentialsOK struct {
Payload garm_params.Credentials
}
// IsSuccess returns true when this list gitea credentials o k response has a 2xx status code
func (o *ListGiteaCredentialsOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this list gitea credentials o k response has a 3xx status code
func (o *ListGiteaCredentialsOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this list gitea credentials o k response has a 4xx status code
func (o *ListGiteaCredentialsOK) IsClientError() bool {
return false
}
// IsServerError returns true when this list gitea credentials o k response has a 5xx status code
func (o *ListGiteaCredentialsOK) IsServerError() bool {
return false
}
// IsCode returns true when this list gitea credentials o k response a status code equal to that given
func (o *ListGiteaCredentialsOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the list gitea credentials o k response
func (o *ListGiteaCredentialsOK) Code() int {
return 200
}
func (o *ListGiteaCredentialsOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/credentials][%d] listGiteaCredentialsOK %s", 200, payload)
}
func (o *ListGiteaCredentialsOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/credentials][%d] listGiteaCredentialsOK %s", 200, payload)
}
func (o *ListGiteaCredentialsOK) GetPayload() garm_params.Credentials {
return o.Payload
}
func (o *ListGiteaCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewListGiteaCredentialsBadRequest creates a ListGiteaCredentialsBadRequest with default headers values
func NewListGiteaCredentialsBadRequest() *ListGiteaCredentialsBadRequest {
return &ListGiteaCredentialsBadRequest{}
}
/*
ListGiteaCredentialsBadRequest describes a response with status code 400, with default header values.
APIErrorResponse
*/
type ListGiteaCredentialsBadRequest struct {
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this list gitea credentials bad request response has a 2xx status code
func (o *ListGiteaCredentialsBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this list gitea credentials bad request response has a 3xx status code
func (o *ListGiteaCredentialsBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this list gitea credentials bad request response has a 4xx status code
func (o *ListGiteaCredentialsBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this list gitea credentials bad request response has a 5xx status code
func (o *ListGiteaCredentialsBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this list gitea credentials bad request response a status code equal to that given
func (o *ListGiteaCredentialsBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the list gitea credentials bad request response
func (o *ListGiteaCredentialsBadRequest) Code() int {
return 400
}
func (o *ListGiteaCredentialsBadRequest) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/credentials][%d] listGiteaCredentialsBadRequest %s", 400, payload)
}
func (o *ListGiteaCredentialsBadRequest) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/credentials][%d] listGiteaCredentialsBadRequest %s", 400, payload)
}
func (o *ListGiteaCredentialsBadRequest) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *ListGiteaCredentialsBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,174 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
garm_params "github.com/cloudbase/garm/params"
)
// NewUpdateCredentialsParams creates a new UpdateCredentialsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewUpdateCredentialsParams() *UpdateCredentialsParams {
return &UpdateCredentialsParams{
timeout: cr.DefaultTimeout,
}
}
// NewUpdateCredentialsParamsWithTimeout creates a new UpdateCredentialsParams object
// with the ability to set a timeout on a request.
func NewUpdateCredentialsParamsWithTimeout(timeout time.Duration) *UpdateCredentialsParams {
return &UpdateCredentialsParams{
timeout: timeout,
}
}
// NewUpdateCredentialsParamsWithContext creates a new UpdateCredentialsParams object
// with the ability to set a context for a request.
func NewUpdateCredentialsParamsWithContext(ctx context.Context) *UpdateCredentialsParams {
return &UpdateCredentialsParams{
Context: ctx,
}
}
// NewUpdateCredentialsParamsWithHTTPClient creates a new UpdateCredentialsParams object
// with the ability to set a custom HTTPClient for a request.
func NewUpdateCredentialsParamsWithHTTPClient(client *http.Client) *UpdateCredentialsParams {
return &UpdateCredentialsParams{
HTTPClient: client,
}
}
/*
UpdateCredentialsParams contains all the parameters to send to the API endpoint
for the update credentials operation.
Typically these are written to a http.Request.
*/
type UpdateCredentialsParams struct {
/* Body.
Parameters used when updating a GitHub credential.
*/
Body garm_params.UpdateGithubCredentialsParams
/* ID.
ID of the GitHub credential.
*/
ID int64
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the update credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *UpdateCredentialsParams) WithDefaults() *UpdateCredentialsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the update credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *UpdateCredentialsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the update credentials params
func (o *UpdateCredentialsParams) WithTimeout(timeout time.Duration) *UpdateCredentialsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the update credentials params
func (o *UpdateCredentialsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the update credentials params
func (o *UpdateCredentialsParams) WithContext(ctx context.Context) *UpdateCredentialsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the update credentials params
func (o *UpdateCredentialsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the update credentials params
func (o *UpdateCredentialsParams) WithHTTPClient(client *http.Client) *UpdateCredentialsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the update credentials params
func (o *UpdateCredentialsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the update credentials params
func (o *UpdateCredentialsParams) WithBody(body garm_params.UpdateGithubCredentialsParams) *UpdateCredentialsParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the update credentials params
func (o *UpdateCredentialsParams) SetBody(body garm_params.UpdateGithubCredentialsParams) {
o.Body = body
}
// WithID adds the id to the update credentials params
func (o *UpdateCredentialsParams) WithID(id int64) *UpdateCredentialsParams {
o.SetID(id)
return o
}
// SetID adds the id to the update credentials params
func (o *UpdateCredentialsParams) SetID(id int64) {
o.ID = id
}
// WriteToRequest writes these params to a swagger request
func (o *UpdateCredentialsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
// path param id
if err := r.SetPathParam("id", swag.FormatInt64(o.ID)); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// UpdateCredentialsReader is a Reader for the UpdateCredentials structure.
type UpdateCredentialsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *UpdateCredentialsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewUpdateCredentialsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewUpdateCredentialsBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[PUT /github/credentials/{id}] UpdateCredentials", response, response.Code())
}
}
// NewUpdateCredentialsOK creates a UpdateCredentialsOK with default headers values
func NewUpdateCredentialsOK() *UpdateCredentialsOK {
return &UpdateCredentialsOK{}
}
/*
UpdateCredentialsOK describes a response with status code 200, with default header values.
ForgeCredentials
*/
type UpdateCredentialsOK struct {
Payload garm_params.ForgeCredentials
}
// IsSuccess returns true when this update credentials o k response has a 2xx status code
func (o *UpdateCredentialsOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this update credentials o k response has a 3xx status code
func (o *UpdateCredentialsOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this update credentials o k response has a 4xx status code
func (o *UpdateCredentialsOK) IsClientError() bool {
return false
}
// IsServerError returns true when this update credentials o k response has a 5xx status code
func (o *UpdateCredentialsOK) IsServerError() bool {
return false
}
// IsCode returns true when this update credentials o k response a status code equal to that given
func (o *UpdateCredentialsOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the update credentials o k response
func (o *UpdateCredentialsOK) Code() int {
return 200
}
func (o *UpdateCredentialsOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /github/credentials/{id}][%d] updateCredentialsOK %s", 200, payload)
}
func (o *UpdateCredentialsOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /github/credentials/{id}][%d] updateCredentialsOK %s", 200, payload)
}
func (o *UpdateCredentialsOK) GetPayload() garm_params.ForgeCredentials {
return o.Payload
}
func (o *UpdateCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewUpdateCredentialsBadRequest creates a UpdateCredentialsBadRequest with default headers values
func NewUpdateCredentialsBadRequest() *UpdateCredentialsBadRequest {
return &UpdateCredentialsBadRequest{}
}
/*
UpdateCredentialsBadRequest describes a response with status code 400, with default header values.
APIErrorResponse
*/
type UpdateCredentialsBadRequest struct {
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this update credentials bad request response has a 2xx status code
func (o *UpdateCredentialsBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this update credentials bad request response has a 3xx status code
func (o *UpdateCredentialsBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this update credentials bad request response has a 4xx status code
func (o *UpdateCredentialsBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this update credentials bad request response has a 5xx status code
func (o *UpdateCredentialsBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this update credentials bad request response a status code equal to that given
func (o *UpdateCredentialsBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the update credentials bad request response
func (o *UpdateCredentialsBadRequest) Code() int {
return 400
}
func (o *UpdateCredentialsBadRequest) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /github/credentials/{id}][%d] updateCredentialsBadRequest %s", 400, payload)
}
func (o *UpdateCredentialsBadRequest) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /github/credentials/{id}][%d] updateCredentialsBadRequest %s", 400, payload)
}
func (o *UpdateCredentialsBadRequest) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *UpdateCredentialsBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,174 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
garm_params "github.com/cloudbase/garm/params"
)
// NewUpdateGiteaCredentialsParams creates a new UpdateGiteaCredentialsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewUpdateGiteaCredentialsParams() *UpdateGiteaCredentialsParams {
return &UpdateGiteaCredentialsParams{
timeout: cr.DefaultTimeout,
}
}
// NewUpdateGiteaCredentialsParamsWithTimeout creates a new UpdateGiteaCredentialsParams object
// with the ability to set a timeout on a request.
func NewUpdateGiteaCredentialsParamsWithTimeout(timeout time.Duration) *UpdateGiteaCredentialsParams {
return &UpdateGiteaCredentialsParams{
timeout: timeout,
}
}
// NewUpdateGiteaCredentialsParamsWithContext creates a new UpdateGiteaCredentialsParams object
// with the ability to set a context for a request.
func NewUpdateGiteaCredentialsParamsWithContext(ctx context.Context) *UpdateGiteaCredentialsParams {
return &UpdateGiteaCredentialsParams{
Context: ctx,
}
}
// NewUpdateGiteaCredentialsParamsWithHTTPClient creates a new UpdateGiteaCredentialsParams object
// with the ability to set a custom HTTPClient for a request.
func NewUpdateGiteaCredentialsParamsWithHTTPClient(client *http.Client) *UpdateGiteaCredentialsParams {
return &UpdateGiteaCredentialsParams{
HTTPClient: client,
}
}
/*
UpdateGiteaCredentialsParams contains all the parameters to send to the API endpoint
for the update gitea credentials operation.
Typically these are written to a http.Request.
*/
type UpdateGiteaCredentialsParams struct {
/* Body.
Parameters used when updating a Gitea credential.
*/
Body garm_params.UpdateGiteaCredentialsParams
/* ID.
ID of the Gitea credential.
*/
ID int64
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the update gitea credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *UpdateGiteaCredentialsParams) WithDefaults() *UpdateGiteaCredentialsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the update gitea credentials params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *UpdateGiteaCredentialsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the update gitea credentials params
func (o *UpdateGiteaCredentialsParams) WithTimeout(timeout time.Duration) *UpdateGiteaCredentialsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the update gitea credentials params
func (o *UpdateGiteaCredentialsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the update gitea credentials params
func (o *UpdateGiteaCredentialsParams) WithContext(ctx context.Context) *UpdateGiteaCredentialsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the update gitea credentials params
func (o *UpdateGiteaCredentialsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the update gitea credentials params
func (o *UpdateGiteaCredentialsParams) WithHTTPClient(client *http.Client) *UpdateGiteaCredentialsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the update gitea credentials params
func (o *UpdateGiteaCredentialsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the update gitea credentials params
func (o *UpdateGiteaCredentialsParams) WithBody(body garm_params.UpdateGiteaCredentialsParams) *UpdateGiteaCredentialsParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the update gitea credentials params
func (o *UpdateGiteaCredentialsParams) SetBody(body garm_params.UpdateGiteaCredentialsParams) {
o.Body = body
}
// WithID adds the id to the update gitea credentials params
func (o *UpdateGiteaCredentialsParams) WithID(id int64) *UpdateGiteaCredentialsParams {
o.SetID(id)
return o
}
// SetID adds the id to the update gitea credentials params
func (o *UpdateGiteaCredentialsParams) SetID(id int64) {
o.ID = id
}
// WriteToRequest writes these params to a swagger request
func (o *UpdateGiteaCredentialsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
// path param id
if err := r.SetPathParam("id", swag.FormatInt64(o.ID)); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,179 @@
// Code generated by go-swagger; DO NOT EDIT.
package credentials
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// UpdateGiteaCredentialsReader is a Reader for the UpdateGiteaCredentials structure.
type UpdateGiteaCredentialsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *UpdateGiteaCredentialsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewUpdateGiteaCredentialsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewUpdateGiteaCredentialsBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[PUT /gitea/credentials/{id}] UpdateGiteaCredentials", response, response.Code())
}
}
// NewUpdateGiteaCredentialsOK creates a UpdateGiteaCredentialsOK with default headers values
func NewUpdateGiteaCredentialsOK() *UpdateGiteaCredentialsOK {
return &UpdateGiteaCredentialsOK{}
}
/*
UpdateGiteaCredentialsOK describes a response with status code 200, with default header values.
ForgeCredentials
*/
type UpdateGiteaCredentialsOK struct {
Payload garm_params.ForgeCredentials
}
// IsSuccess returns true when this update gitea credentials o k response has a 2xx status code
func (o *UpdateGiteaCredentialsOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this update gitea credentials o k response has a 3xx status code
func (o *UpdateGiteaCredentialsOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this update gitea credentials o k response has a 4xx status code
func (o *UpdateGiteaCredentialsOK) IsClientError() bool {
return false
}
// IsServerError returns true when this update gitea credentials o k response has a 5xx status code
func (o *UpdateGiteaCredentialsOK) IsServerError() bool {
return false
}
// IsCode returns true when this update gitea credentials o k response a status code equal to that given
func (o *UpdateGiteaCredentialsOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the update gitea credentials o k response
func (o *UpdateGiteaCredentialsOK) Code() int {
return 200
}
func (o *UpdateGiteaCredentialsOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /gitea/credentials/{id}][%d] updateGiteaCredentialsOK %s", 200, payload)
}
func (o *UpdateGiteaCredentialsOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /gitea/credentials/{id}][%d] updateGiteaCredentialsOK %s", 200, payload)
}
func (o *UpdateGiteaCredentialsOK) GetPayload() garm_params.ForgeCredentials {
return o.Payload
}
func (o *UpdateGiteaCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewUpdateGiteaCredentialsBadRequest creates a UpdateGiteaCredentialsBadRequest with default headers values
func NewUpdateGiteaCredentialsBadRequest() *UpdateGiteaCredentialsBadRequest {
return &UpdateGiteaCredentialsBadRequest{}
}
/*
UpdateGiteaCredentialsBadRequest describes a response with status code 400, with default header values.
APIErrorResponse
*/
type UpdateGiteaCredentialsBadRequest struct {
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this update gitea credentials bad request response has a 2xx status code
func (o *UpdateGiteaCredentialsBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this update gitea credentials bad request response has a 3xx status code
func (o *UpdateGiteaCredentialsBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this update gitea credentials bad request response has a 4xx status code
func (o *UpdateGiteaCredentialsBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this update gitea credentials bad request response has a 5xx status code
func (o *UpdateGiteaCredentialsBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this update gitea credentials bad request response a status code equal to that given
func (o *UpdateGiteaCredentialsBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the update gitea credentials bad request response
func (o *UpdateGiteaCredentialsBadRequest) Code() int {
return 400
}
func (o *UpdateGiteaCredentialsBadRequest) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /gitea/credentials/{id}][%d] updateGiteaCredentialsBadRequest %s", 400, payload)
}
func (o *UpdateGiteaCredentialsBadRequest) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /gitea/credentials/{id}][%d] updateGiteaCredentialsBadRequest %s", 400, payload)
}
func (o *UpdateGiteaCredentialsBadRequest) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *UpdateGiteaCredentialsBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
garm_params "github.com/cloudbase/garm/params"
)
// NewCreateGiteaEndpointParams creates a new CreateGiteaEndpointParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewCreateGiteaEndpointParams() *CreateGiteaEndpointParams {
return &CreateGiteaEndpointParams{
timeout: cr.DefaultTimeout,
}
}
// NewCreateGiteaEndpointParamsWithTimeout creates a new CreateGiteaEndpointParams object
// with the ability to set a timeout on a request.
func NewCreateGiteaEndpointParamsWithTimeout(timeout time.Duration) *CreateGiteaEndpointParams {
return &CreateGiteaEndpointParams{
timeout: timeout,
}
}
// NewCreateGiteaEndpointParamsWithContext creates a new CreateGiteaEndpointParams object
// with the ability to set a context for a request.
func NewCreateGiteaEndpointParamsWithContext(ctx context.Context) *CreateGiteaEndpointParams {
return &CreateGiteaEndpointParams{
Context: ctx,
}
}
// NewCreateGiteaEndpointParamsWithHTTPClient creates a new CreateGiteaEndpointParams object
// with the ability to set a custom HTTPClient for a request.
func NewCreateGiteaEndpointParamsWithHTTPClient(client *http.Client) *CreateGiteaEndpointParams {
return &CreateGiteaEndpointParams{
HTTPClient: client,
}
}
/*
CreateGiteaEndpointParams contains all the parameters to send to the API endpoint
for the create gitea endpoint operation.
Typically these are written to a http.Request.
*/
type CreateGiteaEndpointParams struct {
/* Body.
Parameters used when creating a Gitea endpoint.
*/
Body garm_params.CreateGiteaEndpointParams
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the create gitea endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateGiteaEndpointParams) WithDefaults() *CreateGiteaEndpointParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the create gitea endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateGiteaEndpointParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the create gitea endpoint params
func (o *CreateGiteaEndpointParams) WithTimeout(timeout time.Duration) *CreateGiteaEndpointParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the create gitea endpoint params
func (o *CreateGiteaEndpointParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the create gitea endpoint params
func (o *CreateGiteaEndpointParams) WithContext(ctx context.Context) *CreateGiteaEndpointParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the create gitea endpoint params
func (o *CreateGiteaEndpointParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the create gitea endpoint params
func (o *CreateGiteaEndpointParams) WithHTTPClient(client *http.Client) *CreateGiteaEndpointParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the create gitea endpoint params
func (o *CreateGiteaEndpointParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the create gitea endpoint params
func (o *CreateGiteaEndpointParams) WithBody(body garm_params.CreateGiteaEndpointParams) *CreateGiteaEndpointParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the create gitea endpoint params
func (o *CreateGiteaEndpointParams) SetBody(body garm_params.CreateGiteaEndpointParams) {
o.Body = body
}
// WriteToRequest writes these params to a swagger request
func (o *CreateGiteaEndpointParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// CreateGiteaEndpointReader is a Reader for the CreateGiteaEndpoint structure.
type CreateGiteaEndpointReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *CreateGiteaEndpointReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewCreateGiteaEndpointOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewCreateGiteaEndpointDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewCreateGiteaEndpointOK creates a CreateGiteaEndpointOK with default headers values
func NewCreateGiteaEndpointOK() *CreateGiteaEndpointOK {
return &CreateGiteaEndpointOK{}
}
/*
CreateGiteaEndpointOK describes a response with status code 200, with default header values.
ForgeEndpoint
*/
type CreateGiteaEndpointOK struct {
Payload garm_params.ForgeEndpoint
}
// IsSuccess returns true when this create gitea endpoint o k response has a 2xx status code
func (o *CreateGiteaEndpointOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this create gitea endpoint o k response has a 3xx status code
func (o *CreateGiteaEndpointOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this create gitea endpoint o k response has a 4xx status code
func (o *CreateGiteaEndpointOK) IsClientError() bool {
return false
}
// IsServerError returns true when this create gitea endpoint o k response has a 5xx status code
func (o *CreateGiteaEndpointOK) IsServerError() bool {
return false
}
// IsCode returns true when this create gitea endpoint o k response a status code equal to that given
func (o *CreateGiteaEndpointOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the create gitea endpoint o k response
func (o *CreateGiteaEndpointOK) Code() int {
return 200
}
func (o *CreateGiteaEndpointOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /gitea/endpoints][%d] createGiteaEndpointOK %s", 200, payload)
}
func (o *CreateGiteaEndpointOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /gitea/endpoints][%d] createGiteaEndpointOK %s", 200, payload)
}
func (o *CreateGiteaEndpointOK) GetPayload() garm_params.ForgeEndpoint {
return o.Payload
}
func (o *CreateGiteaEndpointOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewCreateGiteaEndpointDefault creates a CreateGiteaEndpointDefault with default headers values
func NewCreateGiteaEndpointDefault(code int) *CreateGiteaEndpointDefault {
return &CreateGiteaEndpointDefault{
_statusCode: code,
}
}
/*
CreateGiteaEndpointDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type CreateGiteaEndpointDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this create gitea endpoint default response has a 2xx status code
func (o *CreateGiteaEndpointDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this create gitea endpoint default response has a 3xx status code
func (o *CreateGiteaEndpointDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this create gitea endpoint default response has a 4xx status code
func (o *CreateGiteaEndpointDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this create gitea endpoint default response has a 5xx status code
func (o *CreateGiteaEndpointDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this create gitea endpoint default response a status code equal to that given
func (o *CreateGiteaEndpointDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the create gitea endpoint default response
func (o *CreateGiteaEndpointDefault) Code() int {
return o._statusCode
}
func (o *CreateGiteaEndpointDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /gitea/endpoints][%d] CreateGiteaEndpoint default %s", o._statusCode, payload)
}
func (o *CreateGiteaEndpointDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /gitea/endpoints][%d] CreateGiteaEndpoint default %s", o._statusCode, payload)
}
func (o *CreateGiteaEndpointDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *CreateGiteaEndpointDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
garm_params "github.com/cloudbase/garm/params"
)
// NewCreateGithubEndpointParams creates a new CreateGithubEndpointParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewCreateGithubEndpointParams() *CreateGithubEndpointParams {
return &CreateGithubEndpointParams{
timeout: cr.DefaultTimeout,
}
}
// NewCreateGithubEndpointParamsWithTimeout creates a new CreateGithubEndpointParams object
// with the ability to set a timeout on a request.
func NewCreateGithubEndpointParamsWithTimeout(timeout time.Duration) *CreateGithubEndpointParams {
return &CreateGithubEndpointParams{
timeout: timeout,
}
}
// NewCreateGithubEndpointParamsWithContext creates a new CreateGithubEndpointParams object
// with the ability to set a context for a request.
func NewCreateGithubEndpointParamsWithContext(ctx context.Context) *CreateGithubEndpointParams {
return &CreateGithubEndpointParams{
Context: ctx,
}
}
// NewCreateGithubEndpointParamsWithHTTPClient creates a new CreateGithubEndpointParams object
// with the ability to set a custom HTTPClient for a request.
func NewCreateGithubEndpointParamsWithHTTPClient(client *http.Client) *CreateGithubEndpointParams {
return &CreateGithubEndpointParams{
HTTPClient: client,
}
}
/*
CreateGithubEndpointParams contains all the parameters to send to the API endpoint
for the create github endpoint operation.
Typically these are written to a http.Request.
*/
type CreateGithubEndpointParams struct {
/* Body.
Parameters used when creating a GitHub endpoint.
*/
Body garm_params.CreateGithubEndpointParams
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the create github endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateGithubEndpointParams) WithDefaults() *CreateGithubEndpointParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the create github endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateGithubEndpointParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the create github endpoint params
func (o *CreateGithubEndpointParams) WithTimeout(timeout time.Duration) *CreateGithubEndpointParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the create github endpoint params
func (o *CreateGithubEndpointParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the create github endpoint params
func (o *CreateGithubEndpointParams) WithContext(ctx context.Context) *CreateGithubEndpointParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the create github endpoint params
func (o *CreateGithubEndpointParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the create github endpoint params
func (o *CreateGithubEndpointParams) WithHTTPClient(client *http.Client) *CreateGithubEndpointParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the create github endpoint params
func (o *CreateGithubEndpointParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the create github endpoint params
func (o *CreateGithubEndpointParams) WithBody(body garm_params.CreateGithubEndpointParams) *CreateGithubEndpointParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the create github endpoint params
func (o *CreateGithubEndpointParams) SetBody(body garm_params.CreateGithubEndpointParams) {
o.Body = body
}
// WriteToRequest writes these params to a swagger request
func (o *CreateGithubEndpointParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// CreateGithubEndpointReader is a Reader for the CreateGithubEndpoint structure.
type CreateGithubEndpointReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *CreateGithubEndpointReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewCreateGithubEndpointOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewCreateGithubEndpointDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewCreateGithubEndpointOK creates a CreateGithubEndpointOK with default headers values
func NewCreateGithubEndpointOK() *CreateGithubEndpointOK {
return &CreateGithubEndpointOK{}
}
/*
CreateGithubEndpointOK describes a response with status code 200, with default header values.
ForgeEndpoint
*/
type CreateGithubEndpointOK struct {
Payload garm_params.ForgeEndpoint
}
// IsSuccess returns true when this create github endpoint o k response has a 2xx status code
func (o *CreateGithubEndpointOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this create github endpoint o k response has a 3xx status code
func (o *CreateGithubEndpointOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this create github endpoint o k response has a 4xx status code
func (o *CreateGithubEndpointOK) IsClientError() bool {
return false
}
// IsServerError returns true when this create github endpoint o k response has a 5xx status code
func (o *CreateGithubEndpointOK) IsServerError() bool {
return false
}
// IsCode returns true when this create github endpoint o k response a status code equal to that given
func (o *CreateGithubEndpointOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the create github endpoint o k response
func (o *CreateGithubEndpointOK) Code() int {
return 200
}
func (o *CreateGithubEndpointOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /github/endpoints][%d] createGithubEndpointOK %s", 200, payload)
}
func (o *CreateGithubEndpointOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /github/endpoints][%d] createGithubEndpointOK %s", 200, payload)
}
func (o *CreateGithubEndpointOK) GetPayload() garm_params.ForgeEndpoint {
return o.Payload
}
func (o *CreateGithubEndpointOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewCreateGithubEndpointDefault creates a CreateGithubEndpointDefault with default headers values
func NewCreateGithubEndpointDefault(code int) *CreateGithubEndpointDefault {
return &CreateGithubEndpointDefault{
_statusCode: code,
}
}
/*
CreateGithubEndpointDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type CreateGithubEndpointDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this create github endpoint default response has a 2xx status code
func (o *CreateGithubEndpointDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this create github endpoint default response has a 3xx status code
func (o *CreateGithubEndpointDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this create github endpoint default response has a 4xx status code
func (o *CreateGithubEndpointDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this create github endpoint default response has a 5xx status code
func (o *CreateGithubEndpointDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this create github endpoint default response a status code equal to that given
func (o *CreateGithubEndpointDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the create github endpoint default response
func (o *CreateGithubEndpointDefault) Code() int {
return o._statusCode
}
func (o *CreateGithubEndpointDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /github/endpoints][%d] CreateGithubEndpoint default %s", o._statusCode, payload)
}
func (o *CreateGithubEndpointDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /github/endpoints][%d] CreateGithubEndpoint default %s", o._statusCode, payload)
}
func (o *CreateGithubEndpointDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *CreateGithubEndpointDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewDeleteGiteaEndpointParams creates a new DeleteGiteaEndpointParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewDeleteGiteaEndpointParams() *DeleteGiteaEndpointParams {
return &DeleteGiteaEndpointParams{
timeout: cr.DefaultTimeout,
}
}
// NewDeleteGiteaEndpointParamsWithTimeout creates a new DeleteGiteaEndpointParams object
// with the ability to set a timeout on a request.
func NewDeleteGiteaEndpointParamsWithTimeout(timeout time.Duration) *DeleteGiteaEndpointParams {
return &DeleteGiteaEndpointParams{
timeout: timeout,
}
}
// NewDeleteGiteaEndpointParamsWithContext creates a new DeleteGiteaEndpointParams object
// with the ability to set a context for a request.
func NewDeleteGiteaEndpointParamsWithContext(ctx context.Context) *DeleteGiteaEndpointParams {
return &DeleteGiteaEndpointParams{
Context: ctx,
}
}
// NewDeleteGiteaEndpointParamsWithHTTPClient creates a new DeleteGiteaEndpointParams object
// with the ability to set a custom HTTPClient for a request.
func NewDeleteGiteaEndpointParamsWithHTTPClient(client *http.Client) *DeleteGiteaEndpointParams {
return &DeleteGiteaEndpointParams{
HTTPClient: client,
}
}
/*
DeleteGiteaEndpointParams contains all the parameters to send to the API endpoint
for the delete gitea endpoint operation.
Typically these are written to a http.Request.
*/
type DeleteGiteaEndpointParams struct {
/* Name.
The name of the Gitea endpoint.
*/
Name string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the delete gitea endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *DeleteGiteaEndpointParams) WithDefaults() *DeleteGiteaEndpointParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the delete gitea endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *DeleteGiteaEndpointParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the delete gitea endpoint params
func (o *DeleteGiteaEndpointParams) WithTimeout(timeout time.Duration) *DeleteGiteaEndpointParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the delete gitea endpoint params
func (o *DeleteGiteaEndpointParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the delete gitea endpoint params
func (o *DeleteGiteaEndpointParams) WithContext(ctx context.Context) *DeleteGiteaEndpointParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the delete gitea endpoint params
func (o *DeleteGiteaEndpointParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the delete gitea endpoint params
func (o *DeleteGiteaEndpointParams) WithHTTPClient(client *http.Client) *DeleteGiteaEndpointParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the delete gitea endpoint params
func (o *DeleteGiteaEndpointParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithName adds the name to the delete gitea endpoint params
func (o *DeleteGiteaEndpointParams) WithName(name string) *DeleteGiteaEndpointParams {
o.SetName(name)
return o
}
// SetName adds the name to the delete gitea endpoint params
func (o *DeleteGiteaEndpointParams) SetName(name string) {
o.Name = name
}
// WriteToRequest writes these params to a swagger request
func (o *DeleteGiteaEndpointParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param name
if err := r.SetPathParam("name", o.Name); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,106 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
)
// DeleteGiteaEndpointReader is a Reader for the DeleteGiteaEndpoint structure.
type DeleteGiteaEndpointReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *DeleteGiteaEndpointReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
result := NewDeleteGiteaEndpointDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
// NewDeleteGiteaEndpointDefault creates a DeleteGiteaEndpointDefault with default headers values
func NewDeleteGiteaEndpointDefault(code int) *DeleteGiteaEndpointDefault {
return &DeleteGiteaEndpointDefault{
_statusCode: code,
}
}
/*
DeleteGiteaEndpointDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type DeleteGiteaEndpointDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this delete gitea endpoint default response has a 2xx status code
func (o *DeleteGiteaEndpointDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this delete gitea endpoint default response has a 3xx status code
func (o *DeleteGiteaEndpointDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this delete gitea endpoint default response has a 4xx status code
func (o *DeleteGiteaEndpointDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this delete gitea endpoint default response has a 5xx status code
func (o *DeleteGiteaEndpointDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this delete gitea endpoint default response a status code equal to that given
func (o *DeleteGiteaEndpointDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the delete gitea endpoint default response
func (o *DeleteGiteaEndpointDefault) Code() int {
return o._statusCode
}
func (o *DeleteGiteaEndpointDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[DELETE /gitea/endpoints/{name}][%d] DeleteGiteaEndpoint default %s", o._statusCode, payload)
}
func (o *DeleteGiteaEndpointDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[DELETE /gitea/endpoints/{name}][%d] DeleteGiteaEndpoint default %s", o._statusCode, payload)
}
func (o *DeleteGiteaEndpointDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *DeleteGiteaEndpointDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewDeleteGithubEndpointParams creates a new DeleteGithubEndpointParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewDeleteGithubEndpointParams() *DeleteGithubEndpointParams {
return &DeleteGithubEndpointParams{
timeout: cr.DefaultTimeout,
}
}
// NewDeleteGithubEndpointParamsWithTimeout creates a new DeleteGithubEndpointParams object
// with the ability to set a timeout on a request.
func NewDeleteGithubEndpointParamsWithTimeout(timeout time.Duration) *DeleteGithubEndpointParams {
return &DeleteGithubEndpointParams{
timeout: timeout,
}
}
// NewDeleteGithubEndpointParamsWithContext creates a new DeleteGithubEndpointParams object
// with the ability to set a context for a request.
func NewDeleteGithubEndpointParamsWithContext(ctx context.Context) *DeleteGithubEndpointParams {
return &DeleteGithubEndpointParams{
Context: ctx,
}
}
// NewDeleteGithubEndpointParamsWithHTTPClient creates a new DeleteGithubEndpointParams object
// with the ability to set a custom HTTPClient for a request.
func NewDeleteGithubEndpointParamsWithHTTPClient(client *http.Client) *DeleteGithubEndpointParams {
return &DeleteGithubEndpointParams{
HTTPClient: client,
}
}
/*
DeleteGithubEndpointParams contains all the parameters to send to the API endpoint
for the delete github endpoint operation.
Typically these are written to a http.Request.
*/
type DeleteGithubEndpointParams struct {
/* Name.
The name of the GitHub endpoint.
*/
Name string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the delete github endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *DeleteGithubEndpointParams) WithDefaults() *DeleteGithubEndpointParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the delete github endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *DeleteGithubEndpointParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the delete github endpoint params
func (o *DeleteGithubEndpointParams) WithTimeout(timeout time.Duration) *DeleteGithubEndpointParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the delete github endpoint params
func (o *DeleteGithubEndpointParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the delete github endpoint params
func (o *DeleteGithubEndpointParams) WithContext(ctx context.Context) *DeleteGithubEndpointParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the delete github endpoint params
func (o *DeleteGithubEndpointParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the delete github endpoint params
func (o *DeleteGithubEndpointParams) WithHTTPClient(client *http.Client) *DeleteGithubEndpointParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the delete github endpoint params
func (o *DeleteGithubEndpointParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithName adds the name to the delete github endpoint params
func (o *DeleteGithubEndpointParams) WithName(name string) *DeleteGithubEndpointParams {
o.SetName(name)
return o
}
// SetName adds the name to the delete github endpoint params
func (o *DeleteGithubEndpointParams) SetName(name string) {
o.Name = name
}
// WriteToRequest writes these params to a swagger request
func (o *DeleteGithubEndpointParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param name
if err := r.SetPathParam("name", o.Name); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,106 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
)
// DeleteGithubEndpointReader is a Reader for the DeleteGithubEndpoint structure.
type DeleteGithubEndpointReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *DeleteGithubEndpointReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
result := NewDeleteGithubEndpointDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
// NewDeleteGithubEndpointDefault creates a DeleteGithubEndpointDefault with default headers values
func NewDeleteGithubEndpointDefault(code int) *DeleteGithubEndpointDefault {
return &DeleteGithubEndpointDefault{
_statusCode: code,
}
}
/*
DeleteGithubEndpointDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type DeleteGithubEndpointDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this delete github endpoint default response has a 2xx status code
func (o *DeleteGithubEndpointDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this delete github endpoint default response has a 3xx status code
func (o *DeleteGithubEndpointDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this delete github endpoint default response has a 4xx status code
func (o *DeleteGithubEndpointDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this delete github endpoint default response has a 5xx status code
func (o *DeleteGithubEndpointDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this delete github endpoint default response a status code equal to that given
func (o *DeleteGithubEndpointDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the delete github endpoint default response
func (o *DeleteGithubEndpointDefault) Code() int {
return o._statusCode
}
func (o *DeleteGithubEndpointDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[DELETE /github/endpoints/{name}][%d] DeleteGithubEndpoint default %s", o._statusCode, payload)
}
func (o *DeleteGithubEndpointDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[DELETE /github/endpoints/{name}][%d] DeleteGithubEndpoint default %s", o._statusCode, payload)
}
func (o *DeleteGithubEndpointDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *DeleteGithubEndpointDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,451 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// New creates a new endpoints API client.
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
return &Client{transport: transport, formats: formats}
}
// New creates a new endpoints API client with basic auth credentials.
// It takes the following parameters:
// - host: http host (github.com).
// - basePath: any base path for the API client ("/v1", "/v3").
// - scheme: http scheme ("http", "https").
// - user: user for basic authentication header.
// - password: password for basic authentication header.
func NewClientWithBasicAuth(host, basePath, scheme, user, password string) ClientService {
transport := httptransport.New(host, basePath, []string{scheme})
transport.DefaultAuthentication = httptransport.BasicAuth(user, password)
return &Client{transport: transport, formats: strfmt.Default}
}
// New creates a new endpoints API client with a bearer token for authentication.
// It takes the following parameters:
// - host: http host (github.com).
// - basePath: any base path for the API client ("/v1", "/v3").
// - scheme: http scheme ("http", "https").
// - bearerToken: bearer token for Bearer authentication header.
func NewClientWithBearerToken(host, basePath, scheme, bearerToken string) ClientService {
transport := httptransport.New(host, basePath, []string{scheme})
transport.DefaultAuthentication = httptransport.BearerToken(bearerToken)
return &Client{transport: transport, formats: strfmt.Default}
}
/*
Client for endpoints API
*/
type Client struct {
transport runtime.ClientTransport
formats strfmt.Registry
}
// ClientOption may be used to customize the behavior of Client methods.
type ClientOption func(*runtime.ClientOperation)
// ClientService is the interface for Client methods
type ClientService interface {
CreateGiteaEndpoint(params *CreateGiteaEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateGiteaEndpointOK, error)
CreateGithubEndpoint(params *CreateGithubEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateGithubEndpointOK, error)
DeleteGiteaEndpoint(params *DeleteGiteaEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error
DeleteGithubEndpoint(params *DeleteGithubEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error
GetGiteaEndpoint(params *GetGiteaEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetGiteaEndpointOK, error)
GetGithubEndpoint(params *GetGithubEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetGithubEndpointOK, error)
ListGiteaEndpoints(params *ListGiteaEndpointsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListGiteaEndpointsOK, error)
ListGithubEndpoints(params *ListGithubEndpointsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListGithubEndpointsOK, error)
UpdateGiteaEndpoint(params *UpdateGiteaEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateGiteaEndpointOK, error)
UpdateGithubEndpoint(params *UpdateGithubEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateGithubEndpointOK, error)
SetTransport(transport runtime.ClientTransport)
}
/*
CreateGiteaEndpoint creates a gitea endpoint
*/
func (a *Client) CreateGiteaEndpoint(params *CreateGiteaEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateGiteaEndpointOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewCreateGiteaEndpointParams()
}
op := &runtime.ClientOperation{
ID: "CreateGiteaEndpoint",
Method: "POST",
PathPattern: "/gitea/endpoints",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &CreateGiteaEndpointReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*CreateGiteaEndpointOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*CreateGiteaEndpointDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
CreateGithubEndpoint creates a git hub endpoint
*/
func (a *Client) CreateGithubEndpoint(params *CreateGithubEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateGithubEndpointOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewCreateGithubEndpointParams()
}
op := &runtime.ClientOperation{
ID: "CreateGithubEndpoint",
Method: "POST",
PathPattern: "/github/endpoints",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &CreateGithubEndpointReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*CreateGithubEndpointOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*CreateGithubEndpointDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
DeleteGiteaEndpoint deletes a gitea endpoint
*/
func (a *Client) DeleteGiteaEndpoint(params *DeleteGiteaEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error {
// TODO: Validate the params before sending
if params == nil {
params = NewDeleteGiteaEndpointParams()
}
op := &runtime.ClientOperation{
ID: "DeleteGiteaEndpoint",
Method: "DELETE",
PathPattern: "/gitea/endpoints/{name}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &DeleteGiteaEndpointReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
_, err := a.transport.Submit(op)
if err != nil {
return err
}
return nil
}
/*
DeleteGithubEndpoint deletes a git hub endpoint
*/
func (a *Client) DeleteGithubEndpoint(params *DeleteGithubEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error {
// TODO: Validate the params before sending
if params == nil {
params = NewDeleteGithubEndpointParams()
}
op := &runtime.ClientOperation{
ID: "DeleteGithubEndpoint",
Method: "DELETE",
PathPattern: "/github/endpoints/{name}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &DeleteGithubEndpointReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
_, err := a.transport.Submit(op)
if err != nil {
return err
}
return nil
}
/*
GetGiteaEndpoint gets a gitea endpoint
*/
func (a *Client) GetGiteaEndpoint(params *GetGiteaEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetGiteaEndpointOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewGetGiteaEndpointParams()
}
op := &runtime.ClientOperation{
ID: "GetGiteaEndpoint",
Method: "GET",
PathPattern: "/gitea/endpoints/{name}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &GetGiteaEndpointReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*GetGiteaEndpointOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*GetGiteaEndpointDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
GetGithubEndpoint gets a git hub endpoint
*/
func (a *Client) GetGithubEndpoint(params *GetGithubEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetGithubEndpointOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewGetGithubEndpointParams()
}
op := &runtime.ClientOperation{
ID: "GetGithubEndpoint",
Method: "GET",
PathPattern: "/github/endpoints/{name}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &GetGithubEndpointReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*GetGithubEndpointOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*GetGithubEndpointDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
ListGiteaEndpoints lists all gitea endpoints
*/
func (a *Client) ListGiteaEndpoints(params *ListGiteaEndpointsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListGiteaEndpointsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewListGiteaEndpointsParams()
}
op := &runtime.ClientOperation{
ID: "ListGiteaEndpoints",
Method: "GET",
PathPattern: "/gitea/endpoints",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &ListGiteaEndpointsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*ListGiteaEndpointsOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*ListGiteaEndpointsDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
ListGithubEndpoints lists all git hub endpoints
*/
func (a *Client) ListGithubEndpoints(params *ListGithubEndpointsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListGithubEndpointsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewListGithubEndpointsParams()
}
op := &runtime.ClientOperation{
ID: "ListGithubEndpoints",
Method: "GET",
PathPattern: "/github/endpoints",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &ListGithubEndpointsReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*ListGithubEndpointsOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*ListGithubEndpointsDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
UpdateGiteaEndpoint updates a gitea endpoint
*/
func (a *Client) UpdateGiteaEndpoint(params *UpdateGiteaEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateGiteaEndpointOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewUpdateGiteaEndpointParams()
}
op := &runtime.ClientOperation{
ID: "UpdateGiteaEndpoint",
Method: "PUT",
PathPattern: "/gitea/endpoints/{name}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &UpdateGiteaEndpointReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*UpdateGiteaEndpointOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*UpdateGiteaEndpointDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
/*
UpdateGithubEndpoint updates a git hub endpoint
*/
func (a *Client) UpdateGithubEndpoint(params *UpdateGithubEndpointParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateGithubEndpointOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewUpdateGithubEndpointParams()
}
op := &runtime.ClientOperation{
ID: "UpdateGithubEndpoint",
Method: "PUT",
PathPattern: "/github/endpoints/{name}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &UpdateGithubEndpointReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*UpdateGithubEndpointOK)
if ok {
return success, nil
}
// unexpected success response
unexpectedSuccess := result.(*UpdateGithubEndpointDefault)
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
}
// SetTransport changes the transport on the client
func (a *Client) SetTransport(transport runtime.ClientTransport) {
a.transport = transport
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewGetGiteaEndpointParams creates a new GetGiteaEndpointParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewGetGiteaEndpointParams() *GetGiteaEndpointParams {
return &GetGiteaEndpointParams{
timeout: cr.DefaultTimeout,
}
}
// NewGetGiteaEndpointParamsWithTimeout creates a new GetGiteaEndpointParams object
// with the ability to set a timeout on a request.
func NewGetGiteaEndpointParamsWithTimeout(timeout time.Duration) *GetGiteaEndpointParams {
return &GetGiteaEndpointParams{
timeout: timeout,
}
}
// NewGetGiteaEndpointParamsWithContext creates a new GetGiteaEndpointParams object
// with the ability to set a context for a request.
func NewGetGiteaEndpointParamsWithContext(ctx context.Context) *GetGiteaEndpointParams {
return &GetGiteaEndpointParams{
Context: ctx,
}
}
// NewGetGiteaEndpointParamsWithHTTPClient creates a new GetGiteaEndpointParams object
// with the ability to set a custom HTTPClient for a request.
func NewGetGiteaEndpointParamsWithHTTPClient(client *http.Client) *GetGiteaEndpointParams {
return &GetGiteaEndpointParams{
HTTPClient: client,
}
}
/*
GetGiteaEndpointParams contains all the parameters to send to the API endpoint
for the get gitea endpoint operation.
Typically these are written to a http.Request.
*/
type GetGiteaEndpointParams struct {
/* Name.
The name of the Gitea endpoint.
*/
Name string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the get gitea endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetGiteaEndpointParams) WithDefaults() *GetGiteaEndpointParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the get gitea endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetGiteaEndpointParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the get gitea endpoint params
func (o *GetGiteaEndpointParams) WithTimeout(timeout time.Duration) *GetGiteaEndpointParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the get gitea endpoint params
func (o *GetGiteaEndpointParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the get gitea endpoint params
func (o *GetGiteaEndpointParams) WithContext(ctx context.Context) *GetGiteaEndpointParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the get gitea endpoint params
func (o *GetGiteaEndpointParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the get gitea endpoint params
func (o *GetGiteaEndpointParams) WithHTTPClient(client *http.Client) *GetGiteaEndpointParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the get gitea endpoint params
func (o *GetGiteaEndpointParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithName adds the name to the get gitea endpoint params
func (o *GetGiteaEndpointParams) WithName(name string) *GetGiteaEndpointParams {
o.SetName(name)
return o
}
// SetName adds the name to the get gitea endpoint params
func (o *GetGiteaEndpointParams) SetName(name string) {
o.Name = name
}
// WriteToRequest writes these params to a swagger request
func (o *GetGiteaEndpointParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param name
if err := r.SetPathParam("name", o.Name); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// GetGiteaEndpointReader is a Reader for the GetGiteaEndpoint structure.
type GetGiteaEndpointReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *GetGiteaEndpointReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewGetGiteaEndpointOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewGetGiteaEndpointDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewGetGiteaEndpointOK creates a GetGiteaEndpointOK with default headers values
func NewGetGiteaEndpointOK() *GetGiteaEndpointOK {
return &GetGiteaEndpointOK{}
}
/*
GetGiteaEndpointOK describes a response with status code 200, with default header values.
ForgeEndpoint
*/
type GetGiteaEndpointOK struct {
Payload garm_params.ForgeEndpoint
}
// IsSuccess returns true when this get gitea endpoint o k response has a 2xx status code
func (o *GetGiteaEndpointOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this get gitea endpoint o k response has a 3xx status code
func (o *GetGiteaEndpointOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this get gitea endpoint o k response has a 4xx status code
func (o *GetGiteaEndpointOK) IsClientError() bool {
return false
}
// IsServerError returns true when this get gitea endpoint o k response has a 5xx status code
func (o *GetGiteaEndpointOK) IsServerError() bool {
return false
}
// IsCode returns true when this get gitea endpoint o k response a status code equal to that given
func (o *GetGiteaEndpointOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the get gitea endpoint o k response
func (o *GetGiteaEndpointOK) Code() int {
return 200
}
func (o *GetGiteaEndpointOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/endpoints/{name}][%d] getGiteaEndpointOK %s", 200, payload)
}
func (o *GetGiteaEndpointOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/endpoints/{name}][%d] getGiteaEndpointOK %s", 200, payload)
}
func (o *GetGiteaEndpointOK) GetPayload() garm_params.ForgeEndpoint {
return o.Payload
}
func (o *GetGiteaEndpointOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewGetGiteaEndpointDefault creates a GetGiteaEndpointDefault with default headers values
func NewGetGiteaEndpointDefault(code int) *GetGiteaEndpointDefault {
return &GetGiteaEndpointDefault{
_statusCode: code,
}
}
/*
GetGiteaEndpointDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type GetGiteaEndpointDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this get gitea endpoint default response has a 2xx status code
func (o *GetGiteaEndpointDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this get gitea endpoint default response has a 3xx status code
func (o *GetGiteaEndpointDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this get gitea endpoint default response has a 4xx status code
func (o *GetGiteaEndpointDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this get gitea endpoint default response has a 5xx status code
func (o *GetGiteaEndpointDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this get gitea endpoint default response a status code equal to that given
func (o *GetGiteaEndpointDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the get gitea endpoint default response
func (o *GetGiteaEndpointDefault) Code() int {
return o._statusCode
}
func (o *GetGiteaEndpointDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/endpoints/{name}][%d] GetGiteaEndpoint default %s", o._statusCode, payload)
}
func (o *GetGiteaEndpointDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/endpoints/{name}][%d] GetGiteaEndpoint default %s", o._statusCode, payload)
}
func (o *GetGiteaEndpointDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *GetGiteaEndpointDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewGetGithubEndpointParams creates a new GetGithubEndpointParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewGetGithubEndpointParams() *GetGithubEndpointParams {
return &GetGithubEndpointParams{
timeout: cr.DefaultTimeout,
}
}
// NewGetGithubEndpointParamsWithTimeout creates a new GetGithubEndpointParams object
// with the ability to set a timeout on a request.
func NewGetGithubEndpointParamsWithTimeout(timeout time.Duration) *GetGithubEndpointParams {
return &GetGithubEndpointParams{
timeout: timeout,
}
}
// NewGetGithubEndpointParamsWithContext creates a new GetGithubEndpointParams object
// with the ability to set a context for a request.
func NewGetGithubEndpointParamsWithContext(ctx context.Context) *GetGithubEndpointParams {
return &GetGithubEndpointParams{
Context: ctx,
}
}
// NewGetGithubEndpointParamsWithHTTPClient creates a new GetGithubEndpointParams object
// with the ability to set a custom HTTPClient for a request.
func NewGetGithubEndpointParamsWithHTTPClient(client *http.Client) *GetGithubEndpointParams {
return &GetGithubEndpointParams{
HTTPClient: client,
}
}
/*
GetGithubEndpointParams contains all the parameters to send to the API endpoint
for the get github endpoint operation.
Typically these are written to a http.Request.
*/
type GetGithubEndpointParams struct {
/* Name.
The name of the GitHub endpoint.
*/
Name string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the get github endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetGithubEndpointParams) WithDefaults() *GetGithubEndpointParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the get github endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetGithubEndpointParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the get github endpoint params
func (o *GetGithubEndpointParams) WithTimeout(timeout time.Duration) *GetGithubEndpointParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the get github endpoint params
func (o *GetGithubEndpointParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the get github endpoint params
func (o *GetGithubEndpointParams) WithContext(ctx context.Context) *GetGithubEndpointParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the get github endpoint params
func (o *GetGithubEndpointParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the get github endpoint params
func (o *GetGithubEndpointParams) WithHTTPClient(client *http.Client) *GetGithubEndpointParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the get github endpoint params
func (o *GetGithubEndpointParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithName adds the name to the get github endpoint params
func (o *GetGithubEndpointParams) WithName(name string) *GetGithubEndpointParams {
o.SetName(name)
return o
}
// SetName adds the name to the get github endpoint params
func (o *GetGithubEndpointParams) SetName(name string) {
o.Name = name
}
// WriteToRequest writes these params to a swagger request
func (o *GetGithubEndpointParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param name
if err := r.SetPathParam("name", o.Name); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// GetGithubEndpointReader is a Reader for the GetGithubEndpoint structure.
type GetGithubEndpointReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *GetGithubEndpointReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewGetGithubEndpointOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewGetGithubEndpointDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewGetGithubEndpointOK creates a GetGithubEndpointOK with default headers values
func NewGetGithubEndpointOK() *GetGithubEndpointOK {
return &GetGithubEndpointOK{}
}
/*
GetGithubEndpointOK describes a response with status code 200, with default header values.
ForgeEndpoint
*/
type GetGithubEndpointOK struct {
Payload garm_params.ForgeEndpoint
}
// IsSuccess returns true when this get github endpoint o k response has a 2xx status code
func (o *GetGithubEndpointOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this get github endpoint o k response has a 3xx status code
func (o *GetGithubEndpointOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this get github endpoint o k response has a 4xx status code
func (o *GetGithubEndpointOK) IsClientError() bool {
return false
}
// IsServerError returns true when this get github endpoint o k response has a 5xx status code
func (o *GetGithubEndpointOK) IsServerError() bool {
return false
}
// IsCode returns true when this get github endpoint o k response a status code equal to that given
func (o *GetGithubEndpointOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the get github endpoint o k response
func (o *GetGithubEndpointOK) Code() int {
return 200
}
func (o *GetGithubEndpointOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/endpoints/{name}][%d] getGithubEndpointOK %s", 200, payload)
}
func (o *GetGithubEndpointOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/endpoints/{name}][%d] getGithubEndpointOK %s", 200, payload)
}
func (o *GetGithubEndpointOK) GetPayload() garm_params.ForgeEndpoint {
return o.Payload
}
func (o *GetGithubEndpointOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewGetGithubEndpointDefault creates a GetGithubEndpointDefault with default headers values
func NewGetGithubEndpointDefault(code int) *GetGithubEndpointDefault {
return &GetGithubEndpointDefault{
_statusCode: code,
}
}
/*
GetGithubEndpointDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type GetGithubEndpointDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this get github endpoint default response has a 2xx status code
func (o *GetGithubEndpointDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this get github endpoint default response has a 3xx status code
func (o *GetGithubEndpointDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this get github endpoint default response has a 4xx status code
func (o *GetGithubEndpointDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this get github endpoint default response has a 5xx status code
func (o *GetGithubEndpointDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this get github endpoint default response a status code equal to that given
func (o *GetGithubEndpointDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the get github endpoint default response
func (o *GetGithubEndpointDefault) Code() int {
return o._statusCode
}
func (o *GetGithubEndpointDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/endpoints/{name}][%d] GetGithubEndpoint default %s", o._statusCode, payload)
}
func (o *GetGithubEndpointDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/endpoints/{name}][%d] GetGithubEndpoint default %s", o._statusCode, payload)
}
func (o *GetGithubEndpointDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *GetGithubEndpointDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,128 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewListGiteaEndpointsParams creates a new ListGiteaEndpointsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewListGiteaEndpointsParams() *ListGiteaEndpointsParams {
return &ListGiteaEndpointsParams{
timeout: cr.DefaultTimeout,
}
}
// NewListGiteaEndpointsParamsWithTimeout creates a new ListGiteaEndpointsParams object
// with the ability to set a timeout on a request.
func NewListGiteaEndpointsParamsWithTimeout(timeout time.Duration) *ListGiteaEndpointsParams {
return &ListGiteaEndpointsParams{
timeout: timeout,
}
}
// NewListGiteaEndpointsParamsWithContext creates a new ListGiteaEndpointsParams object
// with the ability to set a context for a request.
func NewListGiteaEndpointsParamsWithContext(ctx context.Context) *ListGiteaEndpointsParams {
return &ListGiteaEndpointsParams{
Context: ctx,
}
}
// NewListGiteaEndpointsParamsWithHTTPClient creates a new ListGiteaEndpointsParams object
// with the ability to set a custom HTTPClient for a request.
func NewListGiteaEndpointsParamsWithHTTPClient(client *http.Client) *ListGiteaEndpointsParams {
return &ListGiteaEndpointsParams{
HTTPClient: client,
}
}
/*
ListGiteaEndpointsParams contains all the parameters to send to the API endpoint
for the list gitea endpoints operation.
Typically these are written to a http.Request.
*/
type ListGiteaEndpointsParams struct {
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the list gitea endpoints params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ListGiteaEndpointsParams) WithDefaults() *ListGiteaEndpointsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the list gitea endpoints params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ListGiteaEndpointsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the list gitea endpoints params
func (o *ListGiteaEndpointsParams) WithTimeout(timeout time.Duration) *ListGiteaEndpointsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the list gitea endpoints params
func (o *ListGiteaEndpointsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the list gitea endpoints params
func (o *ListGiteaEndpointsParams) WithContext(ctx context.Context) *ListGiteaEndpointsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the list gitea endpoints params
func (o *ListGiteaEndpointsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the list gitea endpoints params
func (o *ListGiteaEndpointsParams) WithHTTPClient(client *http.Client) *ListGiteaEndpointsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the list gitea endpoints params
func (o *ListGiteaEndpointsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WriteToRequest writes these params to a swagger request
func (o *ListGiteaEndpointsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// ListGiteaEndpointsReader is a Reader for the ListGiteaEndpoints structure.
type ListGiteaEndpointsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *ListGiteaEndpointsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewListGiteaEndpointsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewListGiteaEndpointsDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewListGiteaEndpointsOK creates a ListGiteaEndpointsOK with default headers values
func NewListGiteaEndpointsOK() *ListGiteaEndpointsOK {
return &ListGiteaEndpointsOK{}
}
/*
ListGiteaEndpointsOK describes a response with status code 200, with default header values.
ForgeEndpoints
*/
type ListGiteaEndpointsOK struct {
Payload garm_params.ForgeEndpoints
}
// IsSuccess returns true when this list gitea endpoints o k response has a 2xx status code
func (o *ListGiteaEndpointsOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this list gitea endpoints o k response has a 3xx status code
func (o *ListGiteaEndpointsOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this list gitea endpoints o k response has a 4xx status code
func (o *ListGiteaEndpointsOK) IsClientError() bool {
return false
}
// IsServerError returns true when this list gitea endpoints o k response has a 5xx status code
func (o *ListGiteaEndpointsOK) IsServerError() bool {
return false
}
// IsCode returns true when this list gitea endpoints o k response a status code equal to that given
func (o *ListGiteaEndpointsOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the list gitea endpoints o k response
func (o *ListGiteaEndpointsOK) Code() int {
return 200
}
func (o *ListGiteaEndpointsOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/endpoints][%d] listGiteaEndpointsOK %s", 200, payload)
}
func (o *ListGiteaEndpointsOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/endpoints][%d] listGiteaEndpointsOK %s", 200, payload)
}
func (o *ListGiteaEndpointsOK) GetPayload() garm_params.ForgeEndpoints {
return o.Payload
}
func (o *ListGiteaEndpointsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewListGiteaEndpointsDefault creates a ListGiteaEndpointsDefault with default headers values
func NewListGiteaEndpointsDefault(code int) *ListGiteaEndpointsDefault {
return &ListGiteaEndpointsDefault{
_statusCode: code,
}
}
/*
ListGiteaEndpointsDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type ListGiteaEndpointsDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this list gitea endpoints default response has a 2xx status code
func (o *ListGiteaEndpointsDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this list gitea endpoints default response has a 3xx status code
func (o *ListGiteaEndpointsDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this list gitea endpoints default response has a 4xx status code
func (o *ListGiteaEndpointsDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this list gitea endpoints default response has a 5xx status code
func (o *ListGiteaEndpointsDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this list gitea endpoints default response a status code equal to that given
func (o *ListGiteaEndpointsDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the list gitea endpoints default response
func (o *ListGiteaEndpointsDefault) Code() int {
return o._statusCode
}
func (o *ListGiteaEndpointsDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/endpoints][%d] ListGiteaEndpoints default %s", o._statusCode, payload)
}
func (o *ListGiteaEndpointsDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /gitea/endpoints][%d] ListGiteaEndpoints default %s", o._statusCode, payload)
}
func (o *ListGiteaEndpointsDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *ListGiteaEndpointsDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,128 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewListGithubEndpointsParams creates a new ListGithubEndpointsParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewListGithubEndpointsParams() *ListGithubEndpointsParams {
return &ListGithubEndpointsParams{
timeout: cr.DefaultTimeout,
}
}
// NewListGithubEndpointsParamsWithTimeout creates a new ListGithubEndpointsParams object
// with the ability to set a timeout on a request.
func NewListGithubEndpointsParamsWithTimeout(timeout time.Duration) *ListGithubEndpointsParams {
return &ListGithubEndpointsParams{
timeout: timeout,
}
}
// NewListGithubEndpointsParamsWithContext creates a new ListGithubEndpointsParams object
// with the ability to set a context for a request.
func NewListGithubEndpointsParamsWithContext(ctx context.Context) *ListGithubEndpointsParams {
return &ListGithubEndpointsParams{
Context: ctx,
}
}
// NewListGithubEndpointsParamsWithHTTPClient creates a new ListGithubEndpointsParams object
// with the ability to set a custom HTTPClient for a request.
func NewListGithubEndpointsParamsWithHTTPClient(client *http.Client) *ListGithubEndpointsParams {
return &ListGithubEndpointsParams{
HTTPClient: client,
}
}
/*
ListGithubEndpointsParams contains all the parameters to send to the API endpoint
for the list github endpoints operation.
Typically these are written to a http.Request.
*/
type ListGithubEndpointsParams struct {
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the list github endpoints params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ListGithubEndpointsParams) WithDefaults() *ListGithubEndpointsParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the list github endpoints params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ListGithubEndpointsParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the list github endpoints params
func (o *ListGithubEndpointsParams) WithTimeout(timeout time.Duration) *ListGithubEndpointsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the list github endpoints params
func (o *ListGithubEndpointsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the list github endpoints params
func (o *ListGithubEndpointsParams) WithContext(ctx context.Context) *ListGithubEndpointsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the list github endpoints params
func (o *ListGithubEndpointsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the list github endpoints params
func (o *ListGithubEndpointsParams) WithHTTPClient(client *http.Client) *ListGithubEndpointsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the list github endpoints params
func (o *ListGithubEndpointsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WriteToRequest writes these params to a swagger request
func (o *ListGithubEndpointsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// ListGithubEndpointsReader is a Reader for the ListGithubEndpoints structure.
type ListGithubEndpointsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *ListGithubEndpointsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewListGithubEndpointsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewListGithubEndpointsDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewListGithubEndpointsOK creates a ListGithubEndpointsOK with default headers values
func NewListGithubEndpointsOK() *ListGithubEndpointsOK {
return &ListGithubEndpointsOK{}
}
/*
ListGithubEndpointsOK describes a response with status code 200, with default header values.
ForgeEndpoints
*/
type ListGithubEndpointsOK struct {
Payload garm_params.ForgeEndpoints
}
// IsSuccess returns true when this list github endpoints o k response has a 2xx status code
func (o *ListGithubEndpointsOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this list github endpoints o k response has a 3xx status code
func (o *ListGithubEndpointsOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this list github endpoints o k response has a 4xx status code
func (o *ListGithubEndpointsOK) IsClientError() bool {
return false
}
// IsServerError returns true when this list github endpoints o k response has a 5xx status code
func (o *ListGithubEndpointsOK) IsServerError() bool {
return false
}
// IsCode returns true when this list github endpoints o k response a status code equal to that given
func (o *ListGithubEndpointsOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the list github endpoints o k response
func (o *ListGithubEndpointsOK) Code() int {
return 200
}
func (o *ListGithubEndpointsOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/endpoints][%d] listGithubEndpointsOK %s", 200, payload)
}
func (o *ListGithubEndpointsOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/endpoints][%d] listGithubEndpointsOK %s", 200, payload)
}
func (o *ListGithubEndpointsOK) GetPayload() garm_params.ForgeEndpoints {
return o.Payload
}
func (o *ListGithubEndpointsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewListGithubEndpointsDefault creates a ListGithubEndpointsDefault with default headers values
func NewListGithubEndpointsDefault(code int) *ListGithubEndpointsDefault {
return &ListGithubEndpointsDefault{
_statusCode: code,
}
}
/*
ListGithubEndpointsDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type ListGithubEndpointsDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this list github endpoints default response has a 2xx status code
func (o *ListGithubEndpointsDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this list github endpoints default response has a 3xx status code
func (o *ListGithubEndpointsDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this list github endpoints default response has a 4xx status code
func (o *ListGithubEndpointsDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this list github endpoints default response has a 5xx status code
func (o *ListGithubEndpointsDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this list github endpoints default response a status code equal to that given
func (o *ListGithubEndpointsDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the list github endpoints default response
func (o *ListGithubEndpointsDefault) Code() int {
return o._statusCode
}
func (o *ListGithubEndpointsDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/endpoints][%d] ListGithubEndpoints default %s", o._statusCode, payload)
}
func (o *ListGithubEndpointsDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /github/endpoints][%d] ListGithubEndpoints default %s", o._statusCode, payload)
}
func (o *ListGithubEndpointsDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *ListGithubEndpointsDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,173 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
garm_params "github.com/cloudbase/garm/params"
)
// NewUpdateGiteaEndpointParams creates a new UpdateGiteaEndpointParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewUpdateGiteaEndpointParams() *UpdateGiteaEndpointParams {
return &UpdateGiteaEndpointParams{
timeout: cr.DefaultTimeout,
}
}
// NewUpdateGiteaEndpointParamsWithTimeout creates a new UpdateGiteaEndpointParams object
// with the ability to set a timeout on a request.
func NewUpdateGiteaEndpointParamsWithTimeout(timeout time.Duration) *UpdateGiteaEndpointParams {
return &UpdateGiteaEndpointParams{
timeout: timeout,
}
}
// NewUpdateGiteaEndpointParamsWithContext creates a new UpdateGiteaEndpointParams object
// with the ability to set a context for a request.
func NewUpdateGiteaEndpointParamsWithContext(ctx context.Context) *UpdateGiteaEndpointParams {
return &UpdateGiteaEndpointParams{
Context: ctx,
}
}
// NewUpdateGiteaEndpointParamsWithHTTPClient creates a new UpdateGiteaEndpointParams object
// with the ability to set a custom HTTPClient for a request.
func NewUpdateGiteaEndpointParamsWithHTTPClient(client *http.Client) *UpdateGiteaEndpointParams {
return &UpdateGiteaEndpointParams{
HTTPClient: client,
}
}
/*
UpdateGiteaEndpointParams contains all the parameters to send to the API endpoint
for the update gitea endpoint operation.
Typically these are written to a http.Request.
*/
type UpdateGiteaEndpointParams struct {
/* Body.
Parameters used when updating a Gitea endpoint.
*/
Body garm_params.UpdateGiteaEndpointParams
/* Name.
The name of the Gitea endpoint.
*/
Name string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the update gitea endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *UpdateGiteaEndpointParams) WithDefaults() *UpdateGiteaEndpointParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the update gitea endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *UpdateGiteaEndpointParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the update gitea endpoint params
func (o *UpdateGiteaEndpointParams) WithTimeout(timeout time.Duration) *UpdateGiteaEndpointParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the update gitea endpoint params
func (o *UpdateGiteaEndpointParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the update gitea endpoint params
func (o *UpdateGiteaEndpointParams) WithContext(ctx context.Context) *UpdateGiteaEndpointParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the update gitea endpoint params
func (o *UpdateGiteaEndpointParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the update gitea endpoint params
func (o *UpdateGiteaEndpointParams) WithHTTPClient(client *http.Client) *UpdateGiteaEndpointParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the update gitea endpoint params
func (o *UpdateGiteaEndpointParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the update gitea endpoint params
func (o *UpdateGiteaEndpointParams) WithBody(body garm_params.UpdateGiteaEndpointParams) *UpdateGiteaEndpointParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the update gitea endpoint params
func (o *UpdateGiteaEndpointParams) SetBody(body garm_params.UpdateGiteaEndpointParams) {
o.Body = body
}
// WithName adds the name to the update gitea endpoint params
func (o *UpdateGiteaEndpointParams) WithName(name string) *UpdateGiteaEndpointParams {
o.SetName(name)
return o
}
// SetName adds the name to the update gitea endpoint params
func (o *UpdateGiteaEndpointParams) SetName(name string) {
o.Name = name
}
// WriteToRequest writes these params to a swagger request
func (o *UpdateGiteaEndpointParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
// path param name
if err := r.SetPathParam("name", o.Name); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// UpdateGiteaEndpointReader is a Reader for the UpdateGiteaEndpoint structure.
type UpdateGiteaEndpointReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *UpdateGiteaEndpointReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewUpdateGiteaEndpointOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewUpdateGiteaEndpointDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewUpdateGiteaEndpointOK creates a UpdateGiteaEndpointOK with default headers values
func NewUpdateGiteaEndpointOK() *UpdateGiteaEndpointOK {
return &UpdateGiteaEndpointOK{}
}
/*
UpdateGiteaEndpointOK describes a response with status code 200, with default header values.
ForgeEndpoint
*/
type UpdateGiteaEndpointOK struct {
Payload garm_params.ForgeEndpoint
}
// IsSuccess returns true when this update gitea endpoint o k response has a 2xx status code
func (o *UpdateGiteaEndpointOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this update gitea endpoint o k response has a 3xx status code
func (o *UpdateGiteaEndpointOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this update gitea endpoint o k response has a 4xx status code
func (o *UpdateGiteaEndpointOK) IsClientError() bool {
return false
}
// IsServerError returns true when this update gitea endpoint o k response has a 5xx status code
func (o *UpdateGiteaEndpointOK) IsServerError() bool {
return false
}
// IsCode returns true when this update gitea endpoint o k response a status code equal to that given
func (o *UpdateGiteaEndpointOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the update gitea endpoint o k response
func (o *UpdateGiteaEndpointOK) Code() int {
return 200
}
func (o *UpdateGiteaEndpointOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /gitea/endpoints/{name}][%d] updateGiteaEndpointOK %s", 200, payload)
}
func (o *UpdateGiteaEndpointOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /gitea/endpoints/{name}][%d] updateGiteaEndpointOK %s", 200, payload)
}
func (o *UpdateGiteaEndpointOK) GetPayload() garm_params.ForgeEndpoint {
return o.Payload
}
func (o *UpdateGiteaEndpointOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewUpdateGiteaEndpointDefault creates a UpdateGiteaEndpointDefault with default headers values
func NewUpdateGiteaEndpointDefault(code int) *UpdateGiteaEndpointDefault {
return &UpdateGiteaEndpointDefault{
_statusCode: code,
}
}
/*
UpdateGiteaEndpointDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type UpdateGiteaEndpointDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this update gitea endpoint default response has a 2xx status code
func (o *UpdateGiteaEndpointDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this update gitea endpoint default response has a 3xx status code
func (o *UpdateGiteaEndpointDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this update gitea endpoint default response has a 4xx status code
func (o *UpdateGiteaEndpointDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this update gitea endpoint default response has a 5xx status code
func (o *UpdateGiteaEndpointDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this update gitea endpoint default response a status code equal to that given
func (o *UpdateGiteaEndpointDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the update gitea endpoint default response
func (o *UpdateGiteaEndpointDefault) Code() int {
return o._statusCode
}
func (o *UpdateGiteaEndpointDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /gitea/endpoints/{name}][%d] UpdateGiteaEndpoint default %s", o._statusCode, payload)
}
func (o *UpdateGiteaEndpointDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /gitea/endpoints/{name}][%d] UpdateGiteaEndpoint default %s", o._statusCode, payload)
}
func (o *UpdateGiteaEndpointDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *UpdateGiteaEndpointDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,173 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
garm_params "github.com/cloudbase/garm/params"
)
// NewUpdateGithubEndpointParams creates a new UpdateGithubEndpointParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewUpdateGithubEndpointParams() *UpdateGithubEndpointParams {
return &UpdateGithubEndpointParams{
timeout: cr.DefaultTimeout,
}
}
// NewUpdateGithubEndpointParamsWithTimeout creates a new UpdateGithubEndpointParams object
// with the ability to set a timeout on a request.
func NewUpdateGithubEndpointParamsWithTimeout(timeout time.Duration) *UpdateGithubEndpointParams {
return &UpdateGithubEndpointParams{
timeout: timeout,
}
}
// NewUpdateGithubEndpointParamsWithContext creates a new UpdateGithubEndpointParams object
// with the ability to set a context for a request.
func NewUpdateGithubEndpointParamsWithContext(ctx context.Context) *UpdateGithubEndpointParams {
return &UpdateGithubEndpointParams{
Context: ctx,
}
}
// NewUpdateGithubEndpointParamsWithHTTPClient creates a new UpdateGithubEndpointParams object
// with the ability to set a custom HTTPClient for a request.
func NewUpdateGithubEndpointParamsWithHTTPClient(client *http.Client) *UpdateGithubEndpointParams {
return &UpdateGithubEndpointParams{
HTTPClient: client,
}
}
/*
UpdateGithubEndpointParams contains all the parameters to send to the API endpoint
for the update github endpoint operation.
Typically these are written to a http.Request.
*/
type UpdateGithubEndpointParams struct {
/* Body.
Parameters used when updating a GitHub endpoint.
*/
Body garm_params.UpdateGithubEndpointParams
/* Name.
The name of the GitHub endpoint.
*/
Name string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the update github endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *UpdateGithubEndpointParams) WithDefaults() *UpdateGithubEndpointParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the update github endpoint params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *UpdateGithubEndpointParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the update github endpoint params
func (o *UpdateGithubEndpointParams) WithTimeout(timeout time.Duration) *UpdateGithubEndpointParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the update github endpoint params
func (o *UpdateGithubEndpointParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the update github endpoint params
func (o *UpdateGithubEndpointParams) WithContext(ctx context.Context) *UpdateGithubEndpointParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the update github endpoint params
func (o *UpdateGithubEndpointParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the update github endpoint params
func (o *UpdateGithubEndpointParams) WithHTTPClient(client *http.Client) *UpdateGithubEndpointParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the update github endpoint params
func (o *UpdateGithubEndpointParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the update github endpoint params
func (o *UpdateGithubEndpointParams) WithBody(body garm_params.UpdateGithubEndpointParams) *UpdateGithubEndpointParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the update github endpoint params
func (o *UpdateGithubEndpointParams) SetBody(body garm_params.UpdateGithubEndpointParams) {
o.Body = body
}
// WithName adds the name to the update github endpoint params
func (o *UpdateGithubEndpointParams) WithName(name string) *UpdateGithubEndpointParams {
o.SetName(name)
return o
}
// SetName adds the name to the update github endpoint params
func (o *UpdateGithubEndpointParams) SetName(name string) {
o.Name = name
}
// WriteToRequest writes these params to a swagger request
func (o *UpdateGithubEndpointParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
// path param name
if err := r.SetPathParam("name", o.Name); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package endpoints
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// UpdateGithubEndpointReader is a Reader for the UpdateGithubEndpoint structure.
type UpdateGithubEndpointReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *UpdateGithubEndpointReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewUpdateGithubEndpointOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewUpdateGithubEndpointDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewUpdateGithubEndpointOK creates a UpdateGithubEndpointOK with default headers values
func NewUpdateGithubEndpointOK() *UpdateGithubEndpointOK {
return &UpdateGithubEndpointOK{}
}
/*
UpdateGithubEndpointOK describes a response with status code 200, with default header values.
ForgeEndpoint
*/
type UpdateGithubEndpointOK struct {
Payload garm_params.ForgeEndpoint
}
// IsSuccess returns true when this update github endpoint o k response has a 2xx status code
func (o *UpdateGithubEndpointOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this update github endpoint o k response has a 3xx status code
func (o *UpdateGithubEndpointOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this update github endpoint o k response has a 4xx status code
func (o *UpdateGithubEndpointOK) IsClientError() bool {
return false
}
// IsServerError returns true when this update github endpoint o k response has a 5xx status code
func (o *UpdateGithubEndpointOK) IsServerError() bool {
return false
}
// IsCode returns true when this update github endpoint o k response a status code equal to that given
func (o *UpdateGithubEndpointOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the update github endpoint o k response
func (o *UpdateGithubEndpointOK) Code() int {
return 200
}
func (o *UpdateGithubEndpointOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /github/endpoints/{name}][%d] updateGithubEndpointOK %s", 200, payload)
}
func (o *UpdateGithubEndpointOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /github/endpoints/{name}][%d] updateGithubEndpointOK %s", 200, payload)
}
func (o *UpdateGithubEndpointOK) GetPayload() garm_params.ForgeEndpoint {
return o.Payload
}
func (o *UpdateGithubEndpointOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewUpdateGithubEndpointDefault creates a UpdateGithubEndpointDefault with default headers values
func NewUpdateGithubEndpointDefault(code int) *UpdateGithubEndpointDefault {
return &UpdateGithubEndpointDefault{
_statusCode: code,
}
}
/*
UpdateGithubEndpointDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type UpdateGithubEndpointDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this update github endpoint default response has a 2xx status code
func (o *UpdateGithubEndpointDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this update github endpoint default response has a 3xx status code
func (o *UpdateGithubEndpointDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this update github endpoint default response has a 4xx status code
func (o *UpdateGithubEndpointDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this update github endpoint default response has a 5xx status code
func (o *UpdateGithubEndpointDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this update github endpoint default response a status code equal to that given
func (o *UpdateGithubEndpointDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the update github endpoint default response
func (o *UpdateGithubEndpointDefault) Code() int {
return o._statusCode
}
func (o *UpdateGithubEndpointDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /github/endpoints/{name}][%d] UpdateGithubEndpoint default %s", o._statusCode, payload)
}
func (o *UpdateGithubEndpointDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PUT /github/endpoints/{name}][%d] UpdateGithubEndpoint default %s", o._statusCode, payload)
}
func (o *UpdateGithubEndpointDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *UpdateGithubEndpointDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package enterprises
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
garm_params "github.com/cloudbase/garm/params"
)
// NewCreateEnterpriseParams creates a new CreateEnterpriseParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewCreateEnterpriseParams() *CreateEnterpriseParams {
return &CreateEnterpriseParams{
timeout: cr.DefaultTimeout,
}
}
// NewCreateEnterpriseParamsWithTimeout creates a new CreateEnterpriseParams object
// with the ability to set a timeout on a request.
func NewCreateEnterpriseParamsWithTimeout(timeout time.Duration) *CreateEnterpriseParams {
return &CreateEnterpriseParams{
timeout: timeout,
}
}
// NewCreateEnterpriseParamsWithContext creates a new CreateEnterpriseParams object
// with the ability to set a context for a request.
func NewCreateEnterpriseParamsWithContext(ctx context.Context) *CreateEnterpriseParams {
return &CreateEnterpriseParams{
Context: ctx,
}
}
// NewCreateEnterpriseParamsWithHTTPClient creates a new CreateEnterpriseParams object
// with the ability to set a custom HTTPClient for a request.
func NewCreateEnterpriseParamsWithHTTPClient(client *http.Client) *CreateEnterpriseParams {
return &CreateEnterpriseParams{
HTTPClient: client,
}
}
/*
CreateEnterpriseParams contains all the parameters to send to the API endpoint
for the create enterprise operation.
Typically these are written to a http.Request.
*/
type CreateEnterpriseParams struct {
/* Body.
Parameters used to create the enterprise.
*/
Body garm_params.CreateEnterpriseParams
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the create enterprise params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateEnterpriseParams) WithDefaults() *CreateEnterpriseParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the create enterprise params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateEnterpriseParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the create enterprise params
func (o *CreateEnterpriseParams) WithTimeout(timeout time.Duration) *CreateEnterpriseParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the create enterprise params
func (o *CreateEnterpriseParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the create enterprise params
func (o *CreateEnterpriseParams) WithContext(ctx context.Context) *CreateEnterpriseParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the create enterprise params
func (o *CreateEnterpriseParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the create enterprise params
func (o *CreateEnterpriseParams) WithHTTPClient(client *http.Client) *CreateEnterpriseParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the create enterprise params
func (o *CreateEnterpriseParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the create enterprise params
func (o *CreateEnterpriseParams) WithBody(body garm_params.CreateEnterpriseParams) *CreateEnterpriseParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the create enterprise params
func (o *CreateEnterpriseParams) SetBody(body garm_params.CreateEnterpriseParams) {
o.Body = body
}
// WriteToRequest writes these params to a swagger request
func (o *CreateEnterpriseParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,173 @@
// Code generated by go-swagger; DO NOT EDIT.
package enterprises
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
garm_params "github.com/cloudbase/garm/params"
)
// NewCreateEnterprisePoolParams creates a new CreateEnterprisePoolParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewCreateEnterprisePoolParams() *CreateEnterprisePoolParams {
return &CreateEnterprisePoolParams{
timeout: cr.DefaultTimeout,
}
}
// NewCreateEnterprisePoolParamsWithTimeout creates a new CreateEnterprisePoolParams object
// with the ability to set a timeout on a request.
func NewCreateEnterprisePoolParamsWithTimeout(timeout time.Duration) *CreateEnterprisePoolParams {
return &CreateEnterprisePoolParams{
timeout: timeout,
}
}
// NewCreateEnterprisePoolParamsWithContext creates a new CreateEnterprisePoolParams object
// with the ability to set a context for a request.
func NewCreateEnterprisePoolParamsWithContext(ctx context.Context) *CreateEnterprisePoolParams {
return &CreateEnterprisePoolParams{
Context: ctx,
}
}
// NewCreateEnterprisePoolParamsWithHTTPClient creates a new CreateEnterprisePoolParams object
// with the ability to set a custom HTTPClient for a request.
func NewCreateEnterprisePoolParamsWithHTTPClient(client *http.Client) *CreateEnterprisePoolParams {
return &CreateEnterprisePoolParams{
HTTPClient: client,
}
}
/*
CreateEnterprisePoolParams contains all the parameters to send to the API endpoint
for the create enterprise pool operation.
Typically these are written to a http.Request.
*/
type CreateEnterprisePoolParams struct {
/* Body.
Parameters used when creating the enterprise pool.
*/
Body garm_params.CreatePoolParams
/* EnterpriseID.
Enterprise ID.
*/
EnterpriseID string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the create enterprise pool params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateEnterprisePoolParams) WithDefaults() *CreateEnterprisePoolParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the create enterprise pool params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateEnterprisePoolParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the create enterprise pool params
func (o *CreateEnterprisePoolParams) WithTimeout(timeout time.Duration) *CreateEnterprisePoolParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the create enterprise pool params
func (o *CreateEnterprisePoolParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the create enterprise pool params
func (o *CreateEnterprisePoolParams) WithContext(ctx context.Context) *CreateEnterprisePoolParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the create enterprise pool params
func (o *CreateEnterprisePoolParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the create enterprise pool params
func (o *CreateEnterprisePoolParams) WithHTTPClient(client *http.Client) *CreateEnterprisePoolParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the create enterprise pool params
func (o *CreateEnterprisePoolParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the create enterprise pool params
func (o *CreateEnterprisePoolParams) WithBody(body garm_params.CreatePoolParams) *CreateEnterprisePoolParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the create enterprise pool params
func (o *CreateEnterprisePoolParams) SetBody(body garm_params.CreatePoolParams) {
o.Body = body
}
// WithEnterpriseID adds the enterpriseID to the create enterprise pool params
func (o *CreateEnterprisePoolParams) WithEnterpriseID(enterpriseID string) *CreateEnterprisePoolParams {
o.SetEnterpriseID(enterpriseID)
return o
}
// SetEnterpriseID adds the enterpriseId to the create enterprise pool params
func (o *CreateEnterprisePoolParams) SetEnterpriseID(enterpriseID string) {
o.EnterpriseID = enterpriseID
}
// WriteToRequest writes these params to a swagger request
func (o *CreateEnterprisePoolParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
// path param enterpriseID
if err := r.SetPathParam("enterpriseID", o.EnterpriseID); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package enterprises
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// CreateEnterprisePoolReader is a Reader for the CreateEnterprisePool structure.
type CreateEnterprisePoolReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *CreateEnterprisePoolReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewCreateEnterprisePoolOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewCreateEnterprisePoolDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewCreateEnterprisePoolOK creates a CreateEnterprisePoolOK with default headers values
func NewCreateEnterprisePoolOK() *CreateEnterprisePoolOK {
return &CreateEnterprisePoolOK{}
}
/*
CreateEnterprisePoolOK describes a response with status code 200, with default header values.
Pool
*/
type CreateEnterprisePoolOK struct {
Payload garm_params.Pool
}
// IsSuccess returns true when this create enterprise pool o k response has a 2xx status code
func (o *CreateEnterprisePoolOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this create enterprise pool o k response has a 3xx status code
func (o *CreateEnterprisePoolOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this create enterprise pool o k response has a 4xx status code
func (o *CreateEnterprisePoolOK) IsClientError() bool {
return false
}
// IsServerError returns true when this create enterprise pool o k response has a 5xx status code
func (o *CreateEnterprisePoolOK) IsServerError() bool {
return false
}
// IsCode returns true when this create enterprise pool o k response a status code equal to that given
func (o *CreateEnterprisePoolOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the create enterprise pool o k response
func (o *CreateEnterprisePoolOK) Code() int {
return 200
}
func (o *CreateEnterprisePoolOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises/{enterpriseID}/pools][%d] createEnterprisePoolOK %s", 200, payload)
}
func (o *CreateEnterprisePoolOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises/{enterpriseID}/pools][%d] createEnterprisePoolOK %s", 200, payload)
}
func (o *CreateEnterprisePoolOK) GetPayload() garm_params.Pool {
return o.Payload
}
func (o *CreateEnterprisePoolOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewCreateEnterprisePoolDefault creates a CreateEnterprisePoolDefault with default headers values
func NewCreateEnterprisePoolDefault(code int) *CreateEnterprisePoolDefault {
return &CreateEnterprisePoolDefault{
_statusCode: code,
}
}
/*
CreateEnterprisePoolDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type CreateEnterprisePoolDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this create enterprise pool default response has a 2xx status code
func (o *CreateEnterprisePoolDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this create enterprise pool default response has a 3xx status code
func (o *CreateEnterprisePoolDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this create enterprise pool default response has a 4xx status code
func (o *CreateEnterprisePoolDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this create enterprise pool default response has a 5xx status code
func (o *CreateEnterprisePoolDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this create enterprise pool default response a status code equal to that given
func (o *CreateEnterprisePoolDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the create enterprise pool default response
func (o *CreateEnterprisePoolDefault) Code() int {
return o._statusCode
}
func (o *CreateEnterprisePoolDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises/{enterpriseID}/pools][%d] CreateEnterprisePool default %s", o._statusCode, payload)
}
func (o *CreateEnterprisePoolDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises/{enterpriseID}/pools][%d] CreateEnterprisePool default %s", o._statusCode, payload)
}
func (o *CreateEnterprisePoolDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *CreateEnterprisePoolDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package enterprises
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// CreateEnterpriseReader is a Reader for the CreateEnterprise structure.
type CreateEnterpriseReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *CreateEnterpriseReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewCreateEnterpriseOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewCreateEnterpriseDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewCreateEnterpriseOK creates a CreateEnterpriseOK with default headers values
func NewCreateEnterpriseOK() *CreateEnterpriseOK {
return &CreateEnterpriseOK{}
}
/*
CreateEnterpriseOK describes a response with status code 200, with default header values.
Enterprise
*/
type CreateEnterpriseOK struct {
Payload garm_params.Enterprise
}
// IsSuccess returns true when this create enterprise o k response has a 2xx status code
func (o *CreateEnterpriseOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this create enterprise o k response has a 3xx status code
func (o *CreateEnterpriseOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this create enterprise o k response has a 4xx status code
func (o *CreateEnterpriseOK) IsClientError() bool {
return false
}
// IsServerError returns true when this create enterprise o k response has a 5xx status code
func (o *CreateEnterpriseOK) IsServerError() bool {
return false
}
// IsCode returns true when this create enterprise o k response a status code equal to that given
func (o *CreateEnterpriseOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the create enterprise o k response
func (o *CreateEnterpriseOK) Code() int {
return 200
}
func (o *CreateEnterpriseOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises][%d] createEnterpriseOK %s", 200, payload)
}
func (o *CreateEnterpriseOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises][%d] createEnterpriseOK %s", 200, payload)
}
func (o *CreateEnterpriseOK) GetPayload() garm_params.Enterprise {
return o.Payload
}
func (o *CreateEnterpriseOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewCreateEnterpriseDefault creates a CreateEnterpriseDefault with default headers values
func NewCreateEnterpriseDefault(code int) *CreateEnterpriseDefault {
return &CreateEnterpriseDefault{
_statusCode: code,
}
}
/*
CreateEnterpriseDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type CreateEnterpriseDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this create enterprise default response has a 2xx status code
func (o *CreateEnterpriseDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this create enterprise default response has a 3xx status code
func (o *CreateEnterpriseDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this create enterprise default response has a 4xx status code
func (o *CreateEnterpriseDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this create enterprise default response has a 5xx status code
func (o *CreateEnterpriseDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this create enterprise default response a status code equal to that given
func (o *CreateEnterpriseDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the create enterprise default response
func (o *CreateEnterpriseDefault) Code() int {
return o._statusCode
}
func (o *CreateEnterpriseDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises][%d] CreateEnterprise default %s", o._statusCode, payload)
}
func (o *CreateEnterpriseDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises][%d] CreateEnterprise default %s", o._statusCode, payload)
}
func (o *CreateEnterpriseDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *CreateEnterpriseDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,173 @@
// Code generated by go-swagger; DO NOT EDIT.
package enterprises
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
garm_params "github.com/cloudbase/garm/params"
)
// NewCreateEnterpriseScaleSetParams creates a new CreateEnterpriseScaleSetParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewCreateEnterpriseScaleSetParams() *CreateEnterpriseScaleSetParams {
return &CreateEnterpriseScaleSetParams{
timeout: cr.DefaultTimeout,
}
}
// NewCreateEnterpriseScaleSetParamsWithTimeout creates a new CreateEnterpriseScaleSetParams object
// with the ability to set a timeout on a request.
func NewCreateEnterpriseScaleSetParamsWithTimeout(timeout time.Duration) *CreateEnterpriseScaleSetParams {
return &CreateEnterpriseScaleSetParams{
timeout: timeout,
}
}
// NewCreateEnterpriseScaleSetParamsWithContext creates a new CreateEnterpriseScaleSetParams object
// with the ability to set a context for a request.
func NewCreateEnterpriseScaleSetParamsWithContext(ctx context.Context) *CreateEnterpriseScaleSetParams {
return &CreateEnterpriseScaleSetParams{
Context: ctx,
}
}
// NewCreateEnterpriseScaleSetParamsWithHTTPClient creates a new CreateEnterpriseScaleSetParams object
// with the ability to set a custom HTTPClient for a request.
func NewCreateEnterpriseScaleSetParamsWithHTTPClient(client *http.Client) *CreateEnterpriseScaleSetParams {
return &CreateEnterpriseScaleSetParams{
HTTPClient: client,
}
}
/*
CreateEnterpriseScaleSetParams contains all the parameters to send to the API endpoint
for the create enterprise scale set operation.
Typically these are written to a http.Request.
*/
type CreateEnterpriseScaleSetParams struct {
/* Body.
Parameters used when creating the enterprise scale set.
*/
Body garm_params.CreateScaleSetParams
/* EnterpriseID.
Enterprise ID.
*/
EnterpriseID string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the create enterprise scale set params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateEnterpriseScaleSetParams) WithDefaults() *CreateEnterpriseScaleSetParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the create enterprise scale set params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *CreateEnterpriseScaleSetParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the create enterprise scale set params
func (o *CreateEnterpriseScaleSetParams) WithTimeout(timeout time.Duration) *CreateEnterpriseScaleSetParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the create enterprise scale set params
func (o *CreateEnterpriseScaleSetParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the create enterprise scale set params
func (o *CreateEnterpriseScaleSetParams) WithContext(ctx context.Context) *CreateEnterpriseScaleSetParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the create enterprise scale set params
func (o *CreateEnterpriseScaleSetParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the create enterprise scale set params
func (o *CreateEnterpriseScaleSetParams) WithHTTPClient(client *http.Client) *CreateEnterpriseScaleSetParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the create enterprise scale set params
func (o *CreateEnterpriseScaleSetParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the create enterprise scale set params
func (o *CreateEnterpriseScaleSetParams) WithBody(body garm_params.CreateScaleSetParams) *CreateEnterpriseScaleSetParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the create enterprise scale set params
func (o *CreateEnterpriseScaleSetParams) SetBody(body garm_params.CreateScaleSetParams) {
o.Body = body
}
// WithEnterpriseID adds the enterpriseID to the create enterprise scale set params
func (o *CreateEnterpriseScaleSetParams) WithEnterpriseID(enterpriseID string) *CreateEnterpriseScaleSetParams {
o.SetEnterpriseID(enterpriseID)
return o
}
// SetEnterpriseID adds the enterpriseId to the create enterprise scale set params
func (o *CreateEnterpriseScaleSetParams) SetEnterpriseID(enterpriseID string) {
o.EnterpriseID = enterpriseID
}
// WriteToRequest writes these params to a swagger request
func (o *CreateEnterpriseScaleSetParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
// path param enterpriseID
if err := r.SetPathParam("enterpriseID", o.EnterpriseID); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View file

@ -0,0 +1,184 @@
// Code generated by go-swagger; DO NOT EDIT.
package enterprises
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
apiserver_params "github.com/cloudbase/garm/apiserver/params"
garm_params "github.com/cloudbase/garm/params"
)
// CreateEnterpriseScaleSetReader is a Reader for the CreateEnterpriseScaleSet structure.
type CreateEnterpriseScaleSetReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *CreateEnterpriseScaleSetReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewCreateEnterpriseScaleSetOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewCreateEnterpriseScaleSetDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewCreateEnterpriseScaleSetOK creates a CreateEnterpriseScaleSetOK with default headers values
func NewCreateEnterpriseScaleSetOK() *CreateEnterpriseScaleSetOK {
return &CreateEnterpriseScaleSetOK{}
}
/*
CreateEnterpriseScaleSetOK describes a response with status code 200, with default header values.
ScaleSet
*/
type CreateEnterpriseScaleSetOK struct {
Payload garm_params.ScaleSet
}
// IsSuccess returns true when this create enterprise scale set o k response has a 2xx status code
func (o *CreateEnterpriseScaleSetOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this create enterprise scale set o k response has a 3xx status code
func (o *CreateEnterpriseScaleSetOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this create enterprise scale set o k response has a 4xx status code
func (o *CreateEnterpriseScaleSetOK) IsClientError() bool {
return false
}
// IsServerError returns true when this create enterprise scale set o k response has a 5xx status code
func (o *CreateEnterpriseScaleSetOK) IsServerError() bool {
return false
}
// IsCode returns true when this create enterprise scale set o k response a status code equal to that given
func (o *CreateEnterpriseScaleSetOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the create enterprise scale set o k response
func (o *CreateEnterpriseScaleSetOK) Code() int {
return 200
}
func (o *CreateEnterpriseScaleSetOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises/{enterpriseID}/scalesets][%d] createEnterpriseScaleSetOK %s", 200, payload)
}
func (o *CreateEnterpriseScaleSetOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises/{enterpriseID}/scalesets][%d] createEnterpriseScaleSetOK %s", 200, payload)
}
func (o *CreateEnterpriseScaleSetOK) GetPayload() garm_params.ScaleSet {
return o.Payload
}
func (o *CreateEnterpriseScaleSetOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewCreateEnterpriseScaleSetDefault creates a CreateEnterpriseScaleSetDefault with default headers values
func NewCreateEnterpriseScaleSetDefault(code int) *CreateEnterpriseScaleSetDefault {
return &CreateEnterpriseScaleSetDefault{
_statusCode: code,
}
}
/*
CreateEnterpriseScaleSetDefault describes a response with status code -1, with default header values.
APIErrorResponse
*/
type CreateEnterpriseScaleSetDefault struct {
_statusCode int
Payload apiserver_params.APIErrorResponse
}
// IsSuccess returns true when this create enterprise scale set default response has a 2xx status code
func (o *CreateEnterpriseScaleSetDefault) IsSuccess() bool {
return o._statusCode/100 == 2
}
// IsRedirect returns true when this create enterprise scale set default response has a 3xx status code
func (o *CreateEnterpriseScaleSetDefault) IsRedirect() bool {
return o._statusCode/100 == 3
}
// IsClientError returns true when this create enterprise scale set default response has a 4xx status code
func (o *CreateEnterpriseScaleSetDefault) IsClientError() bool {
return o._statusCode/100 == 4
}
// IsServerError returns true when this create enterprise scale set default response has a 5xx status code
func (o *CreateEnterpriseScaleSetDefault) IsServerError() bool {
return o._statusCode/100 == 5
}
// IsCode returns true when this create enterprise scale set default response a status code equal to that given
func (o *CreateEnterpriseScaleSetDefault) IsCode(code int) bool {
return o._statusCode == code
}
// Code gets the status code for the create enterprise scale set default response
func (o *CreateEnterpriseScaleSetDefault) Code() int {
return o._statusCode
}
func (o *CreateEnterpriseScaleSetDefault) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises/{enterpriseID}/scalesets][%d] CreateEnterpriseScaleSet default %s", o._statusCode, payload)
}
func (o *CreateEnterpriseScaleSetDefault) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /enterprises/{enterpriseID}/scalesets][%d] CreateEnterpriseScaleSet default %s", o._statusCode, payload)
}
func (o *CreateEnterpriseScaleSetDefault) GetPayload() apiserver_params.APIErrorResponse {
return o.Payload
}
func (o *CreateEnterpriseScaleSetDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View file

@ -0,0 +1,151 @@
// Code generated by go-swagger; DO NOT EDIT.
package enterprises
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewDeleteEnterpriseParams creates a new DeleteEnterpriseParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewDeleteEnterpriseParams() *DeleteEnterpriseParams {
return &DeleteEnterpriseParams{
timeout: cr.DefaultTimeout,
}
}
// NewDeleteEnterpriseParamsWithTimeout creates a new DeleteEnterpriseParams object
// with the ability to set a timeout on a request.
func NewDeleteEnterpriseParamsWithTimeout(timeout time.Duration) *DeleteEnterpriseParams {
return &DeleteEnterpriseParams{
timeout: timeout,
}
}
// NewDeleteEnterpriseParamsWithContext creates a new DeleteEnterpriseParams object
// with the ability to set a context for a request.
func NewDeleteEnterpriseParamsWithContext(ctx context.Context) *DeleteEnterpriseParams {
return &DeleteEnterpriseParams{
Context: ctx,
}
}
// NewDeleteEnterpriseParamsWithHTTPClient creates a new DeleteEnterpriseParams object
// with the ability to set a custom HTTPClient for a request.
func NewDeleteEnterpriseParamsWithHTTPClient(client *http.Client) *DeleteEnterpriseParams {
return &DeleteEnterpriseParams{
HTTPClient: client,
}
}
/*
DeleteEnterpriseParams contains all the parameters to send to the API endpoint
for the delete enterprise operation.
Typically these are written to a http.Request.
*/
type DeleteEnterpriseParams struct {
/* EnterpriseID.
ID of the enterprise to delete.
*/
EnterpriseID string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the delete enterprise params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *DeleteEnterpriseParams) WithDefaults() *DeleteEnterpriseParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the delete enterprise params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *DeleteEnterpriseParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the delete enterprise params
func (o *DeleteEnterpriseParams) WithTimeout(timeout time.Duration) *DeleteEnterpriseParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the delete enterprise params
func (o *DeleteEnterpriseParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the delete enterprise params
func (o *DeleteEnterpriseParams) WithContext(ctx context.Context) *DeleteEnterpriseParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the delete enterprise params
func (o *DeleteEnterpriseParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the delete enterprise params
func (o *DeleteEnterpriseParams) WithHTTPClient(client *http.Client) *DeleteEnterpriseParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the delete enterprise params
func (o *DeleteEnterpriseParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithEnterpriseID adds the enterpriseID to the delete enterprise params
func (o *DeleteEnterpriseParams) WithEnterpriseID(enterpriseID string) *DeleteEnterpriseParams {
o.SetEnterpriseID(enterpriseID)
return o
}
// SetEnterpriseID adds the enterpriseId to the delete enterprise params
func (o *DeleteEnterpriseParams) SetEnterpriseID(enterpriseID string) {
o.EnterpriseID = enterpriseID
}
// WriteToRequest writes these params to a swagger request
func (o *DeleteEnterpriseParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param enterpriseID
if err := r.SetPathParam("enterpriseID", o.EnterpriseID); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

Some files were not shown because too many files have changed in this diff Show more