Thanks to visit codestin.com
Credit goes to github.com

Skip to content

refactor: workspace autostop_schedule -> ttl #1578

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 15 commits into from
May 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion agent/usershell/usershell_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ package usershell
import "os"

// Get returns the $SHELL environment variable.
func Get(username string) (string, error) {
func Get(_ string) (string, error) {
return os.Getenv("SHELL"), nil
}
167 changes: 0 additions & 167 deletions cli/autostop.go

This file was deleted.

8 changes: 3 additions & 5 deletions cli/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func list() *cobra.Command {
}

tableWriter := cliui.Table()
header := table.Row{"workspace", "template", "status", "last built", "outdated", "autostart", "autostop"}
header := table.Row{"workspace", "template", "status", "last built", "outdated", "autostart", "ttl"}
tableWriter.AppendHeader(header)
tableWriter.SortBy([]table.SortBy{{
Name: "workspace",
Expand Down Expand Up @@ -116,10 +116,8 @@ func list() *cobra.Command {
}

autostopDisplay := "-"
if workspace.AutostopSchedule != "" {
if sched, err := schedule.Weekly(workspace.AutostopSchedule); err == nil {
autostopDisplay = sched.Cron()
}
if workspace.TTL != nil {
autostopDisplay = workspace.TTL.String()
}

user := usersByID[workspace.OwnerID]
Expand Down
2 changes: 1 addition & 1 deletion cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ func Root() *cobra.Command {

cmd.AddCommand(
autostart(),
autostop(),
configSSH(),
create(),
delete(),
Expand All @@ -78,6 +77,7 @@ func Root() *cobra.Command {
stop(),
ssh(),
templates(),
ttl(),
update(),
users(),
portForward(),
Expand Down
10 changes: 2 additions & 8 deletions cli/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"github.com/coder/coder/cli/cliflag"
"github.com/coder/coder/cli/cliui"
"github.com/coder/coder/coderd/autobuild/notify"
"github.com/coder/coder/coderd/autobuild/schedule"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/cryptorand"
)
Expand Down Expand Up @@ -270,16 +269,11 @@ func notifyCondition(ctx context.Context, client *codersdk.Client, workspaceID u
return time.Time{}, nil
}

if ws.AutostopSchedule == "" {
if ws.TTL == nil || *ws.TTL == 0 {
return time.Time{}, nil
}
Comment on lines +272 to 274
Copy link
Member

Choose a reason for hiding this comment

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

Instead of using a pointer why not just have 0 mean disabled?

Copy link
Member Author

Choose a reason for hiding this comment

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

I considered that initially, but I think using the zero value could lead to bugs and/or unintended behaviour. Grey also preferred the semantics of nil | time.Duration from a FE consumption perspective.

Copy link
Member Author

Choose a reason for hiding this comment

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

You do have a point, though -- 0 is already an invalid TTL.

Copy link
Contributor

Choose a reason for hiding this comment

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

Comment: I think the FE or other clients having to know 0 means "manual" is unfortunate, but I'm willing to accept it if it's cleaner for our backend/APIs.

As stated earlier, from v2 forwards I believe it's best that we look at the Coder system as a frontend for a backend, not the other way around.

Copy link
Member

Choose a reason for hiding this comment

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

Should we then consider that in the API response? We could return something like {"ttl": 0, "ttl_mode": "manual"}?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's certainly golang convention to make use of "zero-values" in this way, but I don't think we should extend that to the HTTP API, CLI, or frontend, which should behave in ways that are independent of golang's idioms.

Copy link
Contributor

Choose a reason for hiding this comment

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

@spikecurtis are you referring to @deansheather 's comment here: #1578 (comment)

why not just have 0 mean disabled?

Or the fact that we're using a pointer such that the value can be nil or a number.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I feel like among go practitioners, 0 means disabled would be preferred to making it a pointer and nil means disabled.


sched, err := schedule.Weekly(ws.AutostopSchedule)
if err != nil {
return time.Time{}, nil
}

deadline = sched.Next(now)
deadline = ws.LatestBuild.UpdatedAt.Add(*ws.TTL)
callback = func() {
ttl := deadline.Sub(now)
var title, body string
Expand Down
144 changes: 144 additions & 0 deletions cli/ttl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package cli

import (
"fmt"
"time"

"github.com/spf13/cobra"
"golang.org/x/xerrors"

"github.com/coder/coder/codersdk"
)

const ttlDescriptionLong = `To have your workspace stop automatically after a configurable interval has passed.
Minimum TTL is 1 minute.
`

func ttl() *cobra.Command {
ttlCmd := &cobra.Command{
Annotations: workspaceCommand,
Use: "ttl [command]",
Short: "Schedule a workspace to automatically stop after a configurable interval",
Long: ttlDescriptionLong,
Example: "coder ttl set my-workspace 8h30m",
}

ttlCmd.AddCommand(ttlShow())
ttlCmd.AddCommand(ttlset())
ttlCmd.AddCommand(ttlunset())

return ttlCmd
}

func ttlShow() *cobra.Command {
cmd := &cobra.Command{
Use: "show <workspace_name>",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd)
if err != nil {
return xerrors.Errorf("create client: %w", err)
}
organization, err := currentOrganization(cmd, client)
if err != nil {
return xerrors.Errorf("get current org: %w", err)
}

workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
if err != nil {
return xerrors.Errorf("get workspace: %w", err)
}

if workspace.TTL == nil {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "not set\n")
return nil
}

_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s\n", workspace.TTL)

return nil
},
}
return cmd
}

func ttlset() *cobra.Command {
cmd := &cobra.Command{
Use: "set <workspace_name> <ttl>",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd)
if err != nil {
return xerrors.Errorf("create client: %w", err)
}
organization, err := currentOrganization(cmd, client)
if err != nil {
return xerrors.Errorf("get current org: %w", err)
}

workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
if err != nil {
return xerrors.Errorf("get workspace: %w", err)
}

ttl, err := time.ParseDuration(args[1])
if err != nil {
return xerrors.Errorf("parse ttl: %w", err)
}

truncated := ttl.Truncate(time.Minute)

if truncated == 0 {
return xerrors.Errorf("ttl must be at least 1m")
}

if truncated != ttl {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "warning: ttl rounded down to %s\n", truncated)
}

err = client.UpdateWorkspaceTTL(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
TTL: &truncated,
})
if err != nil {
return xerrors.Errorf("update workspace ttl: %w", err)
}

return nil
},
}

return cmd
}

func ttlunset() *cobra.Command {
return &cobra.Command{
Use: "unset <workspace_name>",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd)
if err != nil {
return xerrors.Errorf("create client: %w", err)
}
organization, err := currentOrganization(cmd, client)
if err != nil {
return xerrors.Errorf("get current org: %w", err)
}

workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
if err != nil {
return xerrors.Errorf("get workspace: %w", err)
}

err = client.UpdateWorkspaceTTL(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
TTL: nil,
})
if err != nil {
return xerrors.Errorf("update workspace ttl: %w", err)
}

_, _ = fmt.Fprint(cmd.OutOrStdout(), "ttl unset\n", workspace.Name)

return nil
},
}
}
Loading