Skip to content

chore: make default workspace proxy editable #7903

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 13 commits into from
Jun 8, 2023
Next Next commit
chore: add database methods for editing the default workspace proxy
  • Loading branch information
Emyrk committed Jun 7, 2023
commit 9cb6421c3babff749b69d5f68e32328b95500b97
5 changes: 5 additions & 0 deletions coderd/database/dbauthz/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,11 @@ func (q *querier) DeleteLicense(ctx context.Context, id int32) (int32, error) {
return id, nil
}

func (q *querier) GetDefaultProxyConfig(ctx context.Context) (database.GetDefaultProxyConfigRow, error) {
// No authz checks
return q.db.GetDefaultProxyConfig(ctx)
}

func (q *querier) GetDeploymentID(ctx context.Context) (string, error) {
// No authz checks
return q.db.GetDeploymentID(ctx)
Expand Down
3 changes: 3 additions & 0 deletions coderd/database/dbauthz/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ func (s *MethodTestSuite) TestLicense() {
s.Run("GetDeploymentID", s.Subtest(func(db database.Store, check *expects) {
check.Args().Asserts().Returns("")
}))
s.Run("GetDefaultProxyConfig", s.Subtest(func(db database.Store, check *expects) {
check.Args().Asserts().Returns(database.GetDefaultProxyConfigRow{})
}))
s.Run("GetLogoURL", s.Subtest(func(db database.Store, check *expects) {
err := db.UpsertLogoURL(context.Background(), "value")
require.NoError(s.T(), err)
Expand Down
7 changes: 7 additions & 0 deletions coderd/database/dbauthz/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,3 +431,10 @@ func (q *querier) GetWorkspaceProxyByHostname(ctx context.Context, params databa
}
return q.db.GetWorkspaceProxyByHostname(ctx, params)
}

func (q *querier) UpsertDefaultProxy(ctx context.Context, arg database.UpsertDefaultProxyParams) error {
if err := q.authorizeContext(ctx, rbac.ActionUpdate, rbac.ResourceSystem); err != nil {
return err
}
return q.db.UpsertDefaultProxy(ctx, arg)
}
3 changes: 3 additions & 0 deletions coderd/database/dbauthz/system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ func (s *MethodTestSuite) TestSystemFunctions() {
LoginType: database.LoginTypeGithub,
}).Asserts(rbac.ResourceSystem, rbac.ActionUpdate).Returns(l)
}))
s.Run("UpsertDefaultProxy", s.Subtest(func(db database.Store, check *expects) {
check.Args(database.UpsertDefaultProxyParams{}).Asserts(rbac.ResourceSystem, rbac.ActionUpdate).Returns()
}))
s.Run("GetUserLinkByLinkedID", s.Subtest(func(db database.Store, check *expects) {
l := dbgen.UserLink(s.T(), db, database.UserLink{})
check.Args(l.LinkedID).Asserts(rbac.ResourceSystem, rbac.ActionRead).Returns(l)
Expand Down
36 changes: 27 additions & 9 deletions coderd/database/dbfake/databasefake.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ var errDuplicateKey = &pq.Error{

// New returns an in-memory fake of the database.
func New() database.Store {
return &fakeQuerier{
q := &fakeQuerier{
mutex: &sync.RWMutex{},
data: &data{
apiKeys: make([]database.APIKey, 0),
Expand Down Expand Up @@ -73,6 +73,9 @@ func New() database.Store {
locks: map[int64]struct{}{},
},
}
q.defaultProxyDisplayName = "Default"
q.defaultProxyIconURL = "/emojis/1f3e1.png"
return q
}

type rwMutex interface {
Expand Down Expand Up @@ -144,14 +147,16 @@ type data struct {

// Locks is a map of lock names. Any keys within the map are currently
// locked.
locks map[int64]struct{}
deploymentID string
derpMeshKey string
lastUpdateCheck []byte
serviceBanner []byte
logoURL string
appSecurityKey string
lastLicenseID int32
locks map[int64]struct{}
deploymentID string
derpMeshKey string
lastUpdateCheck []byte
serviceBanner []byte
logoURL string
appSecurityKey string
lastLicenseID int32
defaultProxyDisplayName string
defaultProxyIconURL string
}

func validateDatabaseTypeWithValid(v reflect.Value) (handled bool, err error) {
Expand Down Expand Up @@ -5170,3 +5175,16 @@ func isNull(v interface{}) bool {
func isNotNull(v interface{}) bool {
return reflect.ValueOf(v).FieldByName("Valid").Bool()
}

func (q *fakeQuerier) GetDefaultProxyConfig(ctx context.Context) (database.GetDefaultProxyConfigRow, error) {
return database.GetDefaultProxyConfigRow{
DisplayName: q.defaultProxyDisplayName,
IconUrl: q.defaultProxyIconURL,
}, nil
}

func (q *fakeQuerier) UpsertDefaultProxy(ctx context.Context, arg database.UpsertDefaultProxyParams) error {
q.defaultProxyDisplayName = arg.DisplayName
q.defaultProxyIconURL = arg.IconUrl
return nil
}
14 changes: 14 additions & 0 deletions coderd/database/dbmetrics/dbmetrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -1518,3 +1518,17 @@ func (m metricsStore) GetAuthorizedUserCount(ctx context.Context, arg database.G
m.queryLatencies.WithLabelValues("GetAuthorizedUserCount").Observe(time.Since(start).Seconds())
return count, err
}

func (m metricsStore) UpsertDefaultProxy(ctx context.Context, arg database.UpsertDefaultProxyParams) error {
start := time.Now()
err := m.s.UpsertDefaultProxy(ctx, arg)
m.queryLatencies.WithLabelValues("UpsertDefaultProxy").Observe(time.Since(start).Seconds())
return err
}

func (m metricsStore) GetDefaultProxyConfig(ctx context.Context) (database.GetDefaultProxyConfigRow, error) {
start := time.Now()
resp, err := m.s.GetDefaultProxyConfig(ctx)
m.queryLatencies.WithLabelValues("GetDefaultProxyConfig").Observe(time.Since(start).Seconds())
return resp, err
}
29 changes: 29 additions & 0 deletions coderd/database/dbmock/store.go

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

5 changes: 5 additions & 0 deletions coderd/database/querier.go

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

55 changes: 55 additions & 0 deletions coderd/database/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/database/dbgen"
"github.com/coder/coder/coderd/database/migrations"
"github.com/coder/coder/testutil"
)

func TestGetDeploymentWorkspaceAgentStats(t *testing.T) {
Expand Down Expand Up @@ -257,3 +258,57 @@ func TestProxyByHostname(t *testing.T) {
})
}
}

func TestDefaultProxy(t *testing.T) {
t.Parallel()
if testing.Short() {
t.SkipNow()
}
sqlDB := testSQLDB(t)
err := migrations.Up(sqlDB)
require.NoError(t, err)
db := database.New(sqlDB)

ctx := testutil.Context(t, testutil.WaitLong)
depID := uuid.NewString()
err = db.InsertDeploymentID(ctx, depID)
require.NoError(t, err, "insert deployment id")

// Fetch empty proxy values
defProxy, err := db.GetDefaultProxyConfig(ctx)
require.NoError(t, err, "get def proxy")

require.Equal(t, defProxy.DisplayName, "Default")
require.Equal(t, defProxy.IconUrl, "/emojis/1f3e1.png")

// Set the proxy values
args := database.UpsertDefaultProxyParams{
DisplayName: "displayname",
IconUrl: "/icon.png",
}
err = db.UpsertDefaultProxy(ctx, args)
require.NoError(t, err, "insert def proxy")

defProxy, err = db.GetDefaultProxyConfig(ctx)
require.NoError(t, err, "get def proxy")
require.Equal(t, defProxy.DisplayName, args.DisplayName)
require.Equal(t, defProxy.IconUrl, args.IconUrl)

// Upsert values
args = database.UpsertDefaultProxyParams{
DisplayName: "newdisplayname",
IconUrl: "/newicon.png",
}
err = db.UpsertDefaultProxy(ctx, args)
require.NoError(t, err, "upsert def proxy")

defProxy, err = db.GetDefaultProxyConfig(ctx)
require.NoError(t, err, "get def proxy")
require.Equal(t, defProxy.DisplayName, args.DisplayName)
require.Equal(t, defProxy.IconUrl, args.IconUrl)

// Ensure other site configs are the same
found, err := db.GetDeploymentID(ctx)
require.NoError(t, err, "get deployment id")
require.Equal(t, depID, found)
}
41 changes: 41 additions & 0 deletions coderd/database/queries.sql.go

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

20 changes: 20 additions & 0 deletions coderd/database/queries/siteconfig.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
-- name: UpsertDefaultProxy :exec
-- The default proxy is implied and not actually stored in the database.
-- So we need to store it's configuration here for display purposes.
-- The functional values are immutable and controlled implicitly.
INSERT INTO site_configs (key, value)
VALUES
('default_proxy_display_name', @display_name :: text),
('default_proxy_icon_url', @icon_url :: text)
ON CONFLICT
(key)
DO UPDATE SET value = EXCLUDED.value WHERE site_configs.key = EXCLUDED.key
;

-- name: GetDefaultProxyConfig :one
SELECT
COALESCE((SELECT value FROM site_configs WHERE key = 'default_proxy_display_name'), 'Default') :: text AS display_name,
COALESCE((SELECT value FROM site_configs WHERE key = 'default_proxy_icon_url'), '/emojis/1f3e1.png') :: text AS icon_url
;


-- name: InsertDeploymentID :exec
INSERT INTO site_configs (key, value) VALUES ('deployment_id', $1);

Expand Down
6 changes: 2 additions & 4 deletions coderd/workspaceproxies.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,10 @@ func (api *API) PrimaryRegion(ctx context.Context) (codersdk.Region, error) {
}

return codersdk.Region{
ID: deploymentID,
// TODO: provide some way to customize these fields for the primary
// region
ID: deploymentID,
Name: "primary",
DisplayName: "Default",
IconURL: "/emojis/1f60e.png", // face with sunglasses
IconURL: "/emojis/1f3e1.png", // House with garden
Healthy: true,
PathAppURL: api.AccessURL.String(),
WildcardHostname: api.AppHostname,
Expand Down