Skip to content

feat(coderd): update endpoint to allow filtering provisioner daemons by tags #15448

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
3d45f55
feat(coderd/database): allow filtering provisioner daemons by tags
SasSwart Nov 8, 2024
92b9d25
feat(coderd/database): allow filtering provisioner daemons by tags
SasSwart Nov 8, 2024
e68a8fc
add a type hint for sqlc
SasSwart Nov 8, 2024
93058e6
ensure BC with GetProvisionerDaemonsByOrganization
SasSwart Nov 8, 2024
a2bfae3
add a type hint for sqlc
SasSwart Nov 11, 2024
39ab8a0
fix unit test
SasSwart Nov 11, 2024
8bf79c8
Add tags param to provisioner daemons endpoint
SasSwart Nov 11, 2024
86f7dab
fix provisioner tag filtering
SasSwart Nov 11, 2024
bd6f3ed
handle tag reading error
SasSwart Nov 11, 2024
a2476dc
remove assignment to a nil map
SasSwart Nov 11, 2024
e835326
filter by tags in dbmem
SasSwart Nov 11, 2024
23bd23f
correctly set the default value when no tags are provided
SasSwart Nov 11, 2024
9985ef6
support the zero value tag in sql
SasSwart Nov 11, 2024
a173bfb
update the default value for when no tags are provided
SasSwart Nov 12, 2024
70c7ea9
use a sql domain as a type alias so that we can override it as a Stri…
SasSwart Nov 12, 2024
1c57bd2
complete down migration
SasSwart Nov 12, 2024
ebb716d
complete down migration
SasSwart Nov 12, 2024
96b64f4
update the default value for when no tags are provided
SasSwart Nov 12, 2024
5941dc3
fix job acquisition for untagged provisioners
SasSwart Nov 12, 2024
ff75f5e
make gen
SasSwart Nov 12, 2024
85b1ef4
review notes
SasSwart Nov 12, 2024
071fdc4
fix down migration
SasSwart Nov 12, 2024
78abf67
use the correct name for provisionerdaemons' tag field
SasSwart Nov 12, 2024
d1c7d3e
typo
SasSwart Nov 12, 2024
38d77cf
use the updated tag name
SasSwart Nov 12, 2024
1c64353
fix special case of tagset_contains
SasSwart Nov 12, 2024
8508cd8
Use a stringmap instead of a stringslice for provisioner tags
SasSwart Nov 13, 2024
9dcbb83
update tags param parsing in provisionerDaemons
SasSwart Nov 13, 2024
4c1fc0d
update tags param parsing in provisionerDaemons
SasSwart Nov 13, 2024
fbd70f3
fix special case of tagset_contains
SasSwart Nov 13, 2024
69126f4
rename tagset_contains function
SasSwart Nov 13, 2024
e109caf
attempt to fix the special case for provisioner_tagset_contains
SasSwart Nov 13, 2024
f10561e
attempt to fix the special case for provisioner_tagset_contains
SasSwart Nov 13, 2024
a56b130
attempt to fix the special case for provisioner_tagset_contains
SasSwart Nov 13, 2024
2bce007
fix provisioner_tagset_contains
SasSwart Nov 13, 2024
2860f5d
remove defunct code
SasSwart Nov 14, 2024
d6f26df
Add tag filtering tests for GetProvisionerDaemons
SasSwart Nov 14, 2024
1ce410f
fix foreign key constraint in tests
SasSwart Nov 14, 2024
c065742
Add linting
SasSwart Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add tags param to provisioner daemons endpoint
  • Loading branch information
SasSwart committed Nov 11, 2024
commit 8bf79c8e2432530b071c71c1a4cc136a999fc6fb
9 changes: 9 additions & 0 deletions coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 1 addition & 5 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 2 additions & 6 deletions coderd/database/queries/provisionerdaemons.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,10 @@ FROM
provisioner_daemons
WHERE
-- This is the original search criteria:
(@organization_id :: uuid IS NULL OR organization_id = @organization_id :: uuid)
organization_id = @organization_id :: uuid
AND
-- adding support for searching by tags:
(@tags :: jsonb IS NULL OR tags_compatible(@tags :: jsonb, provisioner_daemons.tags :: jsonb))
AND
-- Because we're adding @tags as a second search parameter, we need to do this check to
-- ensure that the first parameter's behavior remains unchanged when no second parameter is provided:
(@organization_id :: uuid IS NOT NULL OR @tags IS NOT NULL);
(@tags :: jsonb IS NULL OR tags_compatible(@tags :: jsonb, provisioner_daemons.tags :: jsonb));

-- name: DeleteOldProvisionerDaemons :exec
-- Delete provisioner daemons that have been created at least a week ago
Expand Down
21 changes: 16 additions & 5 deletions codersdk/organizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"

Expand Down Expand Up @@ -314,11 +315,21 @@ func (c *Client) ProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, e
return daemons, json.NewDecoder(res.Body).Decode(&daemons)
}

func (c *Client) OrganizationProvisionerDaemons(ctx context.Context, organizationID uuid.UUID) ([]ProvisionerDaemon, error) {
res, err := c.Request(ctx, http.MethodGet,
fmt.Sprintf("/api/v2/organizations/%s/provisionerdaemons", organizationID.String()),
nil,
)
func (c *Client) OrganizationProvisionerDaemons(ctx context.Context, organizationID uuid.UUID, tags []string) ([]ProvisionerDaemon, error) {
baseURL := fmt.Sprintf("/api/v2/organizations/%s/provisionerdaemons", organizationID.String())

queryParams := url.Values{}
if len(tags) > 0 {
for _, tag := range tags {
queryParams.Add("tags", tag)
}
}

if len(queryParams) > 0 {
baseURL = fmt.Sprintf("%s?%s", baseURL, queryParams.Encode())
Copy link
Contributor

Choose a reason for hiding this comment

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

It'd be less pithy but more durable if you used the url.URL type here to construct the URL.

}

res, err := c.Request(ctx, http.MethodGet, baseURL, nil)
if err != nil {
return nil, xerrors.Errorf("execute request: %w", err)
}
Expand Down
7 changes: 4 additions & 3 deletions docs/reference/api/enterprise.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions enterprise/cli/provisionerdaemonstart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func TestProvisionerDaemon_SessionToken(t *testing.T) {
var daemons []codersdk.ProvisionerDaemon
var err error
require.Eventually(t, func() bool {
daemons, err = client.OrganizationProvisionerDaemons(ctx, anotherOrg.ID)
daemons, err = client.OrganizationProvisionerDaemons(ctx, anotherOrg.ID, nil)
if err != nil {
return false
}
Expand Down Expand Up @@ -282,7 +282,7 @@ func TestProvisionerDaemon_ProvisionerKey(t *testing.T) {

var daemons []codersdk.ProvisionerDaemon
require.Eventually(t, func() bool {
daemons, err = client.OrganizationProvisionerDaemons(ctx, user.OrganizationID)
daemons, err = client.OrganizationProvisionerDaemons(ctx, user.OrganizationID, nil)
if err != nil {
return false
}
Expand Down Expand Up @@ -376,7 +376,7 @@ func TestProvisionerDaemon_ProvisionerKey(t *testing.T) {

var daemons []codersdk.ProvisionerDaemon
require.Eventually(t, func() bool {
daemons, err = client.OrganizationProvisionerDaemons(ctx, anotherOrg.ID)
daemons, err = client.OrganizationProvisionerDaemons(ctx, anotherOrg.ID, nil)
if err != nil {
return false
}
Expand Down
30 changes: 29 additions & 1 deletion enterprise/coderd/provisionerdaemons.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package coderd
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -56,13 +57,22 @@ func (api *API) provisionerDaemonsEnabledMW(next http.Handler) http.Handler {
// @Produce json
// @Tags Enterprise
// @Param organization path string true "Organization ID" format(uuid)
// @Param tags query []string false "Provisioner tags to filter by"
// @Success 200 {array} codersdk.ProvisionerDaemon
// @Router /organizations/{organization}/provisionerdaemons [get]
func (api *API) provisionerDaemons(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
org := httpmw.OrganizationParam(r)

daemons, err := api.Database.GetProvisionerDaemonsByOrganization(ctx, database.GetProvisionerDaemonsByOrganizationParams{OrganizationID: org.ID})
tags := provisionerTags(r)

daemons, err := api.Database.GetProvisionerDaemonsByOrganization(
ctx,
database.GetProvisionerDaemonsByOrganizationParams{
OrganizationID: org.ID,
Tags: tags,
},
)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching provisioner daemons.",
Expand All @@ -74,6 +84,24 @@ func (api *API) provisionerDaemons(rw http.ResponseWriter, r *http.Request) {
httpapi.Write(ctx, rw, http.StatusOK, db2sdk.List(daemons, db2sdk.ProvisionerDaemon))
}

func provisionerTags(r *http.Request) json.RawMessage {
tags := r.URL.Query()["tags"]
if len(tags) == 0 {
return json.RawMessage("{}")
}

var pairs []string
for _, tag := range tags {
parts := strings.SplitN(tag, "=", 2)
if len(parts) == 2 {
pairs = append(pairs, fmt.Sprintf(`%q:%q`, parts[0], parts[1]))
}
}

jsonString := fmt.Sprintf("{%s}", strings.Join(pairs, ","))
return json.RawMessage(jsonString)
}

type provisiionerDaemonAuthResponse struct {
keyID uuid.UUID
orgID uuid.UUID
Expand Down
2 changes: 1 addition & 1 deletion enterprise/coderd/provisionerdaemons_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ func TestGetProvisionerDaemons(t *testing.T) {
require.NoError(t, err)
srv.DRPCConn().Close()

daemons, err := orgAdmin.OrganizationProvisionerDaemons(ctx, org.ID)
daemons, err := orgAdmin.OrganizationProvisionerDaemons(ctx, org.ID, nil)
require.NoError(t, err)
require.Len(t, daemons, 1)

Expand Down
Loading