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

Skip to content

feat: Add support for MOTD file in coder agents #5147

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 12 commits into from
Nov 24, 2022
Prev Previous commit
Next Next commit
feat: Print motd on SSH login sessions
  • Loading branch information
mafredri committed Nov 23, 2022
commit 797001bed77d531f0b68d380140a9e09b674024d
88 changes: 78 additions & 10 deletions agent/agent.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package agent

import (
"bufio"
"context"
"crypto/rand"
"crypto/rsa"
Expand Down Expand Up @@ -675,6 +676,18 @@ func (a *agent) handleSSHSession(session ssh.Session) (retErr error) {
// See https://github.com/coder/coder/issues/3371.
session.DisablePTYEmulation()

if !isQuietLogin(session.RawCommand()) {
metadata, ok := a.metadata.Load().(codersdk.WorkspaceAgentMetadata)
if ok {
err = showMOTD(session, metadata.MOTDFile)
if err != nil {
a.logger.Error(ctx, "show MOTD", slog.Error(err))
}
} else {
a.logger.Warn(ctx, "metadata lookup failed, unable to show MOTD")
}
}

cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", sshPty.Term))

// The pty package sets `SSH_TTY` on supported platforms.
Expand Down Expand Up @@ -1000,19 +1013,74 @@ func Bicopy(ctx context.Context, c1, c2 io.ReadWriteCloser) {
}
}

// ExpandRelativeHomePath expands the tilde at the beginning of a path to the
// current user's home directory and returns a full absolute path.
func ExpandRelativeHomePath(in string) (string, error) {
usr, err := user.Current()
// isQuietLogin checks if the SSH server should perform a quiet login or not.
//
// https://github.com/openssh/openssh-portable/blob/25bd659cc72268f2858c5415740c442ee950049f/session.c#L816
func isQuietLogin(rawCommand string) bool {
// We are always quiet unless this is a login shell.
if len(rawCommand) != 0 {
return true
}

// Best effort, if we can't get the home directory,
// we can't lookup .hushlogin.
homedir, err := getHomeDir()
if err == nil {
if _, err := os.Stat(filepath.Join(homedir, ".hushlogin")); err == nil {
return true
}
}

return false
}

// showMOTD will output the message of the day from
// the given filename to dest, if the file exists.
//
// https://github.com/openssh/openssh-portable/blob/25bd659cc72268f2858c5415740c442ee950049f/session.c#L784
func showMOTD(dest io.Writer, filename string) error {
if filename == "" {
return nil
}

f, err := os.Open(filename)
if err != nil {
return "", xerrors.Errorf("get current user details: %w", err)
if xerrors.Is(err, os.ErrNotExist) {
// This is not an error, there simply isn't a MOTD to show.
return nil
}
return xerrors.Errorf("open MOTD: %w", err)
}
defer f.Close()

if in == "~" {
in = usr.HomeDir
} else if strings.HasPrefix(in, "~/") {
in = filepath.Join(usr.HomeDir, in[2:])
s := bufio.NewScanner(f)
for s.Scan() {
// Carriage return ensures each line starts
// at the beginning of the terminal.
_, err = fmt.Fprint(dest, s.Text()+"\r\n")
if err != nil {
return xerrors.Errorf("write MOTD: %w", err)
}
}
if err := s.Err(); err != nil {
return xerrors.Errorf("read MOTD: %w", err)
}

return filepath.Abs(in)
return nil
}

// getHomeDir returns the home directory of the current user, giving
// priority to the $HOME environment variable.
func getHomeDir() (string, error) {
// First we check the environment.
homedir, err := os.UserHomeDir()
if err != nil {
// As a fallback, we try the user information.
u, err := user.Current()
if err != nil {
return "", xerrors.Errorf("current user: %w", err)
}
return u.HomeDir, nil
}
return homedir, nil
}
1 change: 1 addition & 0 deletions coderd/workspaceagents.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request)
StartupScript: apiAgent.StartupScript,
Directory: apiAgent.Directory,
VSCodePortProxyURI: vscodeProxyURI,
MOTDFile: workspaceAgent.MOTDFile,
})
}

Expand Down
1 change: 1 addition & 0 deletions codersdk/workspaceagents.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ type WorkspaceAgentMetadata struct {
EnvironmentVariables map[string]string `json:"environment_variables"`
StartupScript string `json:"startup_script"`
Directory string `json:"directory"`
MOTDFile string `json:"motd_file"`
}

// AuthWorkspaceGoogleInstanceIdentity uses the Google Compute Engine Metadata API to
Expand Down