Skip to content

Commit 9329805

Browse files
committed
chore: implement store manager
1 parent a47156d commit 9329805

File tree

6 files changed

+33
-33
lines changed

6 files changed

+33
-33
lines changed

cli/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
827827
// dbauthz is configured in `Coderd.New()`, but we need the manager
828828
// at this level for notifications. We might have to move some init
829829
// code around.
830-
options.RuntimeConfig = runtimeconfig.NewStoreManager(options.Database)
830+
options.RuntimeConfig = runtimeconfig.NewStoreManager()
831831

832832
// This should be output before the logs start streaming.
833833
cliui.Infof(inv.Stdout, "\n==> Logs will stream in below (press ctrl+c to gracefully exit):")

coderd/coderdtest/coderdtest.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,7 @@ func NewOptions(t testing.TB, options *Options) (func(http.Handler), context.Can
255255
var acs dbauthz.AccessControlStore = dbauthz.AGPLTemplateAccessControlStore{}
256256
accessControlStore.Store(&acs)
257257

258-
// runtimeManager does not use dbauthz.
259-
// TODO: It probably should, but the init code for prod happens before dbauthz
260-
// is ready.
261-
runtimeManager := runtimeconfig.NewStoreManager(options.Database)
258+
runtimeManager := runtimeconfig.NewStoreManager()
262259
options.Database = dbauthz.New(options.Database, options.Authorizer, *options.Logger, accessControlStore)
263260

264261
// Some routes expect a deployment ID, so just make sure one exists.

coderd/runtimeconfig/deploymententry.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (e *DeploymentEntry[T]) StartupValue() T {
4545

4646
// Coalesce attempts to resolve the runtime value of this field from the store via the given Manager. Should no runtime
4747
// value be found, the startup value will be used.
48-
func (e *DeploymentEntry[T]) Coalesce(ctx context.Context, r Manager) (T, error) {
48+
func (e *DeploymentEntry[T]) Coalesce(ctx context.Context, r Resolver) (T, error) {
4949
var zero T
5050

5151
resolved, err := e.Resolve(ctx, r)

coderd/runtimeconfig/entry_test.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestEntry(t *testing.T) {
4040
t.Run("zero", func(t *testing.T) {
4141
t.Parallel()
4242

43-
mgr := runtimeconfig.NewNoopManager()
43+
rlv := runtimeconfig.NewNoopResolver()
4444

4545
// A zero-value declaration of a runtimeconfig.Entry should behave as a zero value of the generic type.
4646
// NB! A name has not been set for this entry; it is "uninitialized".
@@ -52,18 +52,19 @@ func TestEntry(t *testing.T) {
5252
require.NoError(t, field.SetStartupValue("true"))
5353

5454
// But attempting to resolve will produce an error.
55-
_, err := field.Resolve(context.Background(), mgr)
55+
_, err := field.Resolve(context.Background(), rlv)
5656
require.ErrorIs(t, err, runtimeconfig.ErrNameNotSet)
5757
// But attempting to set the runtime value will produce an error.
5858
val := serpent.BoolOf(ptr.Ref(true))
59-
require.ErrorIs(t, field.SetRuntimeValue(context.Background(), mgr, val), runtimeconfig.ErrNameNotSet)
59+
require.ErrorIs(t, field.SetRuntimeValue(context.Background(), rlv, val), runtimeconfig.ErrNameNotSet)
6060
})
6161

6262
t.Run("simple", func(t *testing.T) {
6363
t.Parallel()
6464

6565
ctx := testutil.Context(t, testutil.WaitShort)
66-
mgr := runtimeconfig.NewStoreManager(dbmem.New())
66+
mgr := runtimeconfig.NewStoreManager()
67+
db := dbmem.New()
6768

6869
var (
6970
base = serpent.String("system@dev.coder.com")
@@ -78,16 +79,16 @@ func TestEntry(t *testing.T) {
7879
// Validate that it returns that value.
7980
require.Equal(t, base.String(), field.String())
8081
// Validate that there is no org-level override right now.
81-
_, err := field.Resolve(ctx, mgr)
82+
_, err := field.Resolve(ctx, mgr.DeploymentResolver(db))
8283
require.ErrorIs(t, err, runtimeconfig.EntryNotFound)
8384
// Coalesce returns the deployment-wide value.
84-
val, err := field.Coalesce(ctx, mgr)
85+
val, err := field.Coalesce(ctx, mgr.DeploymentResolver(db))
8586
require.NoError(t, err)
8687
require.Equal(t, base.String(), val.String())
8788
// Set an org-level override.
88-
require.NoError(t, field.SetRuntimeValue(ctx, mgr, &override))
89+
require.NoError(t, field.SetRuntimeValue(ctx, mgr.DeploymentResolver(db), &override))
8990
// Coalesce now returns the org-level value.
90-
val, err = field.Coalesce(ctx, mgr)
91+
val, err = field.Coalesce(ctx, mgr.DeploymentResolver(db))
9192
require.NoError(t, err)
9293
require.Equal(t, override.String(), val.String())
9394
})
@@ -96,7 +97,8 @@ func TestEntry(t *testing.T) {
9697
t.Parallel()
9798

9899
ctx := testutil.Context(t, testutil.WaitShort)
99-
mgr := runtimeconfig.NewStoreManager(dbmem.New())
100+
mgr := runtimeconfig.NewStoreManager()
101+
db := dbmem.New()
100102

101103
var (
102104
base = serpent.Struct[map[string]string]{
@@ -117,16 +119,16 @@ func TestEntry(t *testing.T) {
117119
// Check that default has been set.
118120
require.Equal(t, base.String(), field.StartupValue().String())
119121
// Validate that there is no org-level override right now.
120-
_, err := field.Resolve(ctx, mgr)
122+
_, err := field.Resolve(ctx, mgr.DeploymentResolver(db))
121123
require.ErrorIs(t, err, runtimeconfig.EntryNotFound)
122124
// Coalesce returns the deployment-wide value.
123-
val, err := field.Coalesce(ctx, mgr)
125+
val, err := field.Coalesce(ctx, mgr.DeploymentResolver(db))
124126
require.NoError(t, err)
125127
require.Equal(t, base.Value, val.Value)
126128
// Set an org-level override.
127-
require.NoError(t, field.SetRuntimeValue(ctx, mgr, &override))
129+
require.NoError(t, field.SetRuntimeValue(ctx, mgr.DeploymentResolver(db), &override))
128130
// Coalesce now returns the org-level value.
129-
structVal, err := field.Resolve(ctx, mgr)
131+
structVal, err := field.Resolve(ctx, mgr.DeploymentResolver(db))
130132
require.NoError(t, err)
131133
require.Equal(t, override.Value, structVal.Value)
132134
})

coderd/runtimeconfig/manager.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import (
88
"github.com/coder/coder/v2/coderd/util/syncmap"
99
)
1010

11+
// StoreManager is the shared singleton that produces resolvers for runtime configuration.
1112
type StoreManager struct {
1213
}
1314

14-
func NewStoreManager() *StoreManager {
15+
func NewStoreManager() Manager {
1516
return &StoreManager{}
1617
}
1718

@@ -28,22 +29,23 @@ type cacheEntry struct {
2829
lastUpdated time.Time
2930
}
3031

32+
// MemoryCacheManager is an example of how a caching layer can be added to the
33+
// resolver from the manager.
34+
// TODO: Delete MemoryCacheManager and implement it properly in 'StoreManager'.
3135
type MemoryCacheManager struct {
32-
cache *syncmap.Map[string, cacheEntry]
33-
wrapped Manager
36+
cache *syncmap.Map[string, cacheEntry]
3437
}
3538

36-
func NewMemoryCacheManager(wrapped Manager) *MemoryCacheManager {
39+
func NewMemoryCacheManager() *MemoryCacheManager {
3740
return &MemoryCacheManager{
38-
cache: syncmap.New[string, cacheEntry](),
39-
wrapped: wrapped,
41+
cache: syncmap.New[string, cacheEntry](),
4042
}
4143
}
4244

4345
func (m *MemoryCacheManager) DeploymentResolver(db Store) Resolver {
44-
return NewMemoryCachedResolver(m.cache, m.wrapped.DeploymentResolver(db))
46+
return NewMemoryCachedResolver(m.cache, NewStoreResolver(db))
4547
}
4648

4749
func (m *MemoryCacheManager) OrganizationResolver(db Store, orgID uuid.UUID) Resolver {
48-
return OrganizationResolver(orgID, NewMemoryCachedResolver(m.cache, m.wrapped.DeploymentResolver(db)))
50+
return OrganizationResolver(orgID, NewMemoryCachedResolver(m.cache, NewStoreResolver(db)))
4951
}

coderd/runtimeconfig/spec.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@ package runtimeconfig
22

33
import (
44
"context"
5+
6+
"github.com/google/uuid"
57
)
68

79
type Initializer interface {
810
Initialize(name string)
911
}
1012

11-
// Manager is just a factory to produce Resolvers.
12-
// The reason a factory is required, is the Manager can act as a caching
13-
// layer for runtime settings.
13+
// TODO: We should probably remove the manager interface and only support
14+
// 1 implementation.
1415
type Manager interface {
15-
// DeploymentResolver returns a Resolver scoped to the deployment.
1616
DeploymentResolver(db Store) Resolver
17-
// OrganizationResolver returns a Resolver scoped to the organization.
18-
OrganizationResolver(db Store, orgID string) Resolver
17+
OrganizationResolver(db Store, orgID uuid.UUID) Resolver
1918
}
2019

2120
type Resolver interface {

0 commit comments

Comments
 (0)