diff --git a/modules/ordo/connection.scm b/modules/ordo/connection.scm index e17ad7c..b6a5b0c 100644 --- a/modules/ordo/connection.scm +++ b/modules/ordo/connection.scm @@ -18,60 +18,14 @@ #:export ( local-connection ssh-connection - init-connection! - close-connection! + setup + teardown connection-run connection-call-with-input-file connection-call-with-output-file call-with-connection run)) -(define-class () - (sudo #:getter sudo? #:init-keyword #:sudo)) - -(define-class ()) - -(define* (local-connection #:key (sudo? #f)) - (make #:sudo sudo?)) - -(define-class () - (user #:getter get-user #:init-keyword #:user) - (host #:getter get-host #:init-keyword #:host) - (session #:getter get-session #:setter set-session!) - (sftp-session #:getter get-sftp-session #:setter set-sftp-session!)) - -(define* (ssh-connection user host #:key (sudo? #f)) - (make #:user user #:host host #:sudo sudo?)) - -(define-method (init-connection! (c )) #f) - -(define-method (close-connection! (c )) #f) - -(define-method (init-connection! (c )) - (unless (slot-bound? c 'session) - (set-session! c (make-session #:user (get-user c) #:host (get-host c)))) - (let ((s (get-session c))) - (unless (connected? s) - (connect! s) - (let ((server-auth (authenticate-server s))) - (unless (equal? 'ok server-auth) - (error (format #f "authenticate-server: ~a" server-auth)))) - (let ((user-auth (userauth-public-key/auto! s))) - (unless (equal? 'success user-auth) - (error (format #f "userauth-public-key: ~a" user-auth)))))) - #t) - -(define-method (sftp-session (c )) - (unless (slot-bound? c 'sftp-session) - (set-sftp-session! c (make-sftp-session (get-session c)))) - (get-sftp-session c)) - -(define-method (close-connection! (c )) - (when (slot-bound? c 'session) - (let ((s (get-session c))) - (when (connected? s) - (disconnect! s))))) - (define (read-lines port) (define (loop line result) (if (eof-object? line) @@ -79,6 +33,126 @@ (loop (read-line port) (cons line result)))) (loop (read-line port) '())) + +(define-class ()) + +(define-class ()) + +(define-method (setup (c )) #f) + +(define-method (teardown (c )) #f) + +(define (local-connection) + (make )) + +(define-method (connection-run (c ) (command ) + (let* ((port (open-input-pipe command)) + (output (read-lines port)) + (exit-status (status:exit-val (close-pipe port)))) + (values output exit-status)))) + +(define-method (connection-call-with-input-file (c ) (filename ) (proc )) + (call-with-input-file filename proc)) + +(define-method (connection-call-with-output-file (c ) (filename ) (proc )) + (call-with-output-file filename proc)) + +(define-class () + (user #:getter ssh-user #:init-keyword #:user) + (host #:getter ssh-host #:init-keyword #:host) + (password #:getter ssh-password #:init-keyword #:password) + (identity #:getter ssh-identity #:init-keyword #:identity) + (authenticate-server? #:getter ssh-authenticate-server? #:init-keyword authenticate-server?) + (session #:getter ssh-session #:setter set-ssh-session!) + (sftp-session #:getter sftp-session #:setter set-sftp-session!)) + +(define* (ssh-connection user host #:key (authenticate-server #t) password identity) + (make #:user user #:host host #:password password #:identity identity #:authenticate-server? authenticate-server)) + +(define-method (setup (c )) + (unless (slot-bound? c 'session) + (set-session! c (make-session #:user (ssh-user c) #:host (ssh-host c))) + (when (ssh-identity c) + (session-set! (ssh-session c) 'identity (ssh-identity c)))) + (let ((s (get-session c))) + (unless (connected? s) + (connect! s) + (when (authenticate-server? s) + (let ((server-auth (authenticate-server s))) + (unless (equal? 'ok server-auth) + (error (format #f "authenticate-server: ~a" server-auth))))) + (let ((user-auth (if (ssh-password c) + (userauth-password s (ssh-password c)) + (userauth-public-key/auto! s)))) + (unless (equal? 'success user-auth) + (error (format #f "userauth: ~a" user-auth))))))) + +(define-method (connection-run (c ) (command )) + (let* ((channel (open-remote-input-pipe (get-session c) command)) + (output (read-lines channel)) + (exit-status (channel-get-exit-status channel))) + (close channel) + (values output exit-status))) + +(define-method (sftp-session (c )) + (unless (slot-bound? c 'sftp-session) + (set-sftp-session! c (make-sftp-session (get-session c)))) + (get-sftp-session c)) + +(define-method (connection-call-with-input-file (c ) (filename ) (proc )) + (call-with-remote-input-file (sftp-session c) filename proc)) + +(define-method (connection-call-with-output-file (c ) (filename ) (proc )) + (call-with-remote-output-file (sftp-session c) filename proc)) + +(define-method (teardown (c )) + (when (slot-bound? c 'session) + (let ((s (get-session c))) + (when (connected? s) + (disconnect! s))))) + + +(define-class () + (parent-connection #:getter get-connection #:init-keyword #:connection) + (become-user #:getter get-become-user #:init-keyword #:become-user) + (become-password #:getter get-become-password #:init-keyworcd #:become-password) + (password-tmp-file #:getter get-password-tmp-file #:setter set-password-tmp-file!)) + +(define-method (setup (c )) + (setup (parent-connection c)) + (when (become-password c) + (let ((tmp-file (first (connection-run (parent-connection c) "mktemp")))) + (connection-call-with-output-file! (parent-connection c) tmp-file (cut write-line (become-password c) <>)) + (set-password-tmp-file! c tmp-file)))) + +(define-method (sudo-command (c )) + (cond + ((and (become-user c) (become-password c))) + (format #f "cat ~a - | sudo -k -S -H -u ~a" (shell-quote (get-password-tmp-file c)) (shell-quote (get-become-user c))) + + ((become-password c) + (format #f "cat ~a - | sudo -k -S -H" (shell-quote (get-password-tmp-file c)))) + + ((become-user c) + (format #f "sudo -k -n -H -u ~a" (shell-quote (get-become-user c)))) + + (else "sudo -k -n -H"))) + +(define-method (teardown (c )) + (when (slot-bound? c 'password-tmp-file) + (connection-run (parent-connection c) (format #f "rm -rf ~a" (shell-quote (get-password-tmp-file c))))) + (teardown (parent-connection c))) + +(define-method (connection-run (c ) (command )) + (let ((command (string-append (sudo-command c) " -- " command))) + (connection-run (parent-connection c) command))) + +(define-method (connection-call-with-input-file (c ) (filename ) (proc )) + (connection-call-with-input-file (parent-connection c) filename proc)) + +(define-method (connection-call-with-output-file (c ) (filename ) (proc )) + (connection-call-with-output-file (parent-connection c) filename proc)) + (define-method (build-command (c ) pwd env prog args) (let ((cmd (chain-when (list (if (sudo? c) "sudo" "env")) (pwd (append _ (list "--chdir" pwd))) @@ -91,38 +165,13 @@ (log-msg 'INFO "Running command: " cmd) cmd)) -(define-method (connection-run (c ) pwd env prog args) - (let* ((cmd (build-command c pwd env prog args)) - (port (open-input-pipe cmd)) - (output (read-lines port)) - (exit-status (status:exit-val (close-pipe port)))) - (values output exit-status))) -(define-method (connection-run (c ) pwd env prog args) - (let* ((cmd (build-command c pwd env prog args)) - (channel (open-remote-input-pipe (get-session c) cmd)) - (output (read-lines channel)) - (exit-status (channel-get-exit-status channel))) - (close channel) - (values output exit-status))) - -(define-method (connection-call-with-input-file (c ) (filename ) (proc )) - (call-with-input-file filename proc)) - -(define-method (connection-call-with-input-file (c ) (filename ) (proc )) - (call-with-remote-input-file (sftp-session c) filename proc)) - -(define-method (connection-call-with-output-file (c ) (filename ) (proc )) - (call-with-output-file filename proc)) - -(define-method (connection-call-with-output-file (c ) (filename ) (proc )) - (call-with-remote-output-file (sftp-session c) filename proc)) (define (call-with-connection c proc) (dynamic-wind - (lambda () (init-connection! c)) + (lambda () (setup c)) (lambda () (proc c)) - (lambda () (close-connection! c)))) + (lambda () (teardown c)))) (define* (keyword-arg kw args #:optional (default #f)) (cond