Vietnamen’s Weblog

Time, Chances, Diligence, Intelligence: which is the most important?

Soạn thảo file từ xa (emacs + ssh)

leave a comment »

Emacs là một multi-purpose và extremely powerful editor + IDE. Lần này bài viết sẽ giới thiệu TRAMP (Transparent Remote file Access, Multiple Protocol)

TRAMP cho phép ta khai báo: (1) giao thức để kết nối tới remotehost (e.g. ssh), (2) giao thức để truyền tải file qua lại với remotehost (e.g. scp), (3) … từ đó bạn có thể edit 1 remote file giống như đang làm đối với 1 local file.

TRAMP bây giờ là một phần của XEmacs và GNU Emacs. Vì thế, step (I) có thể skip nếu GNU Emacs version > 22.1, XEmacs > …. Để kiểm tra version hiện có của TRAMP, trong Emacs, dùng lệnh

M-x tramp-version

Nếu cũ so với phiên bản mới nhất, ta có thể tiến hành Step (I).

(I) [Có thể skip nếu GNU Emacs version > 22.1] Phiên bản tramp đi kèm với Ubuntu (sudo aptitude) cũ, không nên dùng. Nên download version mới nhất về, sau đó bạn unzip (loại bỏ phần chỉ version trong tên thư mục cho đơn giản), move vào thư mục chia sẻ của emacs, e.g. ~/.emacs.d/share/

# mv tramp ~/.emacs.d/share
cd ~/.emacs.d/share/tramp
./configure –with-contrib
make
sudo make install

Các file cần thiết sẽ được chép vào thư mục mặc định là /usr/local/share/emacs/site-lisp/

(II) Sau đó, edit file ~/.emacs để cấu hình emacs load tramp

;; Remote file editing via ssh
(require 'tramp)
(setq tramp-default-method "ssh")

(III) Sau đó, có thể run emacs và open remoting file để edit.

C-x C-f /user@remotehost:/path/to/file

hoặc (nếu đã có cài đặt username mặc định – đọc thêm phần sau)

C-x C-f /remotehost:filename

Đi sâu vào TRAMP

Để có thể edit được remote file, đường dẫn mà TRAMP sử dụng là

/method:user@remotehost:/path/to/file

Với method là một inline method sẽ được giới thiệu, user@remotehost dùng để xác định người dùng và địa chỉ remote host để kết nối tới.

Giao thức kết nối tới remotehost (inline method)

Giao thức dùng để kết nối tới remote machine, thì được gọi là inline methods (SSH, RSH, Telnet …). Tuỳ vào remote host, mà ta chọn method phù hợp.Nếu 1 giao thức hay được dùng, ta có làm đơn giản hoá đường dẫn

/user@remotehost:/path/to/file

bằng cách khai báo nó qua biến tramp-default-method.

(setq tramp-default-method "rsh")

Trong phần giới thiệu nhanh ở trên, SSH là giao thức được dùng mặc định. Ngoài ra có nhiều option khác:

– Nếu với một user luôn dùng 1 giao thức cố định, cho dù kết nối tới remote host nào, ta dùng tramp-default-method-alist

Ví dụ: user “john” phải dùng ssh, user lily phải dùng rsync,

(add-to-list 'tramp-default-method-alist '("" "john" "ssh"))
(add-to-list 'tramp-default-method-alist '("lily" "" "rsync"))

– Khi mở file, bạn phải chỉ định username và host-name, nếu bạn là người dùng duy nhất, có thể username sẽ không thay đổi, để làm mặc định, ta dùng (cách này sẽ trở nên lỗi thời nhưng vẫn dùng được)

(setq tramp-default-user "username")

Nếu muốn chỉ định cả username lẫn hostname; ví dụ: user “john” ở host-name “binf.network.com”, ta sẽ thêm vào

(setq tramp-default-user "username"
           tramp-default-host "target-hostname")

– – Giải pháp khác là

add-to-list 'tramp-default-user-alist
        '("ssh" ".*\\.binf.network.com\\'" "john"))

NOTE: Nếu default username đã được chỉ định ở đâu đó khác, TRAMP không thể biết được và dẫn đến kết nối luôn thất bại. Giải pháp là  dùng nil

(add-to-list 'tramp-default-user-alist
       '("ssh" "\\`here\\.somewhere\\.else\\'" nil))

Sau đó, khi kết nối dùng thông tin default, ta dùng: C-x C-f /ssh::

Giao thức truyền tải file

Sau khi kết nối tới remotehost, bạn có thể đọc file và edit nó. Việc save file trở lại remote host có thể (1) dùng chung kết nối (giao thức) đang có (inline method); (2) tạo một kết nối mới chỉ dùng để truyền tải file, gọi là external method.

Dùng external method chỉ hiệu quả hơn đối với file kích thước lớn. Khuyến khích bạn nên dùng inline methods. Nếu dùng external methods, nên cấu hình sao cho lúc save file thì nó không đòi hỏi password.

+ Edit file dưới quyền user khác

Ta dùng inline method su hoặc sudo. Cả hai đều không thực sự kết nối tới một remotehost nào, mà chỉ sử dụng su program để edit file dưới quyền user khác (hoặc root với sudo).

(add-to-list 'tramp-default-method-alist
                  '("\\`localhost\\'" "\\`root\\'" "su"))

Sau đó, bạn dùng:

C-x C-f /sudo:localhost:/path/to/file

hay (nếu không có dòng lệnh trên)

C-x C-f /sudo:root@localhost:/path/to/file

Multi-hops connection (pass firewalls or proxy servers)

Việc cài đặt và cấu hình đề cập ở các phần trên chỉ giúp ích khi remoting file nằm ở trên machine mà bạn có thể kết nối trực tiếp. Tuy nhiên, thực tế là đôi khi bạn cần vượt qua một hay nhiều firewalls hay proxies trước khi có thể kết nối trực tiếp tới machine chứa file cần edit.

Ví dụ: Bạn login vào máy A (đóng vai trò proxy hay firewall) với tư cách user Auser, sau đó, từ máy A, bạn sẽ tiếp tục login vào máy B với tư cách Buser. Lúc này máy B là máy chứa file cần edit.

Để vưọt qua firewall hay proxy server, trước đây có giao thức “multi” nay đã lỗi thời với TRAMP 2.1.15.  Bạn nên dùng gateway method hay inline method được chỉ định thông qua variable tramp-default-proxies-alist

Gateway method là các phương thức dùng để vượt qua firewall hay proxy, không phải để truy cập một remote host trực tiếp.  Giao thức đo bao gồm tunnelsocks. Nó hỗ trợ việc khai báo username và password. Ở đây, ta sẽ dùng inline method, ví dụ ssh.

Ví dụ: nfat là tên bạn muốn gán cho remote host (nfat.company.com) bạn cần kết nối tới, thông tin để kết nối vào nfat là mynfat@nfat.machine.com. Tuy nhiên, account trên chỉ dùng được khi connect từ proxy host1.com. Như vậy, muốn kết nối tới nfat, bạn phải login được vào máy host1.com. Thông tin cho phép bạn truy cập vào host1.com là với username là user1. Oái oăm thay, muốn login vào host1.com bạn cần phải login từ máy gateway.com. Máy gateway.com thì có thể login từ bất kì đâu với account commonusser. Các bước như sau

(add-to-list 'tramp-default-proxies-alist
             '("nfat" nil "/ssh:mynfat@nfat.company.com:/"))
(add-to-list 'tramp-default-proxies-alist
             '("nfat\\.company\\.com" nil "/ssh:user1@host1.com:/"))

(add-to-list 'tramp-default-proxies-alist
             '("host1\\.com" nil "/ssh:commonuser@gateway.com:"))

Sau đó, chỉ việc dùng: C-x C-f /nfat:

NOTE: ‘nil’ nghĩa là “always match”.

NOTE: Please note the order of the code. add-to-list adds elements at the beginning of a list. Therefore, most relevant rules must be added last.

Proxy hosts can be cascaded. If there is another host called ‘jump.your.domain’, which is the only one in your local domain who is allowed connecting ‘bastion.your.domain’, you can add another rule:

     (add-to-list 'tramp-default-proxies-alist
                  '("\\`bastion\\.your\\.domain\\'"
                    "\\`bird\\'"
                    "/ssh:jump.your.domain:"))

Quản lí file

Mỗi khi soạn thảo remote file, TRAMP sẽ tạo 1 local copy, lưu ở /tmp folder, mỗi khi save file, bản local copy sẽ đồng thời được copy trở lại lên remote host.

Remote version control

TRAMP còn hỗ trợ remote version control. Nếu remote file đang edit là được quản lí bởi RCS hay CVS; bạn có thể commit dùng lệnh C-x v v .

Chỉnh sửa TRAMP

(custom-set-variables
 '(tramp-verbose 1)
 '(tramp-default-method "rsync")
 '(tramp-auto-save-directory "~/tmp/"))
(custom-set-faces)
(require 'tramp)
(add-to-list 'tramp-default-proxies-alist
	     (list "gluk" "root" "/ssh:alex@gluk:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "plato.chalkface.com" "root" "/ssh:alex@plato.chalkface.com:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "appserver" "sasa" "/ssh:root@appserver:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "www.chalkface.com" "root" "/ssh:alex@www.chalkface.com:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "dimon-notebook" "root" "/ssh:alex@dimon-notebook:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "mir" "igleons" "/ssh:root@mir:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "appserver" "sergej" "/sudo:root@appserver:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "appserver" "max" "/ssh:root@appserver:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "miles" "root" "/ssh:admin2@miles:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "g2.chalkface.com" "root" "/ssh:alex@g2.chalkface.com:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "mail2.virt.halogen.kharkov.ua" "root" "/ssh:alex@halogen.kharkov.ua:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "appserver" "dixon" "/ssh:root@appserver:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "appserver" "max" "/ssh:root@appserver:"))

(add-to-list 'tramp-default-proxies-alist
	     (list "appserver" "av" "/ssh:root@appserver:"))

;; (defmacro require-soft (feature &optional file)
;;   "*Try to require FEATURE, but don't signal an error if `require' fails."
;;   `(require ,feature ,file 'noerror))

;; (when (require-soft 'sudo)
;;   (defun sudo-before-save-hook ()
;;     (set (make-local-variable 'sudo:file) (buffer-file-name))
;;     (when sudo:file
;;       (unless(file-writable-p sudo:file)
;;         (set (make-local-variable 'sudo:old-owner-uid)
;;           (nth 2 (file-attributes sudo:file)))
;;         (when (numberp sudo:old-owner-uid)
;;           (unless (= (user-uid) sudo:old-owner-uid)
;;             (when (y-or-n-p
;;                     (format "File %s is owned by %s, save it with sudo? "
;;                       (file-name-nondirectory sudo:file)
;;                       (user-login-name sudo:old-owner-uid)))
;;               (sudo-chown-file (int-to-string (user-uid))
;;                 (sudo-quoting sudo:file))
;;               (add-hook 'after-save-hook
;;                 (lambda ()
;;                   (sudo-chown-file (int-to-string sudo:old-owner-uid)
;;                     (sudo-quoting sudo:file))
;;                   (if sudo-clear-password-always
;;                     (sudo-kill-password-timeout)))
;;                 nil   ;; not append
;;                 t           ;; buffer local hook
;;                 )))))))
;;   (add-hook 'before-save-hook 'sudo-before-save-hook))

===========================================================================
References:

  1. http://codesnippets.joyent.com/posts/show/366
  2. http://jeremy.zawodny.com/blog/archives/000983.html
  3. http://www.gnu.org/software/tramp/ (TRAM User Manual)
  4. http://www.emacswiki.org/emacs/TrampMode
  5. http://www.linux-mag.com/id/1527
  6. http://www.gnu.org/software/emacs/manual/html_mono/tramp.html (TRAM User Manual)

SSHFS

Một giải pháp thay vì dùng TRAMP là mount remote partition thành một local folder thông qua SSHFS.

Cách này sẽ trở nên lỗi thời

Written by vietnamen

Tháng Bảy 3, 2009 lúc 10:25 sáng

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s

%d bloggers like this: