Skip to content

docs: rebase restructure-new on main #14960

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 10 commits into from
Oct 3, 2024
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
Merge branch 'restructure-new' into atif/rebase-restructure-on-main
  • Loading branch information
matifali committed Oct 3, 2024
commit 1279c75f48ac75acc0724bf0615892d49baefd5c
2 changes: 1 addition & 1 deletion .github/workflows/contrib.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
steps:
- name: cla
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
uses: contributor-assistant/github-action@v2.6.0
uses: contributor-assistant/github-action@v2.6.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret
Expand Down
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ gen: \
agent/proto/agent.pb.go \
provisionersdk/proto/provisioner.pb.go \
provisionerd/proto/provisionerd.pb.go \
vpn/vpn.pb.go \
coderd/database/dump.sql \
$(DB_GEN_FILES) \
site/src/api/typesGenerated.ts \
Expand Down Expand Up @@ -517,6 +518,7 @@ gen/mark-fresh:
agent/proto/agent.pb.go \
provisionersdk/proto/provisioner.pb.go \
provisionerd/proto/provisionerd.pb.go \
vpn/vpn.pb.go \
coderd/database/dump.sql \
$(DB_GEN_FILES) \
site/src/api/typesGenerated.ts \
Expand Down Expand Up @@ -600,6 +602,12 @@ provisionerd/proto/provisionerd.pb.go: provisionerd/proto/provisionerd.proto
--go-drpc_opt=paths=source_relative \
./provisionerd/proto/provisionerd.proto

vpn/vpn.pb.go: vpn/vpn.proto
protoc \
--go_out=. \
--go_opt=paths=source_relative \
./vpn/vpn.proto

site/src/api/typesGenerated.ts: $(wildcard scripts/apitypings/*) $(shell find ./codersdk $(FIND_EXCLUSIONS) -type f -name '*.go')
go run ./scripts/apitypings/ > $@
./scripts/pnpm_install.sh
Expand Down
8 changes: 8 additions & 0 deletions buildinfo/buildinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ var (
// Updated by buildinfo_slim.go on start.
slim bool

// Updated by buildinfo_site.go on start.
site bool

// Injected with ldflags at build, see scripts/build_go.sh
tag string
agpl string // either "true" or "false", ldflags does not support bools
Expand Down Expand Up @@ -95,6 +98,11 @@ func IsSlim() bool {
return slim
}

// HasSite returns true if the frontend is embedded in the build.
func HasSite() bool {
return site
}

// IsAGPL returns true if this is an AGPL build.
func IsAGPL() bool {
return strings.Contains(agpl, "t")
Expand Down
7 changes: 7 additions & 0 deletions buildinfo/buildinfo_site.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build embed

package buildinfo

func init() {
site = true
}
1 change: 0 additions & 1 deletion cli/notifications_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ func createOpts(t *testing.T) *coderdtest.Options {
t.Helper()

dt := coderdtest.DeploymentValues(t)
dt.Experiments = []string{string(codersdk.ExperimentNotifications)}
return &coderdtest.Options{
DeploymentValues: dt,
}
Expand Down
2 changes: 1 addition & 1 deletion cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err
{
Flag: varNoOpen,
Env: "CODER_NO_OPEN",
Description: "Suppress opening the browser after logging in.",
Description: "Suppress opening the browser when logging in, or starting the server.",
Value: serpent.BoolOf(&r.noOpen),
Hidden: true,
Group: globalGroup,
Expand Down
101 changes: 48 additions & 53 deletions cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,16 @@ import (

"cdr.dev/slog"
"cdr.dev/slog/sloggers/sloghuman"
"github.com/coder/coder/v2/coderd/entitlements"
"github.com/coder/coder/v2/coderd/notifications/reports"
"github.com/coder/coder/v2/coderd/runtimeconfig"
"github.com/coder/pretty"
"github.com/coder/quartz"
"github.com/coder/retry"
"github.com/coder/serpent"
"github.com/coder/wgtunnel/tunnelsdk"

"github.com/coder/coder/v2/coderd/entitlements"
"github.com/coder/coder/v2/coderd/notifications/reports"
"github.com/coder/coder/v2/coderd/runtimeconfig"

"github.com/coder/coder/v2/buildinfo"
"github.com/coder/coder/v2/cli/clilog"
"github.com/coder/coder/v2/cli/cliui"
Expand Down Expand Up @@ -492,7 +493,12 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
BorderForeground(lipgloss.Color("12")).
Render(fmt.Sprintf("View the Web UI:\n%s",
pretty.Sprint(cliui.DefaultStyles.Hyperlink, accessURL))))
_ = openURL(inv, accessURL)
if buildinfo.HasSite() {
err = openURL(inv, accessURL)
if err == nil {
cliui.Infof(inv.Stdout, "Opening local browser... You can disable this by passing --no-open.\n")
}
}

// Used for zero-trust instance identity with Google Cloud.
googleTokenValidator, err := idtoken.NewValidator(ctx, option.WithoutAuthentication())
Expand Down Expand Up @@ -679,10 +685,6 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
options.OIDCConfig = oc
}

experiments := coderd.ReadExperiments(
options.Logger, options.DeploymentValues.Experiments.Value(),
)

// We'll read from this channel in the select below that tracks shutdown. If it remains
// nil, that case of the select will just never fire, but it's important not to have a
// "bare" read on this channel.
Expand Down Expand Up @@ -946,6 +948,33 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
return xerrors.Errorf("write config url: %w", err)
}

// Manage notifications.
cfg := options.DeploymentValues.Notifications
metrics := notifications.NewMetrics(options.PrometheusRegistry)
helpers := templateHelpers(options)

// The enqueuer is responsible for enqueueing notifications to the given store.
enqueuer, err := notifications.NewStoreEnqueuer(cfg, options.Database, helpers, logger.Named("notifications.enqueuer"), quartz.NewReal())
if err != nil {
return xerrors.Errorf("failed to instantiate notification store enqueuer: %w", err)
}
options.NotificationsEnqueuer = enqueuer

// The notification manager is responsible for:
// - creating notifiers and managing their lifecycles (notifiers are responsible for dequeueing/sending notifications)
// - keeping the store updated with status updates
notificationsManager, err := notifications.NewManager(cfg, options.Database, helpers, metrics, logger.Named("notifications.manager"))
if err != nil {
return xerrors.Errorf("failed to instantiate notification manager: %w", err)
}

// nolint:gocritic // TODO: create own role.
notificationsManager.Run(dbauthz.AsSystemRestricted(ctx))

// Run report generator to distribute periodic reports.
notificationReportGenerator := reports.NewReportGenerator(ctx, logger.Named("notifications.report_generator"), options.Database, options.NotificationsEnqueuer, quartz.NewReal())
defer notificationReportGenerator.Close()

// Since errCh only has one buffered slot, all routines
// sending on it must be wrapped in a select/default to
// avoid leaving dangling goroutines waiting for the
Expand Down Expand Up @@ -1002,38 +1031,6 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
options.WorkspaceUsageTracker = tracker
defer tracker.Close()

// Manage notifications.
var (
notificationsManager *notifications.Manager
)
if experiments.Enabled(codersdk.ExperimentNotifications) {
cfg := options.DeploymentValues.Notifications
metrics := notifications.NewMetrics(options.PrometheusRegistry)
helpers := templateHelpers(options)

// The enqueuer is responsible for enqueueing notifications to the given store.
enqueuer, err := notifications.NewStoreEnqueuer(cfg, options.Database, helpers, logger.Named("notifications.enqueuer"), quartz.NewReal())
if err != nil {
return xerrors.Errorf("failed to instantiate notification store enqueuer: %w", err)
}
options.NotificationsEnqueuer = enqueuer

// The notification manager is responsible for:
// - creating notifiers and managing their lifecycles (notifiers are responsible for dequeueing/sending notifications)
// - keeping the store updated with status updates
notificationsManager, err = notifications.NewManager(cfg, options.Database, helpers, metrics, logger.Named("notifications.manager"))
if err != nil {
return xerrors.Errorf("failed to instantiate notification manager: %w", err)
}

// nolint:gocritic // TODO: create own role.
notificationsManager.Run(dbauthz.AsSystemRestricted(ctx))

// Run report generator to distribute periodic reports.
notificationReportGenerator := reports.NewReportGenerator(ctx, logger.Named("notifications.report_generator"), options.Database, options.NotificationsEnqueuer, quartz.NewReal())
defer notificationReportGenerator.Close()
}

// Wrap the server in middleware that redirects to the access URL if
// the request is not to a local IP.
var handler http.Handler = coderAPI.RootHandler
Expand Down Expand Up @@ -1153,19 +1150,17 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
// Cancel any remaining in-flight requests.
shutdownConns()

if notificationsManager != nil {
// Stop the notification manager, which will cause any buffered updates to the store to be flushed.
// If the Stop() call times out, messages that were sent but not reflected as such in the store will have
// their leases expire after a period of time and will be re-queued for sending.
// See CODER_NOTIFICATIONS_LEASE_PERIOD.
cliui.Info(inv.Stdout, "Shutting down notifications manager..."+"\n")
err = shutdownWithTimeout(notificationsManager.Stop, 5*time.Second)
if err != nil {
cliui.Warnf(inv.Stderr, "Notifications manager shutdown took longer than 5s, "+
"this may result in duplicate notifications being sent: %s\n", err)
} else {
cliui.Info(inv.Stdout, "Gracefully shut down notifications manager\n")
}
// Stop the notification manager, which will cause any buffered updates to the store to be flushed.
// If the Stop() call times out, messages that were sent but not reflected as such in the store will have
// their leases expire after a period of time and will be re-queued for sending.
// See CODER_NOTIFICATIONS_LEASE_PERIOD.
cliui.Info(inv.Stdout, "Shutting down notifications manager..."+"\n")
err = shutdownWithTimeout(notificationsManager.Stop, 5*time.Second)
if err != nil {
cliui.Warnf(inv.Stderr, "Notifications manager shutdown took longer than 5s, "+
"this may result in duplicate notifications being sent: %s\n", err)
} else {
cliui.Info(inv.Stdout, "Gracefully shut down notifications manager\n")
}

// Shut down provisioners before waiting for WebSockets
Expand Down
4 changes: 4 additions & 0 deletions cli/testdata/coder_tokens_create_--help.golden
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@ OPTIONS:
-n, --name string, $CODER_TOKEN_NAME
Specify a human-readable name.

-u, --user string, $CODER_TOKEN_USER
Specify the user to create the token for (Only works if logged in user
is admin).

———
Run `coder --help` for a list of global options.
14 changes: 13 additions & 1 deletion cli/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func (r *RootCmd) createToken() *serpent.Command {
var (
tokenLifetime time.Duration
name string
user string
)
client := new(codersdk.Client)
cmd := &serpent.Command{
Expand All @@ -58,7 +59,11 @@ func (r *RootCmd) createToken() *serpent.Command {
r.InitClient(client),
),
Handler: func(inv *serpent.Invocation) error {
res, err := client.CreateToken(inv.Context(), codersdk.Me, codersdk.CreateTokenRequest{
userID := codersdk.Me
if user != "" {
userID = user
}
res, err := client.CreateToken(inv.Context(), userID, codersdk.CreateTokenRequest{
Lifetime: tokenLifetime,
TokenName: name,
})
Expand Down Expand Up @@ -87,6 +92,13 @@ func (r *RootCmd) createToken() *serpent.Command {
Description: "Specify a human-readable name.",
Value: serpent.StringOf(&name),
},
{
Flag: "user",
FlagShorthand: "u",
Env: "CODER_TOKEN_USER",
Description: "Specify the user to create the token for (Only works if logged in user is admin).",
Value: serpent.StringOf(&user),
},
}

return cmd
Expand Down
47 changes: 46 additions & 1 deletion cli/tokens_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ import (
func TestTokens(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
adminUser := coderdtest.CreateFirstUser(t, client)

secondUserClient, secondUser := coderdtest.CreateAnotherUser(t, client, adminUser.OrganizationID)
_, thirdUser := coderdtest.CreateAnotherUser(t, client, adminUser.OrganizationID)

ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancelFunc()

// helpful empty response
inv, root := clitest.New(t, "tokens", "ls")
//nolint:gocritic // This should be run as the owner user.
clitest.SetupConfig(t, client, root)
buf := new(bytes.Buffer)
inv.Stdout = buf
Expand All @@ -42,6 +46,19 @@ func TestTokens(t *testing.T) {
require.NotEmpty(t, res)
id := res[:10]

// Test creating a token for second user from first user's (admin) session
inv, root = clitest.New(t, "tokens", "create", "--name", "token-two", "--user", secondUser.ID.String())
clitest.SetupConfig(t, client, root)
buf = new(bytes.Buffer)
inv.Stdout = buf
err = inv.WithContext(ctx).Run()
// Test should succeed in creating token for second user
require.NoError(t, err)
res = buf.String()
require.NotEmpty(t, res)
secondTokenID := res[:10]

// Test listing tokens from the first user's (admin) session
inv, root = clitest.New(t, "tokens", "ls")
clitest.SetupConfig(t, client, root)
buf = new(bytes.Buffer)
Expand All @@ -50,11 +67,39 @@ func TestTokens(t *testing.T) {
require.NoError(t, err)
res = buf.String()
require.NotEmpty(t, res)
// Result should only contain the token created for the admin user
require.Contains(t, res, "ID")
require.Contains(t, res, "EXPIRES AT")
require.Contains(t, res, "CREATED AT")
require.Contains(t, res, "LAST USED")
require.Contains(t, res, id)
// Result should not contain the token created for the second user
require.NotContains(t, res, secondTokenID)

// Test listing tokens from the second user's session
inv, root = clitest.New(t, "tokens", "ls")
clitest.SetupConfig(t, secondUserClient, root)
buf = new(bytes.Buffer)
inv.Stdout = buf
err = inv.WithContext(ctx).Run()
require.NoError(t, err)
res = buf.String()
require.NotEmpty(t, res)
require.Contains(t, res, "ID")
require.Contains(t, res, "EXPIRES AT")
require.Contains(t, res, "CREATED AT")
require.Contains(t, res, "LAST USED")
// Result should contain the token created for the second user
require.Contains(t, res, secondTokenID)

// Test creating a token for third user from second user's (non-admin) session
inv, root = clitest.New(t, "tokens", "create", "--name", "token-two", "--user", thirdUser.ID.String())
clitest.SetupConfig(t, secondUserClient, root)
buf = new(bytes.Buffer)
inv.Stdout = buf
err = inv.WithContext(ctx).Run()
// User (non-admin) should not be able to create a token for another user
require.Error(t, err)

inv, root = clitest.New(t, "tokens", "ls", "--output=json")
clitest.SetupConfig(t, client, root)
Expand Down
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.