diff --git a/lisp/ein-contents-api.el b/lisp/ein-contents-api.el index 8602255..adb4b71 100644 --- a/lisp/ein-contents-api.el +++ b/lisp/ein-contents-api.el @@ -448,7 +448,10 @@ and content format (one of json, text, or base64)." (defun ein:content-upload (path uploaded-file-path &optional url-or-port) (multiple-value-bind (name type format contents) (ein:get-local-file uploaded-file-path) - (let* ((content (make-ein:$content :url-or-port (or url-or-port (ein:default-url-or-port)) + (let* ((content (make-ein:$content :url-or-port (or url-or-port + (if (atom ein:url-or-port) + ein:url-or-port + (car-safe ein:url-or-port))) :name name :path (concat path "/" name) :raw-content contents)) diff --git a/lisp/ein-core.el b/lisp/ein-core.el index d622443..53f6aaf 100644 --- a/lisp/ein-core.el +++ b/lisp/ein-core.el @@ -48,18 +48,21 @@ This will be used for completion. So put your IPython servers. You can connect to servers not in this list \(but you will need to type every time)." - :type '(repeat (choice (integer :tag "Port number" 8888) - (string :tag "URL" "http://127.0.0.1:8888"))) + :type '(repeat (choice (integer :tag "Port number" 8888))) :group 'ein) (defcustom ein:default-url-or-port nil - "Default URL or port. This should be your main IPython -Notebook server." - :type '(choice (integer :tag "Port number" 8888) - (string :tag "URL" "http://127.0.0.1:8888") - (const :tag "First value of `ein:url-or-port'" nil)) + "Should just be first element of `ein:url-or-port'." + :initialize 'custom-initialize-default + :set (lambda (symbol value) + (set-default symbol value) + (when value + (push value ein:url-or-port))) + :type '(choice (integer :tag "Port number" 8888)) :group 'ein) +(make-obsolete-variable 'ein:default-url-or-port 'ein:url-or-port "0.17.0" 'set) + (defcustom ein:filename-translations nil "Convert file paths between Emacs and Python process. @@ -108,9 +111,6 @@ pair of TO-PYTHON and FROM-PYTHON." ;;; Configuration getter -(defun ein:default-url-or-port () - (or ein:default-url-or-port (car ein:url-or-port) 8888)) - (defun ein:version (&optional interactively copy-to-kill) "Return a longer version string. With prefix argument, copy the string to kill ring. diff --git a/lisp/ein-k8s.el b/lisp/ein-k8s.el index 167acdc..d95ac18 100644 --- a/lisp/ein-k8s.el +++ b/lisp/ein-k8s.el @@ -135,6 +135,19 @@ (error (ein:log 'info "ein:k8s-p %s" (error-message-string err)) nil)))))) +(defsubst ein:k8s-in-cluster (addr) + "Is ein client inside the k8s cluster?" + (if-let ((ip-command (executable-find "ip"))) + (with-temp-buffer + (apply #'call-process ip-command nil t nil + (split-string (format "n ls %s" addr))) + (goto-char (point-min)) + (search-forward addr nil t)) + ;; hack if ip command not found + (string= "minikube" + (alist-get 'name (kubernetes-state-current-context + (kubernetes-state)))))) + (defun ein:k8s-service-url-or-port () (-when-let* ((k8s-p (ein:k8s-p)) (service (ein:k8s-get-service)) @@ -146,6 +159,16 @@ (when (string= (alist-get 'type address) "InternalIP") (alist-get 'address address))) addresses))) - (ein:url (concat host-ip ":" (number-to-string nodePort))))) + (if (ein:k8s-in-cluster host-ip) + (ein:url (concat "http://" host-ip ":" (number-to-string nodePort))) + (when-let ((ips (kubernetes-kubectl-await-command ingress + (lambda (item) + (-let* (((&alist 'status + (&alist 'loadBalancer + (&alist 'ingress + [(&alist 'ip)]))) + item)) + ip))))) + (ein:url (concat "http://" (car ips))))))) (provide 'ein-k8s) diff --git a/lisp/ein-notebooklist.el b/lisp/ein-notebooklist.el index 14de211..0251d02 100644 --- a/lisp/ein-notebooklist.el +++ b/lisp/ein-notebooklist.el @@ -183,7 +183,9 @@ This function adds NBLIST to `ein:notebooklist-map'." when (destructuring-bind (&key password url token &allow-other-keys) (ein:json-read-from-string line) - (prog1 (equal (ein:url url) url-or-port) + (prog1 (or (equal (ein:url url) url-or-port) + (equal (url-host (url-generic-parse-url url)) + "0.0.0.0")) (setq password0 password) ;; t or :json-false (setq token0 token))) return (list password0 token0)) @@ -191,8 +193,8 @@ This function adds NBLIST to `ein:notebooklist-map'." (defun ein:crib-running-servers () "Shell out to jupyter for running servers." - (cl-loop for line in - (nconc + (nconc + (cl-loop for line in (apply #'ein:jupyter-process-lines nil ein:jupyter-server-command (split-string @@ -200,10 +202,11 @@ This function adds NBLIST to `ein:notebooklist-map'." (aif ein:jupyter-server-use-subcommand (concat it " ") "") "list" "--json"))) - (aif (ein:k8s-service-url-or-port) (list it))) - collecting (destructuring-bind - (&key url &allow-other-keys) - (ein:json-read-from-string line) (ein:url url)))) + collecting (destructuring-bind + (&key url &allow-other-keys) + (ein:json-read-from-string line) + (ein:url url))) + (aif (ein:k8s-service-url-or-port) (list it)))) (defun ein:notebooklist-token-or-password (url-or-port) "Return token or password for URL-OR-PORT. @@ -220,22 +223,24 @@ Return nil if unclear what, if any, authentication applies." (t nil))))) (defun ein:notebooklist-ask-url-or-port () + (call-interactively #'ein:k8s-select-context) (let* ((default (ein:url (aif (ein:get-notebook) (ein:$notebook-url-or-port it) (aif ein:%notebooklist% - (ein:$notebooklist-url-or-port it) - (ein:default-url-or-port))))) + (ein:$notebooklist-url-or-port it))))) (url-or-port-list (-distinct (mapcar #'ein:url - (append (list default) - ein:url-or-port + (append (when default + (list default)) + (if (atom ein:url-or-port) + (list ein:url-or-port) + ein:url-or-port) (ein:crib-running-servers))))) - (url-or-port (let ((ido-report-no-match nil) - (ido-use-faces nil)) + (url-or-port (let (ido-report-no-match ido-use-faces) (ein:completing-read "URL or port: " url-or-port-list nil nil nil nil - default)))) + (car-safe url-or-port-list))))) (ein:url url-or-port))) (defun ein:notebooklist-open* (url-or-port &optional path resync restore-point-p callback errback) @@ -430,7 +435,9 @@ This function is called via `ein:notebook-after-rename-hook'." "Upon notebook-open, rename the notebook, then funcall CALLBACK." (interactive (let* ((url-or-port (or (ein:get-url-or-port) - (ein:default-url-or-port))) + (if (atom ein:url-or-port) + ein:url-or-port + (car-safe ein:url-or-port)))) (kernelspec (ein:completing-read "Select kernel: " (ein:list-available-kernels url-or-port) @@ -782,8 +789,7 @@ or even this (if you want fast Emacs start-up):: ;; load notebook list if Emacs is idle for 3 sec after start-up (run-with-idle-timer 3 nil #'ein:notebooklist-load) -You should setup `ein:url-or-port' or `ein:default-url-or-port' -in order to make this code work. +You should setup `ein:url-or-port' in order to make this code work. See also: `ein:connect-to-default-notebook', `ein:connect-default-notebook'." @@ -838,7 +844,6 @@ and the url-or-port argument of ein:notebooklist-open*." ,(lambda (buffer url-or-port) (pop-to-buffer buffer)) ,(if current-prefix-arg (ein:notebooklist-ask-user-pw-pair "Cookie name" "Cookie content")))) (unless callback (setq callback (lambda (buffer url-or-port)))) - (when cookie-plist (let* ((parsed-url (url-generic-parse-url (file-name-as-directory url-or-port))) (domain (url-host parsed-url)) @@ -846,7 +851,6 @@ and the url-or-port argument of ein:notebooklist-open*." (cl-loop for (name content) on cookie-plist by (function cddr) for line = (mapconcat #'identity (list domain "FALSE" (car (url-path-and-query parsed-url)) (if securep "TRUE" "FALSE") "0" (symbol-name name) (concat content "\n")) "\t") do (write-region line nil (request--curl-cookie-jar) 'append)))) - (let ((token (ein:notebooklist-token-or-password url-or-port))) (cond ((null token) ;; don't know (ein:notebooklist-login--iteration url-or-port callback nil nil -1 nil)) @@ -855,20 +859,6 @@ and the url-or-port argument of ein:notebooklist-open*." (ein:notebooklist-open* url-or-port nil nil nil callback nil)) (t (ein:notebooklist-login--iteration url-or-port callback nil token 0 nil))))) -;;;###autoload -(defun ein:cluster-login (callback) - "Deal with security before main entry of ein:notebooklist-open*. - -CALLBACK takes two arguments, the buffer created by ein:notebooklist-open--success -and the url-or-port argument of ein:notebooklist-open*." - (interactive `(,(lambda (buffer url-or-port) (pop-to-buffer buffer)))) - (unless callback (setq callback #'ignore)) - (call-interactively #'ein:k8s-select-context) - (if-let ((url-or-port (ein:k8s-service-url-or-port))) - url-or-port - (error "ein:cluster-login: No jupyter node found for %s" - (alist-get 'name (kubernetes-state-current-context (kubernetes-state)))))) - (defun ein:notebooklist-login--parser () (goto-char (point-min)) (list :bad-page (re-search-forward "