Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
fix: ensure TagOwner is an empty string and not nil so that unique co…
…nstraint triggers
  • Loading branch information
johnstcn committed Dec 15, 2023
commit 0506994a1a4d38b6f1f38eaa48597c552c35c9c0
2 changes: 1 addition & 1 deletion coderd/coderd.go
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,7 @@ func (api *API) CreateInMemoryProvisionerDaemon(ctx context.Context, name string
Provisioners: []database.ProvisionerType{
database.ProvisionerTypeEcho, database.ProvisionerTypeTerraform,
},
Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
Tags: provisionersdk.MutateTags(uuid.Nil, nil),
LastSeenAt: sql.NullTime{Time: dbtime.Now(), Valid: true},
Version: buildinfo.Version(),
APIVersion: "1.0",
Expand Down
2 changes: 1 addition & 1 deletion enterprise/coderd/provisionerdaemons.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func (p *provisionerDaemonAuth) authorize(r *http.Request, tags map[string]strin
psk := r.Header.Get(codersdk.ProvisionerDaemonPSK)
if subtle.ConstantTimeCompare([]byte(p.psk), []byte(psk)) == 1 {
// If using PSK auth, the daemon is, by definition, scoped to the organization.
tags[provisionersdk.TagScope] = provisionersdk.ScopeOrganization
tags = provisionersdk.MutateTags(uuid.Nil, tags)
return tags, true
}
}
Expand Down
10 changes: 7 additions & 3 deletions provisionersdk/provisionertags.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,27 @@ const (
// If the scope is "user", the "owner" is changed to the user ID.
// This is for user-scoped provisioner daemons, where users should
// own their own operations.
// Otherwise, the "owner" tag is always empty.
// Otherwise, the "owner" tag is always an empty string.
// NOTE: "owner" must NEVER be nil. Otherwise it will end up being
// duplicated in the database, as idx_provisioner_daemons_name_owner_key
// is a partial unique index that includes a JSON field.
func MutateTags(userID uuid.UUID, tags map[string]string) map[string]string {
if tags == nil {
tags = map[string]string{}
}
_, ok := tags[TagScope]
if !ok {
tags[TagScope] = ScopeOrganization
delete(tags, TagOwner)
tags[TagOwner] = ""
}
switch tags[TagScope] {
case ScopeUser:
tags[TagOwner] = userID.String()
case ScopeOrganization:
delete(tags, TagOwner)
tags[TagOwner] = ""
default:
tags[TagScope] = ScopeOrganization
tags[TagOwner] = ""
Comment on lines +17 to +37
Copy link
Member Author

Choose a reason for hiding this comment

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

review: calling this out here -- I had assumed that the index over (name, tags["owner"]) would disallow multiple rows with ("foo", NULL) but this is apparently not the case. However, it does disallow multiple rows with ("foo", "").

I updated to use MutateProvisionerTags wherever possible when inserting a provisioner daemon.

Copy link
Member Author

Choose a reason for hiding this comment

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

@mafredri helpfully pointed out that we can use COALESCE in the index to ensure that an absent value is treated the same as an empty string. 🎉 Adding a migration for this now.

}
return tags
}
6 changes: 6 additions & 0 deletions provisionersdk/provisionertags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func TestMutateTags(t *testing.T) {
tags: nil,
want: map[string]string{
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
provisionersdk.TagOwner: "",
},
},
{
Expand All @@ -35,6 +36,7 @@ func TestMutateTags(t *testing.T) {
tags: map[string]string{},
want: map[string]string{
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
provisionersdk.TagOwner: "",
},
},
{
Expand All @@ -52,6 +54,7 @@ func TestMutateTags(t *testing.T) {
userID: testUserID,
want: map[string]string{
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
provisionersdk.TagOwner: "",
},
},
{
Expand All @@ -63,6 +66,7 @@ func TestMutateTags(t *testing.T) {
userID: uuid.Nil,
want: map[string]string{
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
provisionersdk.TagOwner: "",
},
},
{
Expand All @@ -73,6 +77,7 @@ func TestMutateTags(t *testing.T) {
userID: uuid.Nil,
want: map[string]string{
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
provisionersdk.TagOwner: "",
},
},
{
Expand All @@ -81,6 +86,7 @@ func TestMutateTags(t *testing.T) {
userID: testUserID,
want: map[string]string{
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
provisionersdk.TagOwner: "",
},
},
} {
Expand Down