From 995a04679eb42ccdf4c8b751770ce9b3535f56e0 Mon Sep 17 00:00:00 2001 From: defelmnq Date: Thu, 14 Nov 2024 07:06:46 +0100 Subject: [PATCH 01/16] feat(provisioners) - add endpoint to fetch tags associated to a key using its id fix: change from database.StringMap to codersdk.ProvisionerKeyTags in endpoint response improve annotations for endpoint move logic to enterprise part generate new doc move logic to enterprise part generate doc --- coderd/apidoc/docs.go | 37 +++++++++++++++++++++++ coderd/apidoc/swagger.json | 33 ++++++++++++++++++++ codersdk/provisionerdaemons.go | 18 +++++++++++ docs/reference/api/enterprise.md | 36 ++++++++++++++++++++++ enterprise/coderd/coderd.go | 1 + enterprise/coderd/provisionerkeys.go | 17 +++++++++++ enterprise/coderd/provisionerkeys_test.go | 35 +++++++++++++++++++++ 7 files changed, 177 insertions(+) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 983abb61169c9..47b2093bfd2b2 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -3091,6 +3091,43 @@ const docTemplate = `{ } } }, + "/organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Enterprise" + ], + "summary": "Get provisioner key tags by ID", + "operationId": "get-provisioner-key-tags-by-id", + "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organization", + "in": "path", + "required": true + }, + { + "type": "string", + "format": "uuid", + "description": "Provisioner Key ID", + "name": "provisionerkeyid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.ProvisionerKeyTags" + } + } + } + } + }, "/organizations/{organization}/provisionerkeys/{provisionerkey}": { "delete": { "security": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 67cc92c71331d..2152aba0589ae 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -2715,6 +2715,39 @@ } } }, + "/organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags": { + "get": { + "produces": ["application/json"], + "tags": ["Enterprise"], + "summary": "Get provisioner key tags by ID", + "operationId": "get-provisioner-key-tags-by-id", + "parameters": [ + { + "type": "string", + "description": "Organization ID", + "name": "organization", + "in": "path", + "required": true + }, + { + "type": "string", + "format": "uuid", + "description": "Provisioner Key ID", + "name": "provisionerkeyid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.ProvisionerKeyTags" + } + } + } + } + }, "/organizations/{organization}/provisionerkeys/{provisionerkey}": { "delete": { "security": [ diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go index 7b14afbbb285a..22ec9228f0565 100644 --- a/codersdk/provisionerdaemons.go +++ b/codersdk/provisionerdaemons.go @@ -368,6 +368,24 @@ func (c *Client) ListProvisionerKeys(ctx context.Context, organizationID uuid.UU return resp, json.NewDecoder(res.Body).Decode(&resp) } +// GetProvisionTagsByKey returns the provisioner tags associated with the provisioner key. +func (c *Client) GetProvisionTagsByKey(ctx context.Context, organizationID uuid.UUID, provisionerKey string) (ProvisionerKeyTags, error) { + res, err := c.Request(ctx, http.MethodGet, + fmt.Sprintf("/api/v2/organizations/%s/provisionerkeys/%s/tags", organizationID.String(), provisionerKey), + nil, + ) + if err != nil { + return nil, xerrors.Errorf("make request: %w", err) + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return nil, ReadBodyAsError(res) + } + var resp ProvisionerKeyTags + return resp, json.NewDecoder(res.Body).Decode(&resp) +} + // ListProvisionerKeyDaemons lists all provisioner keys with their associated daemons for an organization. func (c *Client) ListProvisionerKeyDaemons(ctx context.Context, organizationID uuid.UUID) ([]ProvisionerKeyDaemons, error) { res, err := c.Request(ctx, http.MethodGet, diff --git a/docs/reference/api/enterprise.md b/docs/reference/api/enterprise.md index 17f55afcddd81..a0b87d16e6973 100644 --- a/docs/reference/api/enterprise.md +++ b/docs/reference/api/enterprise.md @@ -1750,6 +1750,42 @@ Status Code **200** To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Get provisioner key tags by ID + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags \ + -H 'Accept: application/json' +``` + +`GET /organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags` + +### Parameters + +| Name | In | Type | Required | Description | +| ------------------ | ---- | ------------ | -------- | ------------------ | +| `organization` | path | string | true | Organization ID | +| `provisionerkeyid` | path | string(uuid) | true | Provisioner Key ID | + +### Example responses + +> 200 Response + +```json +{ + "property1": "string", + "property2": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.ProvisionerKeyTags](schemas.md#codersdkprovisionerkeytags) | + ## Delete provisioner key ### Code samples diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index 03d535f6ffb69..b46516265f289 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -352,6 +352,7 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { r.Use( httpmw.ExtractProvisionerKeyParam(options.Database), ) + r.Get("/tags", api.fetchProvisionerKeyTags) r.Delete("/", api.deleteProvisionerKey) }) }) diff --git a/enterprise/coderd/provisionerkeys.go b/enterprise/coderd/provisionerkeys.go index 0d153ffef1791..83e4a5e77865b 100644 --- a/enterprise/coderd/provisionerkeys.go +++ b/enterprise/coderd/provisionerkeys.go @@ -200,6 +200,23 @@ func (api *API) deleteProvisionerKey(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusNoContent, nil) } +// @Summary Get provisioner key tags by ID +// @ID get-provisioner-key-tags-by-id +// @Produce json +// @Tags Enterprise +// @Param organization path string true "Organization ID" +// @Param provisionerkeyid path string true "Provisioner Key ID" format(uuid) +// @Success 200 {object} codersdk.ProvisionerKeyTags +// @Router /organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags [get] +func (api *API) fetchProvisionerKeyTags(rw http.ResponseWriter, r *http.Request) { + var ( + ctx = r.Context() + pk = httpmw.ProvisionerKeyParam(r) + ) + + httpapi.Write(ctx, rw, http.StatusOK, codersdk.ProvisionerKeyTags(pk.Tags)) +} + func convertProvisionerKeys(dbKeys []database.ProvisionerKey) []codersdk.ProvisionerKey { keys := make([]codersdk.ProvisionerKey, 0, len(dbKeys)) for _, dbKey := range dbKeys { diff --git a/enterprise/coderd/provisionerkeys_test.go b/enterprise/coderd/provisionerkeys_test.go index d3615c1ccc931..8cb13fdafa368 100644 --- a/enterprise/coderd/provisionerkeys_test.go +++ b/enterprise/coderd/provisionerkeys_test.go @@ -133,3 +133,38 @@ func TestProvisionerKeys(t *testing.T) { err = orgAdmin.DeleteProvisionerKey(ctx, owner.OrganizationID, codersdk.ProvisionerKeyNamePSK) require.ErrorContains(t, err, "reserved") } + +func TestProvisionerKeyTags(t *testing.T) { + t.Parallel() + t.Run("GetTags", func(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong*10) + t.Cleanup(cancel) + dv := coderdtest.DeploymentValues(t) + client, owner := coderdenttest.New(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + DeploymentValues: dv, + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{ + codersdk.FeatureMultipleOrganizations: 1, + }, + }, + }) + + //nolint:gocritic // Not the purpose of this test + _, err := client.CreateProvisionerKey(ctx, owner.OrganizationID, codersdk.CreateProvisionerKeyRequest{ + Name: "key", + Tags: map[string]string{"key1": "value1", "key2": "value2"}, + }) + require.NoError(t, err) + + tags, err := client.GetProvisionTagsByKeyID(ctx, owner.OrganizationID, "key") + require.NoError(t, err) + require.Equal(t, tags, codersdk.ProvisionerKeyTags{"key1": "value1", "key2": "value2"}) + + err = client.DeleteProvisionerKey(ctx, owner.OrganizationID, "invalid_key") + require.ErrorContains(t, err, "Resource not found") + }) +} From 2ca6c91dd17d9ddf1f5c36442b6b0894b7ab2fa9 Mon Sep 17 00:00:00 2001 From: defelmnq Date: Thu, 14 Nov 2024 08:12:19 +0000 Subject: [PATCH 02/16] rename function --- codersdk/provisionerdaemons.go | 4 ++-- enterprise/coderd/provisionerkeys_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go index 22ec9228f0565..431cce742e973 100644 --- a/codersdk/provisionerdaemons.go +++ b/codersdk/provisionerdaemons.go @@ -368,8 +368,8 @@ func (c *Client) ListProvisionerKeys(ctx context.Context, organizationID uuid.UU return resp, json.NewDecoder(res.Body).Decode(&resp) } -// GetProvisionTagsByKey returns the provisioner tags associated with the provisioner key. -func (c *Client) GetProvisionTagsByKey(ctx context.Context, organizationID uuid.UUID, provisionerKey string) (ProvisionerKeyTags, error) { +// FetchProvisionerTagsTagsByKey returns the provisioner tags associated with the provisioner key. +func (c *Client) FetchProvisionerTagsTagsByKey(ctx context.Context, organizationID uuid.UUID, provisionerKey string) (ProvisionerKeyTags, error) { res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s/provisionerkeys/%s/tags", organizationID.String(), provisionerKey), nil, diff --git a/enterprise/coderd/provisionerkeys_test.go b/enterprise/coderd/provisionerkeys_test.go index 8cb13fdafa368..7d020368b1546 100644 --- a/enterprise/coderd/provisionerkeys_test.go +++ b/enterprise/coderd/provisionerkeys_test.go @@ -160,11 +160,11 @@ func TestProvisionerKeyTags(t *testing.T) { }) require.NoError(t, err) - tags, err := client.GetProvisionTagsByKeyID(ctx, owner.OrganizationID, "key") + tags, err := client.FetchProvisionerTagsTagsByKey(ctx, owner.OrganizationID, "key") require.NoError(t, err) require.Equal(t, tags, codersdk.ProvisionerKeyTags{"key1": "value1", "key2": "value2"}) - err = client.DeleteProvisionerKey(ctx, owner.OrganizationID, "invalid_key") + tags, err = client.FetchProvisionerTagsTagsByKey(ctx, owner.OrganizationID, "invalid_key") require.ErrorContains(t, err, "Resource not found") }) } From c67d3227e930f09193b26ec438560e3cc938cd5a Mon Sep 17 00:00:00 2001 From: defelmnq Date: Thu, 14 Nov 2024 08:16:55 +0000 Subject: [PATCH 03/16] linter --- enterprise/coderd/provisionerkeys.go | 2 +- enterprise/coderd/provisionerkeys_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/enterprise/coderd/provisionerkeys.go b/enterprise/coderd/provisionerkeys.go index 83e4a5e77865b..4a7928025b462 100644 --- a/enterprise/coderd/provisionerkeys.go +++ b/enterprise/coderd/provisionerkeys.go @@ -208,7 +208,7 @@ func (api *API) deleteProvisionerKey(rw http.ResponseWriter, r *http.Request) { // @Param provisionerkeyid path string true "Provisioner Key ID" format(uuid) // @Success 200 {object} codersdk.ProvisionerKeyTags // @Router /organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags [get] -func (api *API) fetchProvisionerKeyTags(rw http.ResponseWriter, r *http.Request) { +func (*API) fetchProvisionerKeyTags(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() pk = httpmw.ProvisionerKeyParam(r) diff --git a/enterprise/coderd/provisionerkeys_test.go b/enterprise/coderd/provisionerkeys_test.go index 7d020368b1546..fa4962c42fd07 100644 --- a/enterprise/coderd/provisionerkeys_test.go +++ b/enterprise/coderd/provisionerkeys_test.go @@ -164,7 +164,7 @@ func TestProvisionerKeyTags(t *testing.T) { require.NoError(t, err) require.Equal(t, tags, codersdk.ProvisionerKeyTags{"key1": "value1", "key2": "value2"}) - tags, err = client.FetchProvisionerTagsTagsByKey(ctx, owner.OrganizationID, "invalid_key") + _, err = client.FetchProvisionerTagsTagsByKey(ctx, owner.OrganizationID, "invalid_key") require.ErrorContains(t, err, "Resource not found") }) } From 911a47ddb7f78a9bb45d9a1e18ab1375c9137d2c Mon Sep 17 00:00:00 2001 From: defelmnq Date: Thu, 14 Nov 2024 08:20:20 +0000 Subject: [PATCH 04/16] linter --- codersdk/provisionerdaemons.go | 4 ++-- enterprise/coderd/provisionerkeys_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go index 431cce742e973..55b34e72953db 100644 --- a/codersdk/provisionerdaemons.go +++ b/codersdk/provisionerdaemons.go @@ -368,8 +368,8 @@ func (c *Client) ListProvisionerKeys(ctx context.Context, organizationID uuid.UU return resp, json.NewDecoder(res.Body).Decode(&resp) } -// FetchProvisionerTagsTagsByKey returns the provisioner tags associated with the provisioner key. -func (c *Client) FetchProvisionerTagsTagsByKey(ctx context.Context, organizationID uuid.UUID, provisionerKey string) (ProvisionerKeyTags, error) { +// FetchProvisionerTagsByKey returns the provisioner tags associated with the provisioner key. +func (c *Client) FetchProvisionerTagsByKey(ctx context.Context, organizationID uuid.UUID, provisionerKey string) (ProvisionerKeyTags, error) { res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s/provisionerkeys/%s/tags", organizationID.String(), provisionerKey), nil, diff --git a/enterprise/coderd/provisionerkeys_test.go b/enterprise/coderd/provisionerkeys_test.go index fa4962c42fd07..8ba2b4ef1f711 100644 --- a/enterprise/coderd/provisionerkeys_test.go +++ b/enterprise/coderd/provisionerkeys_test.go @@ -160,11 +160,11 @@ func TestProvisionerKeyTags(t *testing.T) { }) require.NoError(t, err) - tags, err := client.FetchProvisionerTagsTagsByKey(ctx, owner.OrganizationID, "key") + tags, err := client.FetchProvisionerTagsByKey(ctx, owner.OrganizationID, "key") require.NoError(t, err) require.Equal(t, tags, codersdk.ProvisionerKeyTags{"key1": "value1", "key2": "value2"}) - _, err = client.FetchProvisionerTagsTagsByKey(ctx, owner.OrganizationID, "invalid_key") + _, err = client.FetchProvisionerTagsByKey(ctx, owner.OrganizationID, "invalid_key") require.ErrorContains(t, err, "Resource not found") }) } From 1a019bb254016c1bf79fbb22b392dcf4156e5357 Mon Sep 17 00:00:00 2001 From: defelmnq Date: Thu, 14 Nov 2024 08:35:14 +0000 Subject: [PATCH 05/16] generate doc --- coderd/apidoc/docs.go | 46 ++++++++++--------- coderd/apidoc/swagger.json | 44 +++++++++--------- docs/reference/api/enterprise.md | 67 +++++++++++++++------------- enterprise/coderd/provisionerkeys.go | 5 ++- 4 files changed, 87 insertions(+), 75 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 47b2093bfd2b2..1a11de044a852 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -3091,16 +3091,18 @@ const docTemplate = `{ } } }, - "/organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags": { - "get": { - "produces": [ - "application/json" + "/organizations/{organization}/provisionerkeys/{provisionerkey}": { + "delete": { + "security": [ + { + "CoderSessionToken": [] + } ], "tags": [ "Enterprise" ], - "summary": "Get provisioner key tags by ID", - "operationId": "get-provisioner-key-tags-by-id", + "summary": "Delete provisioner key", + "operationId": "delete-provisioner-key", "parameters": [ { "type": "string", @@ -3111,35 +3113,34 @@ const docTemplate = `{ }, { "type": "string", - "format": "uuid", - "description": "Provisioner Key ID", - "name": "provisionerkeyid", + "description": "Provisioner key name", + "name": "provisionerkey", "in": "path", "required": true } ], "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.ProvisionerKeyTags" - } + "204": { + "description": "No Content" } } } }, - "/organizations/{organization}/provisionerkeys/{provisionerkey}": { - "delete": { + "/organizations/{organization}/provisionerkeys/{provisionerkey}/tags": { + "get": { "security": [ { "CoderSessionToken": [] } ], + "produces": [ + "application/json" + ], "tags": [ "Enterprise" ], - "summary": "Delete provisioner key", - "operationId": "delete-provisioner-key", + "summary": "Get provisioner key tags by ID", + "operationId": "get-provisioner-key-tags-by-id", "parameters": [ { "type": "string", @@ -3150,15 +3151,18 @@ const docTemplate = `{ }, { "type": "string", - "description": "Provisioner key name", + "description": "Provisioner Key", "name": "provisionerkey", "in": "path", "required": true } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.ProvisionerKeyTags" + } } } } diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 2152aba0589ae..348624883c3b9 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -2715,12 +2715,16 @@ } } }, - "/organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags": { - "get": { - "produces": ["application/json"], + "/organizations/{organization}/provisionerkeys/{provisionerkey}": { + "delete": { + "security": [ + { + "CoderSessionToken": [] + } + ], "tags": ["Enterprise"], - "summary": "Get provisioner key tags by ID", - "operationId": "get-provisioner-key-tags-by-id", + "summary": "Delete provisioner key", + "operationId": "delete-provisioner-key", "parameters": [ { "type": "string", @@ -2731,33 +2735,30 @@ }, { "type": "string", - "format": "uuid", - "description": "Provisioner Key ID", - "name": "provisionerkeyid", + "description": "Provisioner key name", + "name": "provisionerkey", "in": "path", "required": true } ], "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.ProvisionerKeyTags" - } + "204": { + "description": "No Content" } } } }, - "/organizations/{organization}/provisionerkeys/{provisionerkey}": { - "delete": { + "/organizations/{organization}/provisionerkeys/{provisionerkey}/tags": { + "get": { "security": [ { "CoderSessionToken": [] } ], + "produces": ["application/json"], "tags": ["Enterprise"], - "summary": "Delete provisioner key", - "operationId": "delete-provisioner-key", + "summary": "Get provisioner key tags by ID", + "operationId": "get-provisioner-key-tags-by-id", "parameters": [ { "type": "string", @@ -2768,15 +2769,18 @@ }, { "type": "string", - "description": "Provisioner key name", + "description": "Provisioner Key", "name": "provisionerkey", "in": "path", "required": true } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.ProvisionerKeyTags" + } } } } diff --git a/docs/reference/api/enterprise.md b/docs/reference/api/enterprise.md index a0b87d16e6973..965955605394e 100644 --- a/docs/reference/api/enterprise.md +++ b/docs/reference/api/enterprise.md @@ -1750,66 +1750,69 @@ Status Code **200** To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Get provisioner key tags by ID +## Delete provisioner key ### Code samples ```shell # Example request using curl -curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags \ - -H 'Accept: application/json' +curl -X DELETE http://coder-server:8080/api/v2/organizations/{organization}/provisionerkeys/{provisionerkey} \ + -H 'Coder-Session-Token: API_KEY' ``` -`GET /organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags` +`DELETE /organizations/{organization}/provisionerkeys/{provisionerkey}` ### Parameters -| Name | In | Type | Required | Description | -| ------------------ | ---- | ------------ | -------- | ------------------ | -| `organization` | path | string | true | Organization ID | -| `provisionerkeyid` | path | string(uuid) | true | Provisioner Key ID | - -### Example responses - -> 200 Response - -```json -{ - "property1": "string", - "property2": "string" -} -``` +| Name | In | Type | Required | Description | +| ---------------- | ---- | ------ | -------- | -------------------- | +| `organization` | path | string | true | Organization ID | +| `provisionerkey` | path | string | true | Provisioner key name | ### Responses -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.ProvisionerKeyTags](schemas.md#codersdkprovisionerkeytags) | +| Status | Meaning | Description | Schema | +| ------ | --------------------------------------------------------------- | ----------- | ------ | +| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | No Content | | -## Delete provisioner key +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Get provisioner key tags by ID ### Code samples ```shell # Example request using curl -curl -X DELETE http://coder-server:8080/api/v2/organizations/{organization}/provisionerkeys/{provisionerkey} \ +curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisionerkeys/{provisionerkey}/tags \ + -H 'Accept: application/json' \ -H 'Coder-Session-Token: API_KEY' ``` -`DELETE /organizations/{organization}/provisionerkeys/{provisionerkey}` +`GET /organizations/{organization}/provisionerkeys/{provisionerkey}/tags` ### Parameters -| Name | In | Type | Required | Description | -| ---------------- | ---- | ------ | -------- | -------------------- | -| `organization` | path | string | true | Organization ID | -| `provisionerkey` | path | string | true | Provisioner key name | +| Name | In | Type | Required | Description | +| ---------------- | ---- | ------ | -------- | --------------- | +| `organization` | path | string | true | Organization ID | +| `provisionerkey` | path | string | true | Provisioner Key | + +### Example responses + +> 200 Response + +```json +{ + "property1": "string", + "property2": "string" +} +``` ### Responses -| Status | Meaning | Description | Schema | -| ------ | --------------------------------------------------------------- | ----------- | ------ | -| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | No Content | | +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.ProvisionerKeyTags](schemas.md#codersdkprovisionerkeytags) | To perform this operation, you must be authenticated. [Learn more](authentication.md). diff --git a/enterprise/coderd/provisionerkeys.go b/enterprise/coderd/provisionerkeys.go index 4a7928025b462..5672e224af89a 100644 --- a/enterprise/coderd/provisionerkeys.go +++ b/enterprise/coderd/provisionerkeys.go @@ -202,12 +202,13 @@ func (api *API) deleteProvisionerKey(rw http.ResponseWriter, r *http.Request) { // @Summary Get provisioner key tags by ID // @ID get-provisioner-key-tags-by-id +// @Security CoderSessionToken // @Produce json // @Tags Enterprise // @Param organization path string true "Organization ID" -// @Param provisionerkeyid path string true "Provisioner Key ID" format(uuid) +// @Param provisionerkey path string true "Provisioner Key" // @Success 200 {object} codersdk.ProvisionerKeyTags -// @Router /organizations/{organization}/provisionerkeys/{provisionerkeyid}/tags [get] +// @Router /organizations/{organization}/provisionerkeys/{provisionerkey}/tags [get] func (*API) fetchProvisionerKeyTags(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() From c629f07f8a175e163086ff2a063028e413bb7685 Mon Sep 17 00:00:00 2001 From: defelmnq Date: Mon, 18 Nov 2024 13:38:28 +0000 Subject: [PATCH 06/16] changes endpoint to return all pk details --- codersdk/provisionerdaemons.go | 16 ++++---- enterprise/coderd/coderd.go | 10 ++++- enterprise/coderd/provisionerkeys.go | 49 +++++++++++++---------- enterprise/coderd/provisionerkeys_test.go | 20 ++++----- 4 files changed, 56 insertions(+), 39 deletions(-) diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go index 55b34e72953db..011a59383a316 100644 --- a/codersdk/provisionerdaemons.go +++ b/codersdk/provisionerdaemons.go @@ -368,21 +368,23 @@ func (c *Client) ListProvisionerKeys(ctx context.Context, organizationID uuid.UU return resp, json.NewDecoder(res.Body).Decode(&resp) } -// FetchProvisionerTagsByKey returns the provisioner tags associated with the provisioner key. -func (c *Client) FetchProvisionerTagsByKey(ctx context.Context, organizationID uuid.UUID, provisionerKey string) (ProvisionerKeyTags, error) { +// GetProvisionerKey returns the provisioner key. +func (c *Client) GetProvisionerKey(ctx context.Context, pk string) (ProvisionerKey, error) { res, err := c.Request(ctx, http.MethodGet, - fmt.Sprintf("/api/v2/organizations/%s/provisionerkeys/%s/tags", organizationID.String(), provisionerKey), - nil, + fmt.Sprintf("/api/v2/provisionerkeys/%s", pk), nil, + func(req *http.Request) { + req.Header.Add(ProvisionerDaemonKey, pk) + }, ) if err != nil { - return nil, xerrors.Errorf("make request: %w", err) + return ProvisionerKey{}, xerrors.Errorf("make request: %w", err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { - return nil, ReadBodyAsError(res) + return ProvisionerKey{}, ReadBodyAsError(res) } - var resp ProvisionerKeyTags + var resp ProvisionerKey return resp, json.NewDecoder(res.Body).Decode(&resp) } diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index b46516265f289..1b242f2b05137 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -339,6 +339,15 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { r.Get("/", api.groupByOrganization) }) }) + r.Route("/provisionerkeys", func(r chi.Router) { + r.Use( + httpmw.ExtractProvisionerDaemonAuthenticated(httpmw.ExtractProvisionerAuthConfig{ + DB: api.Database, + Optional: false, + }), + ) + r.Get("/{provisionerkey}", api.getProvisionerKey) + }) r.Route("/organizations/{organization}/provisionerkeys", func(r chi.Router) { r.Use( apiKeyMiddleware, @@ -352,7 +361,6 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { r.Use( httpmw.ExtractProvisionerKeyParam(options.Database), ) - r.Get("/tags", api.fetchProvisionerKeyTags) r.Delete("/", api.deleteProvisionerKey) }) }) diff --git a/enterprise/coderd/provisionerkeys.go b/enterprise/coderd/provisionerkeys.go index 5672e224af89a..9f3e7dfac74cf 100644 --- a/enterprise/coderd/provisionerkeys.go +++ b/enterprise/coderd/provisionerkeys.go @@ -200,35 +200,42 @@ func (api *API) deleteProvisionerKey(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusNoContent, nil) } -// @Summary Get provisioner key tags by ID -// @ID get-provisioner-key-tags-by-id -// @Security CoderSessionToken +// @Summary Get provisioner key details +// @ID get-provisioner-key +// @Security CoderProvisionerDaemonKey // @Produce json // @Tags Enterprise -// @Param organization path string true "Organization ID" // @Param provisionerkey path string true "Provisioner Key" -// @Success 200 {object} codersdk.ProvisionerKeyTags -// @Router /organizations/{organization}/provisionerkeys/{provisionerkey}/tags [get] -func (*API) fetchProvisionerKeyTags(rw http.ResponseWriter, r *http.Request) { - var ( - ctx = r.Context() - pk = httpmw.ProvisionerKeyParam(r) - ) - - httpapi.Write(ctx, rw, http.StatusOK, codersdk.ProvisionerKeyTags(pk.Tags)) +// @Success 200 {object} codersdk.ProvisionerKey +// @Router provisionerkeys/{provisionerkey} [get] +func (*API) getProvisionerKey(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + pk, ok := httpmw.ProvisionerKeyAuthOptional(r) + // extra check but this one should never happen as it is covered by the auth middleware + if !ok { + httpapi.Forbidden(rw) + return + } + + httpapi.Write(ctx, rw, http.StatusOK, convertProvisionerKey(pk)) +} + +func convertProvisionerKey(dbKey database.ProvisionerKey) codersdk.ProvisionerKey { + return codersdk.ProvisionerKey{ + ID: dbKey.ID, + CreatedAt: dbKey.CreatedAt, + OrganizationID: dbKey.OrganizationID, + Name: dbKey.Name, + Tags: codersdk.ProvisionerKeyTags(dbKey.Tags), + // HashedSecret - never include the access token in the API response + } } func convertProvisionerKeys(dbKeys []database.ProvisionerKey) []codersdk.ProvisionerKey { keys := make([]codersdk.ProvisionerKey, 0, len(dbKeys)) for _, dbKey := range dbKeys { - keys = append(keys, codersdk.ProvisionerKey{ - ID: dbKey.ID, - CreatedAt: dbKey.CreatedAt, - OrganizationID: dbKey.OrganizationID, - Name: dbKey.Name, - Tags: codersdk.ProvisionerKeyTags(dbKey.Tags), - // HashedSecret - never include the access token in the API response - }) + keys = append(keys, convertProvisionerKey(dbKey)) } slices.SortFunc(keys, func(key1, key2 codersdk.ProvisionerKey) int { diff --git a/enterprise/coderd/provisionerkeys_test.go b/enterprise/coderd/provisionerkeys_test.go index 8ba2b4ef1f711..62852819fadcd 100644 --- a/enterprise/coderd/provisionerkeys_test.go +++ b/enterprise/coderd/provisionerkeys_test.go @@ -134,12 +134,12 @@ func TestProvisionerKeys(t *testing.T) { require.ErrorContains(t, err, "reserved") } -func TestProvisionerKeyTags(t *testing.T) { +func TestProvisionerKey(t *testing.T) { t.Parallel() - t.Run("GetTags", func(t *testing.T) { + t.Run("GetKey", func(t *testing.T) { t.Parallel() - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong*10) + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) t.Cleanup(cancel) dv := coderdtest.DeploymentValues(t) client, owner := coderdenttest.New(t, &coderdenttest.Options{ @@ -153,18 +153,18 @@ func TestProvisionerKeyTags(t *testing.T) { }, }) - //nolint:gocritic // Not the purpose of this test - _, err := client.CreateProvisionerKey(ctx, owner.OrganizationID, codersdk.CreateProvisionerKeyRequest{ - Name: "key", + key, err := client.CreateProvisionerKey(ctx, owner.OrganizationID, codersdk.CreateProvisionerKeyRequest{ + Name: "my-test-key", Tags: map[string]string{"key1": "value1", "key2": "value2"}, }) require.NoError(t, err) - tags, err := client.FetchProvisionerTagsByKey(ctx, owner.OrganizationID, "key") + _, err = client.GetProvisionerKey(ctx, key.Key) require.NoError(t, err) - require.Equal(t, tags, codersdk.ProvisionerKeyTags{"key1": "value1", "key2": "value2"}) + // require.Equal(t, tags, codersdk.ProvisionerKeyTags{"key1": "value1", "key2": "value2"}) - _, err = client.FetchProvisionerTagsByKey(ctx, owner.OrganizationID, "invalid_key") - require.ErrorContains(t, err, "Resource not found") + erroneousPK, err := client.GetProvisionerKey(ctx, "abcdefghijklmnopqrstuvwxyz01234567890123456") + require.Empty(t, erroneousPK) + require.Error(t, err) }) } From 54437f2e4ebc7ae139ef583e8e4c3159b22e3da4 Mon Sep 17 00:00:00 2001 From: defelmnq Date: Mon, 18 Nov 2024 14:39:52 +0000 Subject: [PATCH 07/16] generate doc --- coderd/apidoc/docs.go | 75 ++++++++++---------- coderd/apidoc/swagger.json | 67 ++++++++---------- codersdk/provisionerdaemons.go | 2 +- docs/reference/api/enterprise.md | 83 ++++++++++++----------- enterprise/coderd/coderd.go | 2 +- enterprise/coderd/provisionerkeys.go | 10 +-- enterprise/coderd/provisionerkeys_test.go | 10 +-- 7 files changed, 121 insertions(+), 128 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 1a11de044a852..6410a8f9f7e4f 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -3126,47 +3126,6 @@ const docTemplate = `{ } } }, - "/organizations/{organization}/provisionerkeys/{provisionerkey}/tags": { - "get": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "Enterprise" - ], - "summary": "Get provisioner key tags by ID", - "operationId": "get-provisioner-key-tags-by-id", - "parameters": [ - { - "type": "string", - "description": "Organization ID", - "name": "organization", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Provisioner Key", - "name": "provisionerkey", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.ProvisionerKeyTags" - } - } - } - } - }, "/organizations/{organization}/settings/idpsync/groups": { "get": { "security": [ @@ -3635,6 +3594,40 @@ const docTemplate = `{ } } }, + "/provisionerkeys/{provisionerkey}": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Enterprise" + ], + "summary": "Fetch provisioner key details", + "operationId": "fetch-provisioner-key-details", + "parameters": [ + { + "type": "string", + "description": "Provisioner Key", + "name": "provisionerkey", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.ProvisionerKey" + } + } + } + } + }, "/regions": { "get": { "security": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 348624883c3b9..6ae60ee74178d 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -2748,43 +2748,6 @@ } } }, - "/organizations/{organization}/provisionerkeys/{provisionerkey}/tags": { - "get": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "produces": ["application/json"], - "tags": ["Enterprise"], - "summary": "Get provisioner key tags by ID", - "operationId": "get-provisioner-key-tags-by-id", - "parameters": [ - { - "type": "string", - "description": "Organization ID", - "name": "organization", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Provisioner Key", - "name": "provisionerkey", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.ProvisionerKeyTags" - } - } - } - } - }, "/organizations/{organization}/settings/idpsync/groups": { "get": { "security": [ @@ -3201,6 +3164,36 @@ } } }, + "/provisionerkeys/{provisionerkey}": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Enterprise"], + "summary": "Fetch provisioner key details", + "operationId": "fetch-provisioner-key-details", + "parameters": [ + { + "type": "string", + "description": "Provisioner Key", + "name": "provisionerkey", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.ProvisionerKey" + } + } + } + } + }, "/regions": { "get": { "security": [ diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go index 011a59383a316..12b5ac97565a4 100644 --- a/codersdk/provisionerdaemons.go +++ b/codersdk/provisionerdaemons.go @@ -377,7 +377,7 @@ func (c *Client) GetProvisionerKey(ctx context.Context, pk string) (ProvisionerK }, ) if err != nil { - return ProvisionerKey{}, xerrors.Errorf("make request: %w", err) + return ProvisionerKey{}, xerrors.Errorf("request to fetch provisioner key failed: %w", err) } defer res.Body.Close() diff --git a/docs/reference/api/enterprise.md b/docs/reference/api/enterprise.md index 965955605394e..4f669aca05550 100644 --- a/docs/reference/api/enterprise.md +++ b/docs/reference/api/enterprise.md @@ -1777,45 +1777,6 @@ curl -X DELETE http://coder-server:8080/api/v2/organizations/{organization}/prov To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Get provisioner key tags by ID - -### Code samples - -```shell -# Example request using curl -curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisionerkeys/{provisionerkey}/tags \ - -H 'Accept: application/json' \ - -H 'Coder-Session-Token: API_KEY' -``` - -`GET /organizations/{organization}/provisionerkeys/{provisionerkey}/tags` - -### Parameters - -| Name | In | Type | Required | Description | -| ---------------- | ---- | ------ | -------- | --------------- | -| `organization` | path | string | true | Organization ID | -| `provisionerkey` | path | string | true | Provisioner Key | - -### Example responses - -> 200 Response - -```json -{ - "property1": "string", - "property2": "string" -} -``` - -### Responses - -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.ProvisionerKeyTags](schemas.md#codersdkprovisionerkeytags) | - -To perform this operation, you must be authenticated. [Learn more](authentication.md). - ## Get group IdP Sync settings by organization ### Code samples @@ -2026,6 +1987,50 @@ curl -X PATCH http://coder-server:8080/api/v2/organizations/{organization}/setti To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Fetch provisioner key details + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/provisionerkeys/{provisionerkey} \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /provisionerkeys/{provisionerkey}` + +### Parameters + +| Name | In | Type | Required | Description | +| ---------------- | ---- | ------ | -------- | --------------- | +| `provisionerkey` | path | string | true | Provisioner Key | + +### Example responses + +> 200 Response + +```json +{ + "created_at": "2019-08-24T14:15:22Z", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "name": "string", + "organization": "452c1a86-a0af-475b-b03f-724878b0f387", + "tags": { + "property1": "string", + "property2": "string" + } +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------------------ | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.ProvisionerKey](schemas.md#codersdkprovisionerkey) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## Get active replicas ### Code samples diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index 1b242f2b05137..dd18e6fd8c293 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -346,7 +346,7 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { Optional: false, }), ) - r.Get("/{provisionerkey}", api.getProvisionerKey) + r.Get("/{provisionerkey}", api.fetchProvisionerKey) }) r.Route("/organizations/{organization}/provisionerkeys", func(r chi.Router) { r.Use( diff --git a/enterprise/coderd/provisionerkeys.go b/enterprise/coderd/provisionerkeys.go index 9f3e7dfac74cf..3ddefdc95ce3e 100644 --- a/enterprise/coderd/provisionerkeys.go +++ b/enterprise/coderd/provisionerkeys.go @@ -200,15 +200,15 @@ func (api *API) deleteProvisionerKey(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusNoContent, nil) } -// @Summary Get provisioner key details -// @ID get-provisioner-key -// @Security CoderProvisionerDaemonKey +// @Summary Fetch provisioner key details +// @ID fetch-provisioner-key-details +// @Security CoderSessionToken // @Produce json // @Tags Enterprise // @Param provisionerkey path string true "Provisioner Key" // @Success 200 {object} codersdk.ProvisionerKey -// @Router provisionerkeys/{provisionerkey} [get] -func (*API) getProvisionerKey(rw http.ResponseWriter, r *http.Request) { +// @Router /provisionerkeys/{provisionerkey} [get] +func (*API) fetchProvisionerKey(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() pk, ok := httpmw.ProvisionerKeyAuthOptional(r) diff --git a/enterprise/coderd/provisionerkeys_test.go b/enterprise/coderd/provisionerkeys_test.go index 62852819fadcd..471ddd2c61a0d 100644 --- a/enterprise/coderd/provisionerkeys_test.go +++ b/enterprise/coderd/provisionerkeys_test.go @@ -139,8 +139,8 @@ func TestProvisionerKey(t *testing.T) { t.Run("GetKey", func(t *testing.T) { t.Parallel() - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) - t.Cleanup(cancel) + ctx := testutil.Context(t, testutil.WaitShort) + dv := coderdtest.DeploymentValues(t) client, owner := coderdenttest.New(t, &coderdenttest.Options{ Options: &coderdtest.Options{ @@ -153,15 +153,17 @@ func TestProvisionerKey(t *testing.T) { }, }) + // nolint:gocritic key, err := client.CreateProvisionerKey(ctx, owner.OrganizationID, codersdk.CreateProvisionerKeyRequest{ Name: "my-test-key", Tags: map[string]string{"key1": "value1", "key2": "value2"}, }) require.NoError(t, err) - _, err = client.GetProvisionerKey(ctx, key.Key) + fetchedKey, err := client.GetProvisionerKey(ctx, key.Key) require.NoError(t, err) - // require.Equal(t, tags, codersdk.ProvisionerKeyTags{"key1": "value1", "key2": "value2"}) + require.Equal(t, fetchedKey.Name, "my-test-key") + require.Equal(t, fetchedKey.Tags, codersdk.ProvisionerKeyTags{"key1": "value1", "key2": "value2"}) erroneousPK, err := client.GetProvisionerKey(ctx, "abcdefghijklmnopqrstuvwxyz01234567890123456") require.Empty(t, erroneousPK) From 8eeffb1351f79632b5e15147073965d71df666aa Mon Sep 17 00:00:00 2001 From: defelmnq Date: Mon, 18 Nov 2024 15:47:48 +0000 Subject: [PATCH 08/16] work on tests --- enterprise/coderd/provisionerkeys_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/enterprise/coderd/provisionerkeys_test.go b/enterprise/coderd/provisionerkeys_test.go index 471ddd2c61a0d..32321425129e5 100644 --- a/enterprise/coderd/provisionerkeys_test.go +++ b/enterprise/coderd/provisionerkeys_test.go @@ -148,7 +148,8 @@ func TestProvisionerKey(t *testing.T) { }, LicenseOptions: &coderdenttest.LicenseOptions{ Features: license.Features{ - codersdk.FeatureMultipleOrganizations: 1, + codersdk.FeatureMultipleOrganizations: 1, + codersdk.FeatureExternalProvisionerDaemons: 1, }, }, }) From 3aa81edb883588c9f0d889dbd8a5826491f4ba77 Mon Sep 17 00:00:00 2001 From: defelmnq Date: Tue, 19 Nov 2024 09:29:56 +0000 Subject: [PATCH 09/16] work on improving tag logs for provisioner start --- enterprise/cli/provisionerdaemonstart.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/enterprise/cli/provisionerdaemonstart.go b/enterprise/cli/provisionerdaemonstart.go index be7a11b6e363b..ba8f0914d0a01 100644 --- a/enterprise/cli/provisionerdaemonstart.go +++ b/enterprise/cli/provisionerdaemonstart.go @@ -104,6 +104,22 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { return err } + displayedTags := make(map[string]string) + for key, val := range tags { + displayedTags[key] = val + } + + if provisionerKey != "" { + pkDetails, err := client.GetProvisionerKey(ctx, provisionerKey) + if err != nil { + return xerrors.New("unable to get provisioner key details") + } + + for k, v := range pkDetails.Tags { + displayedTags[k] = v + } + } + if name == "" { name = cliutil.Hostname() } @@ -202,7 +218,7 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { defer closeFunc() } - logger.Info(ctx, "starting provisioner daemon", slog.F("tags", tags), slog.F("name", name)) + logger.Info(ctx, "starting provisioner daemon", slog.F("tags", displayedTags), slog.F("name", name)) connector := provisionerd.LocalProvisioners{ string(database.ProvisionerTypeTerraform): proto.NewDRPCProvisionerClient(terraformClient), From 0cff661caf991c2c2ef83c6fdfd47bd8ff78ae0c Mon Sep 17 00:00:00 2001 From: defelmnq Date: Thu, 21 Nov 2024 15:42:48 +0000 Subject: [PATCH 10/16] Work on tags for provisioner daemon --- enterprise/cli/provisionerdaemonstart.go | 2 +- enterprise/cli/provisionerdaemonstart_test.go | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/enterprise/cli/provisionerdaemonstart.go b/enterprise/cli/provisionerdaemonstart.go index ba8f0914d0a01..491dd4284660c 100644 --- a/enterprise/cli/provisionerdaemonstart.go +++ b/enterprise/cli/provisionerdaemonstart.go @@ -147,7 +147,7 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { defer closeLogger() } - if len(tags) == 0 { + if len(displayedTags) == 0 { logger.Info(ctx, "note: untagged provisioners can only pick up jobs from untagged templates") } diff --git a/enterprise/cli/provisionerdaemonstart_test.go b/enterprise/cli/provisionerdaemonstart_test.go index 763ac49b92996..3dba46b028492 100644 --- a/enterprise/cli/provisionerdaemonstart_test.go +++ b/enterprise/cli/provisionerdaemonstart_test.go @@ -294,6 +294,51 @@ func TestProvisionerDaemon_ProvisionerKey(t *testing.T) { require.Equal(t, proto.CurrentVersion.String(), daemons[0].APIVersion) }) + t.Run("OKWithTags", func(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + client, user := coderdenttest.New(t, &coderdenttest.Options{ + ProvisionerDaemonPSK: "provisionersftw", + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{ + codersdk.FeatureExternalProvisionerDaemons: 1, + codersdk.FeatureMultipleOrganizations: 1, + }, + }, + }) + // nolint:gocritic // test + res, err := client.CreateProvisionerKey(ctx, user.OrganizationID, codersdk.CreateProvisionerKeyRequest{ + Name: "dont-TEST-me", + Tags: map[string]string{ + "tag1": "value1", + "tag2": "value2", + }, + }) + require.NoError(t, err) + inv, conf := newCLI(t, "provisionerd", "start", "--key", res.Key, "--name=matt-daemon") + err = conf.URL().Write(client.URL.String()) + require.NoError(t, err) + pty := ptytest.New(t).Attach(inv) + clitest.Start(t, inv) + pty.ExpectNoMatchBefore(ctx, "check entitlement", "starting provisioner daemon") + pty.ExpectMatchContext(ctx, `tags={"tag1":"value1","tag2":"value2"}`) + + var daemons []codersdk.ProvisionerDaemon + require.Eventually(t, func() bool { + daemons, err = client.OrganizationProvisionerDaemons(ctx, user.OrganizationID, nil) + if err != nil { + return false + } + return len(daemons) == 1 + }, testutil.WaitShort, testutil.IntervalSlow) + require.Equal(t, "matt-daemon", daemons[0].Name) + require.Equal(t, provisionersdk.ScopeOrganization, daemons[0].Tags[provisionersdk.TagScope]) + require.Equal(t, buildinfo.Version(), daemons[0].Version) + require.Equal(t, proto.CurrentVersion.String(), daemons[0].APIVersion) + }) + t.Run("NoPSK", func(t *testing.T) { t.Parallel() From d4472a26dabc1a2ab08dfb0e58c4d8c0e5bfd894 Mon Sep 17 00:00:00 2001 From: defelmnq Date: Thu, 21 Nov 2024 22:54:08 +0000 Subject: [PATCH 11/16] details golint --- enterprise/cli/provisionerdaemonstart_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise/cli/provisionerdaemonstart_test.go b/enterprise/cli/provisionerdaemonstart_test.go index 3dba46b028492..35cc3b5d2835a 100644 --- a/enterprise/cli/provisionerdaemonstart_test.go +++ b/enterprise/cli/provisionerdaemonstart_test.go @@ -308,7 +308,7 @@ func TestProvisionerDaemon_ProvisionerKey(t *testing.T) { }, }, }) - // nolint:gocritic // test + //nolint:gocritic // ignore This client is operating as the owner user, which has unrestricted permissions res, err := client.CreateProvisionerKey(ctx, user.OrganizationID, codersdk.CreateProvisionerKeyRequest{ Name: "dont-TEST-me", Tags: map[string]string{ From ee0fef67b8cc24f8bf87769576140f1b38cef75d Mon Sep 17 00:00:00 2001 From: defelmnq Date: Mon, 25 Nov 2024 05:01:50 +0000 Subject: [PATCH 12/16] change tags variable --- enterprise/cli/provisionerdaemonstart.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/enterprise/cli/provisionerdaemonstart.go b/enterprise/cli/provisionerdaemonstart.go index 491dd4284660c..98a87e07c1d71 100644 --- a/enterprise/cli/provisionerdaemonstart.go +++ b/enterprise/cli/provisionerdaemonstart.go @@ -104,19 +104,14 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { return err } - displayedTags := make(map[string]string) - for key, val := range tags { - displayedTags[key] = val - } - if provisionerKey != "" { pkDetails, err := client.GetProvisionerKey(ctx, provisionerKey) if err != nil { - return xerrors.New("unable to get provisioner key details") + return xerrors.New(fmt.Sprintf("unable to get provisioner key details: %w", err)) } for k, v := range pkDetails.Tags { - displayedTags[k] = v + tags[k] = v } } @@ -147,7 +142,7 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { defer closeLogger() } - if len(displayedTags) == 0 { + if len(tags) == 0 { logger.Info(ctx, "note: untagged provisioners can only pick up jobs from untagged templates") } @@ -218,7 +213,7 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { defer closeFunc() } - logger.Info(ctx, "starting provisioner daemon", slog.F("tags", displayedTags), slog.F("name", name)) + logger.Info(ctx, "starting provisioner daemon", slog.F("tags", tags), slog.F("name", name)) connector := provisionerd.LocalProvisioners{ string(database.ProvisionerTypeTerraform): proto.NewDRPCProvisionerClient(terraformClient), From 703668b0e68142f597d9a17d831d16cffc738ab8 Mon Sep 17 00:00:00 2001 From: defelmnq Date: Mon, 25 Nov 2024 05:27:13 +0000 Subject: [PATCH 13/16] change tags variable --- enterprise/cli/provisionerdaemonstart.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise/cli/provisionerdaemonstart.go b/enterprise/cli/provisionerdaemonstart.go index 98a87e07c1d71..168d8715c0bdc 100644 --- a/enterprise/cli/provisionerdaemonstart.go +++ b/enterprise/cli/provisionerdaemonstart.go @@ -107,7 +107,7 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { if provisionerKey != "" { pkDetails, err := client.GetProvisionerKey(ctx, provisionerKey) if err != nil { - return xerrors.New(fmt.Sprintf("unable to get provisioner key details: %w", err)) + return xerrors.Errorf("unable to get provisioner key details: %w", err) } for k, v := range pkDetails.Tags { From b5ff46568772651516d24fc2e465d58c42f2f15b Mon Sep 17 00:00:00 2001 From: defelmnq Date: Mon, 25 Nov 2024 06:41:22 +0000 Subject: [PATCH 14/16] pre-allocate map --- enterprise/cli/provisionerdaemonstart.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/enterprise/cli/provisionerdaemonstart.go b/enterprise/cli/provisionerdaemonstart.go index 168d8715c0bdc..9c91f2c301f46 100644 --- a/enterprise/cli/provisionerdaemonstart.go +++ b/enterprise/cli/provisionerdaemonstart.go @@ -104,14 +104,20 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { return err } + displayedTags := make(map[string]string, len(tags)) + for key, val := range tags { + displayedTags[key] = val + } + if provisionerKey != "" { pkDetails, err := client.GetProvisionerKey(ctx, provisionerKey) if err != nil { - return xerrors.Errorf("unable to get provisioner key details: %w", err) + return xerrors.New("unable to get provisioner key details") } + displayedTags = make(map[string]string, len(pkDetails.Tags)) for k, v := range pkDetails.Tags { - tags[k] = v + displayedTags[k] = v } } @@ -142,7 +148,7 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { defer closeLogger() } - if len(tags) == 0 { + if len(displayedTags) == 0 { logger.Info(ctx, "note: untagged provisioners can only pick up jobs from untagged templates") } @@ -213,7 +219,7 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { defer closeFunc() } - logger.Info(ctx, "starting provisioner daemon", slog.F("tags", tags), slog.F("name", name)) + logger.Info(ctx, "starting provisioner daemon", slog.F("tags", displayedTags), slog.F("name", name)) connector := provisionerd.LocalProvisioners{ string(database.ProvisionerTypeTerraform): proto.NewDRPCProvisionerClient(terraformClient), From 7ea193f567ea8df36efe9ca9ce0b3456cdfd0bbb Mon Sep 17 00:00:00 2001 From: defelmnq Date: Mon, 25 Nov 2024 06:45:48 +0000 Subject: [PATCH 15/16] add missing test for failing case --- enterprise/cli/provisionerdaemonstart_test.go | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/enterprise/cli/provisionerdaemonstart_test.go b/enterprise/cli/provisionerdaemonstart_test.go index 35cc3b5d2835a..4829ccc38f23d 100644 --- a/enterprise/cli/provisionerdaemonstart_test.go +++ b/enterprise/cli/provisionerdaemonstart_test.go @@ -339,6 +339,28 @@ func TestProvisionerDaemon_ProvisionerKey(t *testing.T) { require.Equal(t, proto.CurrentVersion.String(), daemons[0].APIVersion) }) + t.Run("NoProvisionerKeyFound", func(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + client, _ := coderdenttest.New(t, &coderdenttest.Options{ + ProvisionerDaemonPSK: "provisionersftw", + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{ + codersdk.FeatureExternalProvisionerDaemons: 1, + codersdk.FeatureMultipleOrganizations: 1, + }, + }, + }) + + inv, conf := newCLI(t, "provisionerd", "start", "--key", "ThisKeyDoesNotExist", "--name=matt-daemon") + err := conf.URL().Write(client.URL.String()) + require.NoError(t, err) + err = inv.WithContext(ctx).Run() + require.ErrorContains(t, err, "unable to get provisioner key details") + }) + t.Run("NoPSK", func(t *testing.T) { t.Parallel() From 08ab03292163f9aa9838e91dda7ccc7cd1d8140b Mon Sep 17 00:00:00 2001 From: defelmnq Date: Mon, 25 Nov 2024 08:59:36 +0000 Subject: [PATCH 16/16] improve map allocation --- enterprise/cli/provisionerdaemonstart.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/enterprise/cli/provisionerdaemonstart.go b/enterprise/cli/provisionerdaemonstart.go index 9c91f2c301f46..3c3f1f0712800 100644 --- a/enterprise/cli/provisionerdaemonstart.go +++ b/enterprise/cli/provisionerdaemonstart.go @@ -105,20 +105,19 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { } displayedTags := make(map[string]string, len(tags)) - for key, val := range tags { - displayedTags[key] = val - } - if provisionerKey != "" { pkDetails, err := client.GetProvisionerKey(ctx, provisionerKey) if err != nil { return xerrors.New("unable to get provisioner key details") } - displayedTags = make(map[string]string, len(pkDetails.Tags)) for k, v := range pkDetails.Tags { displayedTags[k] = v } + } else { + for key, val := range tags { + displayedTags[key] = val + } } if name == "" {