@@ -310,17 +310,18 @@ func (ex *RunExecutor) execJob(ctx context.Context, jobLogFile io.Writer) error
310310 // `env` interpolation feature is postponed to some future release
311311 envMap .Update (ex .jobSpec .Env , false )
312312
313+ const profilePath = "/etc/profile"
314+ const dstackProfilePath = "/tmp/dstack_profile"
315+ if err := writeDstackProfile (envMap , dstackProfilePath ); err != nil {
316+ log .Warning (ctx , "failed to write dstack_profile" , "path" , dstackProfilePath , "err" , err )
317+ } else if err := includeDstackProfile (profilePath , dstackProfilePath ); err != nil {
318+ log .Warning (ctx , "failed to include dstack_profile" , "path" , profilePath , "err" , err )
319+ }
320+
313321 // As of 2024-11-29, ex.homeDir is always set to /root
314322 rootSSHDir , err := prepareSSHDir (- 1 , - 1 , ex .homeDir )
315323 if err != nil {
316324 log .Warning (ctx , "failed to prepare ssh dir" , "home" , ex .homeDir , "err" , err )
317- } else {
318- rootSSHEnvPath := filepath .Join (rootSSHDir , "environment" )
319- restoreRootSSHEnv := backupFile (ctx , rootSSHEnvPath )
320- defer restoreRootSSHEnv (ctx )
321- if err := writeSSHEnvironment (envMap , - 1 , - 1 , rootSSHEnvPath ); err != nil {
322- log .Warning (ctx , "failed to write SSH environment" , "path" , ex .homeDir , "err" , err )
323- }
324325 }
325326 userSSHDir := ""
326327 uid := - 1
@@ -337,12 +338,6 @@ func (ex *RunExecutor) execJob(ctx context.Context, jobLogFile io.Writer) error
337338 if err != nil {
338339 log .Warning (ctx , "failed to prepare ssh dir" , "home" , homeDir , "err" , err )
339340 } else {
340- userSSHEnvPath := filepath .Join (userSSHDir , "environment" )
341- restoreUserSSHEnv := backupFile (ctx , userSSHEnvPath )
342- defer restoreUserSSHEnv (ctx )
343- if err := writeSSHEnvironment (envMap , uid , gid , userSSHEnvPath ); err != nil {
344- log .Warning (ctx , "failed to write SSH environment" , "path" , homeDir , "err" , err )
345- }
346341 rootSSHKeysPath := filepath .Join (rootSSHDir , "authorized_keys" )
347342 userSSHKeysPath := filepath .Join (userSSHDir , "authorized_keys" )
348343 restoreUserSSHKeys := backupFile (ctx , userSSHKeysPath )
@@ -676,53 +671,40 @@ func prepareSSHDir(uid int, gid int, homeDir string) (string, error) {
676671 return sshDir , nil
677672}
678673
679- func writeSSHEnvironment (env map [string ]string , uid int , gid int , envPath string ) error {
680- info , err := os .Stat (envPath )
681- if err == nil {
682- if info .IsDir () {
683- return fmt .Errorf ("is a directory: %s" , envPath )
684- }
685- if err = os .Chmod (envPath , 0o600 ); err != nil {
686- return err
687- }
688- } else if ! errors .Is (err , os .ErrNotExist ) {
689- return err
690- }
691-
692- envFile , err := os .OpenFile (envPath , os .O_APPEND | os .O_WRONLY | os .O_CREATE , 0o600 )
674+ func writeDstackProfile (env map [string ]string , path string ) error {
675+ file , err := os .OpenFile (path , os .O_CREATE | os .O_TRUNC | os .O_WRONLY , 0o644 )
693676 if err != nil {
694677 return err
695678 }
696- defer envFile .Close ()
679+ defer file .Close ()
697680 for key , value := range env {
698681 switch key {
699- case "USER" , "HOME" , "SHELL" , "PWD" , "_" :
700- continue
701- }
702- // sshd doesn't support multiline variable values in .ssh/environment:
703- // VAR1=line1
704- // line2
705- // line3
706- // VAR2=singleline
707- // leads to:
708- // Bad line 2 in /root/.ssh/environment
709- // Bad line 3 in /root/.ssh/environment
710- // Assuming a single trailing newline is not a big deal
711- value := strings .TrimSuffix (value , "\n " )
712- // If there is any non-trailing newline, or more than one
713- // trailing newline, skip the variable
714- if strings .Contains (value , "\n " ) {
682+ case "HOSTNAME" , "USER" , "HOME" , "SHELL" , "SHLVL" , "PWD" , "_" :
715683 continue
716684 }
717- line := fmt .Sprintf ("%s=%s \n " , key , value )
718- if _ , err = envFile .WriteString (line ); err != nil {
685+ line := fmt .Sprintf ("export %s='%s' \n " , key , strings . ReplaceAll ( value , `'` , `'"'"'` ) )
686+ if _ , err = file .WriteString (line ); err != nil {
719687 return err
720688 }
721689 }
722- if err = os .Chown ( envPath , uid , gid ); err != nil {
690+ if err = os .Chmod ( path , 0o644 ); err != nil {
723691 return err
724692 }
693+ return nil
694+ }
725695
696+ func includeDstackProfile (profilePath string , dstackProfilePath string ) error {
697+ file , err := os .OpenFile (profilePath , os .O_CREATE | os .O_APPEND | os .O_WRONLY , 0o644 )
698+ if err != nil {
699+ return err
700+ }
701+ defer file .Close ()
702+ if _ , err = file .WriteString (fmt .Sprintf ("\n . '%s'\n " , dstackProfilePath )); err != nil {
703+ return err
704+ }
705+ if err = os .Chmod (profilePath , 0o644 ); err != nil {
706+ return err
707+ }
726708 return nil
727709}
728710
0 commit comments