;;
;; Use `kubed-display-pod' to display a Kuberenetes pod,
;; `kubed-edit-pod' to edit it, `kubed-delete-pods' to delete it, and
-;; `kubed-list-pods' to see a menu of all pods. To update the list of
-;; current pods, use `kubed-update-pods' or `kubed-update-all'.
+;; `kubed-list-pods' to see a menu of all pods. You can create new pods
+;; from YAML or JSON files with `kubed-create-pod'. To update the list
+;; of current pods, use `kubed-update-pods' or `kubed-update-all'.
;;
;; Similar commands are defined for other types of resources as well.
;;
;; current `kubectl' context and namespace. To change your current
;; Kuberenetes context or namespace, use `kubed-use-context' and
;; `kubed-set-namespace'; all resource lists are updated automatically
-;; after you do so.
+;; after you do so. In addition, you can use the minor mode
+;; `kubed-all-namespaces-mode' to see resources from all namespaces.
;;
;; If you want to work with more or different types of Kubernetes
;; resources, use the macro `kubed-define-resource'. This macro defines
;; some common functions and commands that'll get you started with ease.
-;;; TODO:
-
-;; - Add a way to filter resources lists.
-;; - Add `kubed-create-*' commands for more resource types.
-
;;; Code:
(defgroup kubed nil
"Show Kubernetes resources from all namespaces, not just current namespace."
:global t
(message "Kubed \"all namespaces\" mode is now %s"
- (if kubed-all-namespaces-mode "ON" "OFF"))
- (kubed-update-all))
+ (if kubed-all-namespaces-mode "ON" "OFF")))
+;;;###autoload
(defmacro kubed-define-resource (resource &optional properties &rest commands)
"Define Kubernetes RESOURCE with associated PROPERTIES and COMMANDS.
current namespace. The RESOURCEs list buffer uses a dedicated major
mode, `kubed-RESOURCEs-mode', which is also defined by this macro.
- `kubed-update-RESROURCEs': update and repopulate RESOURCEs list.
+- `kubed-create-RESROURCE': create a RESOURCE from a YAML or a JSON file.
PROPERTIES is a list of elements (PROPERTY JSON-PATH WIDTH SORT . ATTRS)
that specify properties of RESOURCEs. PROPERTY is the name of the
-property, as a symbol; JSON-PATH is JSONPath expression that evaluates
+property, as a symbol; JSON-PATH is a JSONPath expression that evaluates
to the value of PROPERTY when applied to the full JSON representation of
a RESOURCE. WIDTH, SORT and ATTRS are optional and can be omitted.
WIDTH is used as the default width of the column corresponding to
(affx-fun (intern (format "kubed-%Ss-affixation" resource)))
(updt-cmd (intern (format "kubed-update-%Ss" resource)))
(list-cmd (intern (format "kubed-list-%Ss" resource)))
- (edit-cmd (intern (format "kubed-%Ss-edit" resource)))
- (slct-cmd (intern (format "kubed-%Ss-get" resource)))
- (othr-cmd (intern (format "kubed-%Ss-get-in-other-window" resource)))
- (desc-cmd (intern (format "kubed-%Ss-display" resource)))
(mark-cmd (intern (format "kubed-%Ss-mark-for-deletion" resource)))
(umrk-cmd (intern (format "kubed-%Ss-unmark" resource)))
(exec-cmd (intern (format "kubed-%Ss-execute" resource)))
- (dlt-cmd (intern (format "kubed-%Ss-delete" resource)))
(list-buf (format "*kubed-%Ss*" resource))
(buf-name (format "*kubed-%S*" resource))
(out-name (format " *kubed-get-%Ss*" resource))
(edt-name (intern (format "kubed-edit-%S" resource)))
(dlt-name (intern (format "kubed-delete-%Ss" resource)))
(mod-name (intern (format "kubed-%Ss-mode" resource)))
- (namespaced t))
- (when (eq (car commands) :namespaced)
- (pop commands)
- (setq namespaced (pop commands)))
+ (crt-name (intern (format "kubed-create-%S" resource)))
+ (crt-spec nil)
+ (namespaced t)
+ (keyword nil))
+
+ ;; Process keyword arguments.
+ (while (keywordp (car commands))
+ (setq keyword (pop commands))
+ (cond
+ ((eq keyword :namespaced) (setq namespaced (pop commands)))
+ ((eq keyword :create) (setq crt-spec (pop commands)))
+ ;; FIXME: Add error for unknown keywords
+ (t (pop commands))))
+
+ ;; Extend `commands' with standard commands.
+ (dolist (c `((get "RET" "Switch to buffer showing description of"
+ (switch-to-buffer
+ ,(if namespaced
+ `(,desc-fun ,resource k8sns)
+ `(,desc-fun ,resource))))
+ (get-in-other-window
+ "o" "Pop to buffer showing description of"
+ (switch-to-buffer-other-window
+ ,(if namespaced
+ `(,desc-fun ,resource k8sns)
+ `(,desc-fun ,resource))))
+ (display "C-o" "Display description of"
+ (display-buffer
+ ,(if namespaced
+ `(,desc-fun ,resource k8sns)
+ `(,desc-fun ,resource))))
+ (edit "e" "Edit"
+ ,(if namespaced
+ `(,edt-name ,resource k8sns)
+ `(,edt-name ,resource)))
+ (delete "D" "Delete"
+ ,(if namespaced
+ `(if k8sns
+ (when (y-or-n-p
+ (format ,(concat "Delete Kubernetes "
+ (symbol-name resource)
+ " `%s' in namespace `%s'?")
+ ,resource k8sns))
+ (,dlt-name (list (list ,resource k8sns))))
+ (when (y-or-n-p
+ (format ,(concat "Delete Kubernetes "
+ (symbol-name resource)
+ " `%s'?")
+ ,resource))
+ (,dlt-name (list ,resource))))
+ `(when (y-or-n-p
+ (format ,(concat "Delete Kubernetes "
+ (symbol-name resource)
+ " `%s'?")
+ ,resource))
+ (,dlt-name (list ,resource)))))))
+ (push c commands))
+
+ ;; Generate code.
`(progn
(defvar ,hist-var nil
,(format "History list for `%S'." read-fun))
(defun ,sure-fun ()
,(format "Populate `%S', if not already populated." list-var)
- (unless (or ,list-var (process-live-p ,proc-var))
- (,updt-cmd)))
+ (unless (or ,list-var (process-live-p ,proc-var)) (,updt-cmd)))
(defun ,updt-cmd ()
,(format "Update `%S'." list-var)
,list-var)
s p)))
nil 'confirm nil ',hist-var default))
- (split (mapcar (lambda (c) (split-string c " ")) (ensure-list choice))))
+ (split (mapcar (lambda (c)
+ (split-string c " "))
+ (ensure-list choice))))
(if multi split (car split)))))
,(if namespaced
`(defun ,cmd-name (,resource &optional k8sns)
- ,(format "Display Kubernetes %S %s." resource (upcase (symbol-name resource)))
+ ,(format "Display Kubernetes %S %s."
+ resource (upcase (symbol-name resource)))
(interactive (if kubed-all-namespaces-mode
(,read-nms "Display")
(list (,read-fun "Display"))))
(display-buffer (,desc-fun ,resource k8sns)))
`(defun ,cmd-name (,resource)
- ,(format "Display Kubernetes %S %s." resource (upcase (symbol-name resource)))
+ ,(format "Display Kubernetes %S %s."
+ resource (upcase (symbol-name resource)))
(interactive (list (,read-fun "Display")))
(display-buffer (,desc-fun ,resource))))
(add-hook 'kubed-update-hook #',updt-cmd)
+ ,(when namespaced
+ `(add-hook 'kubed-all-namespaces-mode-hook
+ (lambda ()
+ (setq ,list-var nil)
+ (,updt-cmd))))
+
,(if namespaced
`(defun ,edt-name (,resource &optional k8sns)
- ,(format "Edit Kubernetes %S %s." resource (upcase (symbol-name resource)))
+ ,(format "Edit Kubernetes %S %s."
+ resource (upcase (symbol-name resource)))
(interactive (if kubed-all-namespaces-mode
(,read-nms "Edit")
(list (,read-fun "Edit"))))
,(if namespaced
`(defun ,dlt-name (,plrl-var)
- ,(format "Delete Kubernetes %S %s." plrl-var (upcase (symbol-name plrl-var)))
+ ,(format "Delete Kubernetes %S %s."
+ plrl-var (upcase (symbol-name plrl-var)))
(interactive (if kubed-all-namespaces-mode
(,read-nms "Delete" nil t)
(list (,read-crm "Delete"))))
(user-error ,(format "You didn't specify %S to delete" plrl-var)))
(if kubed-all-namespaces-mode
(pcase-dolist (`(,name ,space) ,plrl-var)
- (message ,(concat "Deleting Kubernetes " (symbol-name resource) " `%s' in namespace `%s'...") name space)
+ (message ,(concat "Deleting Kubernetes "
+ (symbol-name resource)
+ " `%s' in namespace `%s'...")
+ name space)
(if (zerop (apply #'call-process
kubed-kubectl-executable nil nil nil
- "delete" "--namespace" space ,(symbol-name plrl-var) name))
- (message ,(concat "Deleting Kubernetes " (symbol-name resource) " `%s' in namespace `%s'... Done.") name space)
- (error ,(concat "Failed to delete Kubernetes" (symbol-name resource) " `%s' in namespace `%s'") name space))))
- (message ,(concat "Deleting Kubernetes " (symbol-name plrl-var) " `%s'...") (string-join ,plrl-var "', `"))
+ "delete" "--namespace" space
+ ,(symbol-name plrl-var) name))
+ (message ,(concat "Deleting Kubernetes "
+ (symbol-name resource)
+ " `%s' in namespace `%s'... Done.")
+ name space)
+ (error ,(concat "Failed to delete Kubernetes"
+ (symbol-name resource)
+ " `%s' in namespace `%s'")
+ name space))))
+ (message ,(concat "Deleting Kubernetes "
+ (symbol-name plrl-var)
+ " `%s'...")
+ (string-join ,plrl-var "', `"))
(if (zerop (apply #'call-process
kubed-kubectl-executable nil nil nil
"delete" ,(symbol-name plrl-var) ,plrl-var))
- (message ,(concat "Deleting Kubernetes " (symbol-name plrl-var) " `%s'... Done.") (string-join ,plrl-var "', `"))
- (error ,(concat "Failed to delete Kubernetes" (symbol-name plrl-var) " `%s'") (string-join ,plrl-var "', `"))))
+ (message ,(concat "Deleting Kubernetes "
+ (symbol-name plrl-var)
+ " `%s'... Done.")
+ (string-join ,plrl-var "', `"))
+ (error ,(concat "Failed to delete Kubernetes"
+ (symbol-name plrl-var)
+ " `%s'")
+ (string-join ,plrl-var "', `"))))
`(defun ,dlt-name (,plrl-var)
- ,(format "Delete Kubernetes %S %s." plrl-var (upcase (symbol-name plrl-var)))
+ ,(format "Delete Kubernetes %S %s." plrl-var
+ (upcase (symbol-name plrl-var)))
(interactive (list (,read-crm "Delete")))
(unless ,plrl-var
(user-error ,(format "You didn't specify %S to delete" plrl-var)))
- (message ,(concat "Deleting Kubernetes " (symbol-name plrl-var) " `%s'...") (string-join ,plrl-var "', `"))
+ (message ,(concat "Deleting Kubernetes "
+ (symbol-name plrl-var)
+ " `%s'...")
+ (string-join ,plrl-var "', `"))
(if (zerop (apply #'call-process
kubed-kubectl-executable nil nil nil
"delete" ,(symbol-name plrl-var) ,plrl-var))
- (message ,(concat "Deleting Kubernetes " (symbol-name plrl-var) " `%s'... Done.") (string-join ,plrl-var "', `"))
- (error ,(concat "Failed to delete Kubernetes" (symbol-name plrl-var) " `%s'") (string-join ,plrl-var "', `")))))
+ (message ,(concat "Deleting Kubernetes "
+ (symbol-name plrl-var)
+ " `%s'... Done.")
+ (string-join ,plrl-var "', `"))
+ (error ,(concat "Failed to delete Kubernetes"
+ (symbol-name plrl-var)
+ " `%s'")
+ (string-join ,plrl-var "', `")))))
(defvar-local ,ents-var nil)
(apply #'vector c)))
,ents-var))
- (defun ,dlt-cmd ()
- ,(format "Delete Kubernetes %S at point." resource)
- (interactive "" ,mod-name)
- (if-let ,(if namespaced
- `((k8sent (tabulated-list-get-entry))
- (,resource (aref k8sent 0)))
- `(,resource (tabulated-list-get-id)))
- ,(if namespaced
- `(if-let ((k8sns (and kubed-all-namespaces-mode
- (aref (tabulated-list-get-entry) 1))))
- (when (y-or-n-p (format ,(concat "Delete Kubernetes " (symbol-name resource) " `%s' in namespace `%s'?") ,resource k8sns))
- (,dlt-name (list (list ,resource k8sns))))
- (when (y-or-n-p (format ,(concat "Delete Kubernetes " (symbol-name resource) " `%s'?") ,resource))
- (,dlt-name (list ,resource))))
- `(when (y-or-n-p (format ,(concat "Delete Kubernetes " (symbol-name resource) " `%s'?") ,resource))
- (,dlt-name (list ,resource))))
- (user-error ,(format "No Kubernetes %S at point" resource))))
-
- (defun ,slct-cmd ()
- ,(format "Switch to buffer showing description of Kubernetes %s at point." resource)
- (interactive "" ,mod-name)
- (if-let ,(if namespaced
- `((k8sent (tabulated-list-get-entry))
- (,resource (aref k8sent 0)))
- `(,resource (tabulated-list-get-id)))
- ,(if namespaced
- `(let ((k8sns (when kubed-all-namespaces-mode
- (aref (tabulated-list-get-entry) 1))))
- (switch-to-buffer (,desc-fun ,resource k8sns)))
- `(switch-to-buffer (,desc-fun ,resource)))
- (user-error ,(format "No Kubernetes %S at point" resource))))
-
- (defun ,othr-cmd ()
- ,(format "Pop to buffer showing description of Kubernetes %s at point." resource)
- (interactive "" ,mod-name)
- (if-let ,(if namespaced
- `((k8sent (tabulated-list-get-entry))
- (,resource (aref k8sent 0)))
- `(,resource (tabulated-list-get-id)))
- ,(if namespaced
- `(let ((k8sns (when kubed-all-namespaces-mode
- (aref (tabulated-list-get-entry) 1))))
- (switch-to-buffer-other-window (,desc-fun ,resource k8sns)))
- `(switch-to-buffer-other-window (,desc-fun ,resource)))
- (user-error ,(format "No Kubernetes %S at point" resource))))
-
- (defun ,desc-cmd ()
- ,(format "Display Kubernetes %S at point." resource)
- (interactive "" ,mod-name)
- (if-let ,(if namespaced
- `((k8sent (tabulated-list-get-entry))
- (,resource (aref k8sent 0)))
- `(,resource (tabulated-list-get-id)))
- ,(if namespaced
- `(let ((k8sns (when kubed-all-namespaces-mode
- (aref (tabulated-list-get-entry) 1))))
- (display-buffer (,desc-fun ,resource k8sns)))
- `(display-buffer (,desc-fun ,resource)))
- (user-error ,(format "No Kubernetes %S at point" resource))))
-
- (defun ,edit-cmd ()
- ,(format "Edit Kubernetes %S at point." resource)
- (interactive "" ,mod-name)
- (if-let ,(if namespaced
- `((k8sent (tabulated-list-get-entry))
- (,resource (aref k8sent 0)))
- `(,resource (tabulated-list-get-id)))
- ,(if namespaced
- `(let ((k8sns (when kubed-all-namespaces-mode
- (aref (tabulated-list-get-entry) 1))))
- (,edt-name ,resource k8sns))
- `(,edt-name ,resource))
- (user-error ,(format "No Kubernetes %S at point" resource))))
-
(defun ,mark-cmd ()
,(format "Mark Kubernetes %S at point for deletion." resource)
(interactive "" ,mod-name)
(display-buffer ,dlt-errb))))))))
(user-error ,(format "No Kubernetes %S marked for deletion" plrl-var)))))
+ ,(if crt-spec `(defun ,crt-name . ,crt-spec)
+ `(defun ,crt-name (definition)
+ ,(format "Create Kubernetes %s from definition file DEFINITION."
+ (symbol-name resource))
+ (interactive (list (kubed-read-resource-definition-file-name
+ ,(capitalize (symbol-name resource)))))
+ (kubed-create definition ,(symbol-name resource))))
+
,@(mapcar
(pcase-lambda (`(,suffix ,_key ,desc . ,body))
`(defun ,(intern (format "kubed-%Ss-%S" resource suffix)) ()
(defvar-keymap ,(intern (format "kubed-%Ss-mode-map" resource))
:doc ,(format "Keymap for `%S" mod-name)
- "RET" #',slct-cmd
- "o" #',othr-cmd
- "C-o" #',desc-cmd
+ "A" #'kubed-all-namespaces-mode
"G" #',updt-cmd
"d" #',mark-cmd
"x" #',exec-cmd
"u" #',umrk-cmd
- "e" #',edit-cmd
- "D" #',dlt-cmd
+ "+" #',crt-name
,@(mapcan
(pcase-lambda (`(,suffix ,key ,_desc . ,_body))
(when key
`(let ((c (+ ,i (if kubed-all-namespaces-mode 1 0))))
(funcall ,sorter (aref (cadr l) c) (aref (cadr r) c)))
`(funcall ,sorter (aref (cadr l) ,i) (aref (cadr r) ,i))))
-
t))
(nthcdr 4 p))
res))
(setq tabulated-list-format (,frmt-fun))
(setq tabulated-list-entries #',ents-fun)
(setq tabulated-list-padding 2)
+ (setq-local truncate-string-ellipsis (propertize ">" 'face 'shadow))
(tabulated-list-init-header))
(defun ,buff-fun (,plrl-var &optional buffer frozen)
;;;###autoload (autoload 'kubed-edit-pod "kubed" nil t)
;;;###autoload (autoload 'kubed-delete-pods "kubed" nil t)
;;;###autoload (autoload 'kubed-list-pods "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-pod "kubed" nil t)
(kubed-define-resource pod
((phase ".status.phase" 10) (starttime ".status.startTime" 20))
(dired "C-d" "Start Dired in home directory of first container of"
;;;###autoload (autoload 'kubed-edit-namespace "kubed" nil t)
;;;###autoload (autoload 'kubed-delete-namespaces "kubed" nil t)
;;;###autoload (autoload 'kubed-list-namespaces "kubed" nil t)
-(kubed-define-resource namespace () :namespaced nil)
+;;;###autoload (autoload 'kubed-create-namespace "kubed" nil t)
+(kubed-define-resource namespace ()
+ :namespaced nil
+ :create
+ ((name) "Create Kubernetes namespace with name NAME."
+ (interactive (list (read-string "Create namespace with name: ")))
+ (unless (zerop
+ (call-process
+ kubed-kubectl-executable nil nil nil
+ "create" "namespace" name))
+ (user-error "Failed to create Kubernetes namespace with name `%s'" name))
+ (message "Created Kubernetes namespace with name `%s'." name)
+ (kubed-update-namespaces)))
;;;###autoload (autoload 'kubed-display-persistentvolume "kubed" nil t)
;;;###autoload (autoload 'kubed-edit-persistentvolume "kubed" nil t)
;;;###autoload (autoload 'kubed-delete-persistentvolumes "kubed" nil t)
;;;###autoload (autoload 'kubed-list-persistentvolumes "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-persistentvolume "kubed" nil t)
(kubed-define-resource persistentvolume () :namespaced nil)
;;;###autoload (autoload 'kubed-display-service "kubed" nil t)
;;;###autoload (autoload 'kubed-edit-service "kubed" nil t)
;;;###autoload (autoload 'kubed-delete-services "kubed" nil t)
;;;###autoload (autoload 'kubed-list-services "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-service "kubed" nil t)
(kubed-define-resource service)
;;;###autoload (autoload 'kubed-display-secret "kubed" nil t)
;;;###autoload (autoload 'kubed-edit-secret "kubed" nil t)
;;;###autoload (autoload 'kubed-delete-secrets "kubed" nil t)
;;;###autoload (autoload 'kubed-list-secrets "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-secret "kubed" nil t)
(kubed-define-resource secret
((type ".type" 32) (creationtimestamp ".metadata.creationTimestamp" 20)))
;;;###autoload (autoload 'kubed-edit-job "kubed" nil t)
;;;###autoload (autoload 'kubed-delete-jobs "kubed" nil t)
;;;###autoload (autoload 'kubed-list-jobs "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-job "kubed" nil t)
(kubed-define-resource job
((status ".status.conditions[0].type" 10) (starttime ".status.startTime" 20)))
;;;###autoload (autoload 'kubed-edit-deployment "kubed" nil t)
;;;###autoload (autoload 'kubed-delete-deployments "kubed" nil t)
;;;###autoload (autoload 'kubed-list-deployments "kubed" nil t)
-(kubed-define-resource deployment)
+;;;###autoload (autoload 'kubed-create-deployment "kubed" nil t)
+(kubed-define-resource deployment
+ ((reps ".status.replicas" 4
+ (lambda (l r) (< (string-to-number l) (string-to-number r)))
+ :right-align t)
+ (creationtimestamp ".metadata.creationTimestamp" 20)))
;;;###autoload (autoload 'kubed-display-replicaset "kubed" nil t)
;;;###autoload (autoload 'kubed-edit-replicaset "kubed" nil t)
;;;###autoload (autoload 'kubed-delete-replicasets "kubed" nil t)
;;;###autoload (autoload 'kubed-list-replicasets "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-replicaset "kubed" nil t)
(kubed-define-resource replicaset
((reps ".status.replicas" 4
(lambda (l r) (< (string-to-number l) (string-to-number r)))
;;;###autoload (autoload 'kubed-edit-statefulset "kubed" nil t)
;;;###autoload (autoload 'kubed-delete-statefulsets "kubed" nil t)
;;;###autoload (autoload 'kubed-list-statefulsets "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-statefulset "kubed" nil t)
(kubed-define-resource statefulset
((reps ".status.replicas" 4
(lambda (l r) (< (string-to-number l) (string-to-number r)))
(message "Kubernetes namespace is now `%s'." ns)
(kubed-update-all))
+(defcustom kubed-read-resource-definition-filter-files-by-kind t
+ "Whether to filter file completion candidates by their Kubernetes \"kind\".
+
+If this is non-nil, `kubed-read-resource-definition-file-name' only
+suggests files with the right \"kind\" as completion candidates when you
+call it with non-nil KIND argument. This is useful because you get more
+relevant completions, but it may become slow in directories with many
+large JSON and YAML files, in which case you can set this option to nil."
+ :type 'boolean)
+
+(defun kubed-read-resource-definition-file-name (&optional kind)
+ "Prompt for Kubernetes resource definition file name.
+
+Optional argument KIND is the kind of resource the file should define.
+If `kubed-read-resource-definition-filter-files-by-kind' is non-nil,
+this function suggests only files that define resources of kind KIND as
+completion candidates."
+ (read-file-name
+ (format "%s definition file: " (or kind "Resource")) nil nil t nil
+ (if (and kind kubed-read-resource-definition-filter-files-by-kind
+ (executable-find "grep"))
+ (let ((cache (make-hash-table :test 'equal)))
+ (lambda (f)
+ (or (file-directory-p f)
+ (when-let ((ext (and (string-match "\\.[^.]*\\'" f)
+ (substring f (1+ (match-beginning 0))))))
+ (or (and (member ext '("yaml" "yml"))
+ (pcase (gethash (expand-file-name f) cache 'noval)
+ ('noval
+ (puthash (expand-file-name f)
+ (zerop (call-process
+ "grep" f nil nil
+ (format "^kind: %s$" kind)))
+ cache))
+ (val val)))
+ (and (equal ext "json")
+ (pcase (gethash (expand-file-name f) cache 'noval)
+ ('noval
+ (puthash (expand-file-name f)
+ (zerop (call-process
+ "grep" f nil nil
+ (format "^kind: %s$" kind)))
+ cache))
+ (val val))))))))
+ (lambda (f)
+ (or (file-directory-p f)
+ (when (string-match "\\.[^.]*\\'" f)
+ (member (substring f (1+ (match-beginning 0)))
+ '("yaml" "yml" "json"))))))))
+
;;;###autoload
-(defun kubed-create-pod (definition)
- "Create Kubernetes pod with definition DEFINITION."
- (interactive (list (read-file-name "Pod definition file: ")))
- (message "Creating pod with definition `%s'..." definition)
- (message "Creating pod with definition `%s'... Done. New pod name is `%s'."
- definition (car (process-lines kubed-kubectl-executable
- "create" "-f"
- (expand-file-name definition)
- "-o" "jsonpath={.metadata.name}"))))
-
-(keymap-set kubed-pods-mode-map "+" #'kubed-create-pod)
+(defun kubed-create (definition &optional kind)
+ "Create Kubernetes resource of kind KIND with definition DEFINITION."
+ (interactive
+ (list (kubed-read-resource-definition-file-name)))
+ (message "Creating Kubernetes %s with definition `%s'..." (or kind "resource") definition)
+ (message "Creating Kubernetes %s with definition `%s'... Done. New %s name is `%s'."
+ (or kind "resource") definition (or kind "resource")
+ (car (process-lines kubed-kubectl-executable
+ "create" "-f" (expand-file-name definition)
+ "-o" "jsonpath={.metadata.name}"))))
(defun kubed-pod-containers (pod &optional k8sns)
"Return list of containers in Kubernetes pod POD in namespace K8SNS."