Skip to content

Commit cb9d40f

Browse files
Emyrkdannykopping
andauthored
feat: implement runtime configuration package with multi-org support (#14624)
runtime configuration package --------- Signed-off-by: Danny Kopping <danny@coder.com> Co-authored-by: Danny Kopping <danny@coder.com>
1 parent 9da6467 commit cb9d40f

File tree

18 files changed

+546
-0
lines changed

18 files changed

+546
-0
lines changed

cli/server.go

+3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import (
5656
"cdr.dev/slog"
5757
"cdr.dev/slog/sloggers/sloghuman"
5858
"github.com/coder/coder/v2/coderd/entitlements"
59+
"github.com/coder/coder/v2/coderd/runtimeconfig"
5960
"github.com/coder/pretty"
6061
"github.com/coder/quartz"
6162
"github.com/coder/retry"
@@ -820,6 +821,8 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
820821
return err
821822
}
822823

824+
options.RuntimeConfig = runtimeconfig.NewManager()
825+
823826
// This should be output before the logs start streaming.
824827
cliui.Infof(inv.Stdout, "\n==> Logs will stream in below (press ctrl+c to gracefully exit):")
825828

coderd/coderd.go

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"cdr.dev/slog"
4040
"github.com/coder/coder/v2/coderd/entitlements"
4141
"github.com/coder/coder/v2/coderd/idpsync"
42+
"github.com/coder/coder/v2/coderd/runtimeconfig"
4243
"github.com/coder/quartz"
4344
"github.com/coder/serpent"
4445

@@ -135,6 +136,7 @@ type Options struct {
135136
Logger slog.Logger
136137
Database database.Store
137138
Pubsub pubsub.Pubsub
139+
RuntimeConfig *runtimeconfig.Manager
138140

139141
// CacheDir is used for caching files served by the API.
140142
CacheDir string

coderd/coderdtest/coderdtest.go

+3
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import (
6767
"github.com/coder/coder/v2/coderd/notifications"
6868
"github.com/coder/coder/v2/coderd/rbac"
6969
"github.com/coder/coder/v2/coderd/rbac/policy"
70+
"github.com/coder/coder/v2/coderd/runtimeconfig"
7071
"github.com/coder/coder/v2/coderd/schedule"
7172
"github.com/coder/coder/v2/coderd/telemetry"
7273
"github.com/coder/coder/v2/coderd/unhanger"
@@ -254,6 +255,7 @@ func NewOptions(t testing.TB, options *Options) (func(http.Handler), context.Can
254255
var acs dbauthz.AccessControlStore = dbauthz.AGPLTemplateAccessControlStore{}
255256
accessControlStore.Store(&acs)
256257

258+
runtimeManager := runtimeconfig.NewManager()
257259
options.Database = dbauthz.New(options.Database, options.Authorizer, *options.Logger, accessControlStore)
258260

259261
// Some routes expect a deployment ID, so just make sure one exists.
@@ -482,6 +484,7 @@ func NewOptions(t testing.TB, options *Options) (func(http.Handler), context.Can
482484
AppHostnameRegex: appHostnameRegex,
483485
Logger: *options.Logger,
484486
CacheDir: t.TempDir(),
487+
RuntimeConfig: runtimeManager,
485488
Database: options.Database,
486489
Pubsub: options.Pubsub,
487490
ExternalAuthConfigs: options.ExternalAuthConfigs,

coderd/database/dbauthz/dbauthz.go

+21
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,13 @@ func (q *querier) DeleteReplicasUpdatedBefore(ctx context.Context, updatedAt tim
11831183
return q.db.DeleteReplicasUpdatedBefore(ctx, updatedAt)
11841184
}
11851185

1186+
func (q *querier) DeleteRuntimeConfig(ctx context.Context, key string) error {
1187+
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceSystem); err != nil {
1188+
return err
1189+
}
1190+
return q.db.DeleteRuntimeConfig(ctx, key)
1191+
}
1192+
11861193
func (q *querier) DeleteTailnetAgent(ctx context.Context, arg database.DeleteTailnetAgentParams) (database.DeleteTailnetAgentRow, error) {
11871194
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceTailnetCoordinator); err != nil {
11881195
return database.DeleteTailnetAgentRow{}, err
@@ -1856,6 +1863,13 @@ func (q *querier) GetReplicasUpdatedAfter(ctx context.Context, updatedAt time.Ti
18561863
return q.db.GetReplicasUpdatedAfter(ctx, updatedAt)
18571864
}
18581865

1866+
func (q *querier) GetRuntimeConfig(ctx context.Context, key string) (string, error) {
1867+
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
1868+
return "", err
1869+
}
1870+
return q.db.GetRuntimeConfig(ctx, key)
1871+
}
1872+
18591873
func (q *querier) GetTailnetAgents(ctx context.Context, id uuid.UUID) ([]database.TailnetAgent, error) {
18601874
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceTailnetCoordinator); err != nil {
18611875
return nil, err
@@ -3906,6 +3920,13 @@ func (q *querier) UpsertProvisionerDaemon(ctx context.Context, arg database.Upse
39063920
return q.db.UpsertProvisionerDaemon(ctx, arg)
39073921
}
39083922

3923+
func (q *querier) UpsertRuntimeConfig(ctx context.Context, arg database.UpsertRuntimeConfigParams) error {
3924+
if err := q.authorizeContext(ctx, policy.ActionCreate, rbac.ResourceSystem); err != nil {
3925+
return err
3926+
}
3927+
return q.db.UpsertRuntimeConfig(ctx, arg)
3928+
}
3929+
39093930
func (q *querier) UpsertTailnetAgent(ctx context.Context, arg database.UpsertTailnetAgentParams) (database.TailnetAgent, error) {
39103931
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceTailnetCoordinator); err != nil {
39113932
return database.TailnetAgent{}, err

coderd/database/dbauthz/dbauthz_test.go

+16
Original file line numberDiff line numberDiff line change
@@ -2696,6 +2696,22 @@ func (s *MethodTestSuite) TestSystemFunctions() {
26962696
AgentID: uuid.New(),
26972697
}).Asserts(tpl, policy.ActionCreate)
26982698
}))
2699+
s.Run("DeleteRuntimeConfig", s.Subtest(func(db database.Store, check *expects) {
2700+
check.Args("test").Asserts(rbac.ResourceSystem, policy.ActionDelete)
2701+
}))
2702+
s.Run("GetRuntimeConfig", s.Subtest(func(db database.Store, check *expects) {
2703+
_ = db.UpsertRuntimeConfig(context.Background(), database.UpsertRuntimeConfigParams{
2704+
Key: "test",
2705+
Value: "value",
2706+
})
2707+
check.Args("test").Asserts(rbac.ResourceSystem, policy.ActionRead)
2708+
}))
2709+
s.Run("UpsertRuntimeConfig", s.Subtest(func(db database.Store, check *expects) {
2710+
check.Args(database.UpsertRuntimeConfigParams{
2711+
Key: "test",
2712+
Value: "value",
2713+
}).Asserts(rbac.ResourceSystem, policy.ActionCreate)
2714+
}))
26992715
}
27002716

27012717
func (s *MethodTestSuite) TestNotifications() {

coderd/database/dbmem/dbmem.go

+35
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func New() database.Store {
8484
workspaceProxies: make([]database.WorkspaceProxy, 0),
8585
customRoles: make([]database.CustomRole, 0),
8686
locks: map[int64]struct{}{},
87+
runtimeConfig: map[string]string{},
8788
},
8889
}
8990
// Always start with a default org. Matching migration 198.
@@ -194,6 +195,7 @@ type data struct {
194195
workspaces []database.Workspace
195196
workspaceProxies []database.WorkspaceProxy
196197
customRoles []database.CustomRole
198+
runtimeConfig map[string]string
197199
// Locks is a map of lock names. Any keys within the map are currently
198200
// locked.
199201
locks map[int64]struct{}
@@ -1928,6 +1930,14 @@ func (q *FakeQuerier) DeleteReplicasUpdatedBefore(_ context.Context, before time
19281930
return nil
19291931
}
19301932

1933+
func (q *FakeQuerier) DeleteRuntimeConfig(_ context.Context, key string) error {
1934+
q.mutex.Lock()
1935+
defer q.mutex.Unlock()
1936+
1937+
delete(q.runtimeConfig, key)
1938+
return nil
1939+
}
1940+
19311941
func (*FakeQuerier) DeleteTailnetAgent(context.Context, database.DeleteTailnetAgentParams) (database.DeleteTailnetAgentRow, error) {
19321942
return database.DeleteTailnetAgentRow{}, ErrUnimplemented
19331943
}
@@ -3505,6 +3515,18 @@ func (q *FakeQuerier) GetReplicasUpdatedAfter(_ context.Context, updatedAt time.
35053515
return replicas, nil
35063516
}
35073517

3518+
func (q *FakeQuerier) GetRuntimeConfig(_ context.Context, key string) (string, error) {
3519+
q.mutex.Lock()
3520+
defer q.mutex.Unlock()
3521+
3522+
val, ok := q.runtimeConfig[key]
3523+
if !ok {
3524+
return "", sql.ErrNoRows
3525+
}
3526+
3527+
return val, nil
3528+
}
3529+
35083530
func (*FakeQuerier) GetTailnetAgents(context.Context, uuid.UUID) ([]database.TailnetAgent, error) {
35093531
return nil, ErrUnimplemented
35103532
}
@@ -9187,6 +9209,19 @@ func (q *FakeQuerier) UpsertProvisionerDaemon(_ context.Context, arg database.Up
91879209
return d, nil
91889210
}
91899211

9212+
func (q *FakeQuerier) UpsertRuntimeConfig(_ context.Context, arg database.UpsertRuntimeConfigParams) error {
9213+
err := validateDatabaseType(arg)
9214+
if err != nil {
9215+
return err
9216+
}
9217+
9218+
q.mutex.Lock()
9219+
defer q.mutex.Unlock()
9220+
9221+
q.runtimeConfig[arg.Key] = arg.Value
9222+
return nil
9223+
}
9224+
91909225
func (*FakeQuerier) UpsertTailnetAgent(context.Context, database.UpsertTailnetAgentParams) (database.TailnetAgent, error) {
91919226
return database.TailnetAgent{}, ErrUnimplemented
91929227
}

coderd/database/dbmetrics/dbmetrics.go

+21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

+43
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

+36
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/siteconfig.sql

+11
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,14 @@ SELECT
9696
INSERT INTO site_configs (key, value) VALUES ('notifications_settings', $1)
9797
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'notifications_settings';
9898

99+
-- name: GetRuntimeConfig :one
100+
SELECT value FROM site_configs WHERE site_configs.key = $1;
101+
102+
-- name: UpsertRuntimeConfig :exec
103+
INSERT INTO site_configs (key, value) VALUES ($1, $2)
104+
ON CONFLICT (key) DO UPDATE SET value = $2 WHERE site_configs.key = $1;
105+
106+
-- name: DeleteRuntimeConfig :exec
107+
DELETE FROM site_configs
108+
WHERE site_configs.key = $1;
109+

0 commit comments

Comments
 (0)