├── .gitignore ├── CONTRIBUTING.md ├── Cask ├── ChangeLog.md ├── LICENSE ├── Makefile ├── README.md ├── test ├── test-helper.el ├── timonier-k8s-test.el └── timonier-version-test.el ├── timonier-0.1.0.png ├── timonier-custom.el ├── timonier-io.el ├── timonier-k8s.el ├── timonier-mode.el ├── timonier-utils.el ├── timonier-version.el └── timonier.el /.gitignore: -------------------------------------------------------------------------------- 1 | # Emacs 2 | *~ 3 | 4 | # Emacslisp 5 | .cask 6 | elpa 7 | .projectile 8 | *.elc 9 | test/sandbox/ 10 | 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | If you discover issues, have ideas for improvements or new features, or 4 | want to contribute a new module, please report them to the 5 | [issue tracker][1] of the repository or submit a pull request. Please, 6 | try to follow these guidelines when you do so. 7 | 8 | ## Issue reporting 9 | 10 | * Check that the issue has not already been reported. 11 | * Check that the issue has not already been fixed in the latest code 12 | (a.k.a. `develop`). 13 | * Be clear, concise and precise in your description of the problem. 14 | * Open an issue with a descriptive title and a summary in grammatically correct, 15 | complete sentences. 16 | * Include any relevant code to the issue summary. 17 | 18 | ## Pull requests 19 | 20 | * Use a topic branch to easily amend a pull request later, if necessary. 21 | * Use the same coding conventions as the rest of the project. 22 | * Verify your Emacs Lisp code with `checkdoc`. 23 | * Open a [pull request][4] that relates to *only* one subject with a clear title 24 | and description in grammatically correct, complete sentences. (Target branch 25 | must be `develop` branch). 26 | 27 | 28 | [1]: https://github.com/nlamirault/ripgrep.el/issues 29 | [2]: http://gun.io/blog/how-to-github-fork-branch-and-pull-request 30 | [3]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html 31 | [4]: https://help.github.com/articles/using-pull-requests 32 | -------------------------------------------------------------------------------- /Cask: -------------------------------------------------------------------------------- 1 | ;;; Timonier -- Cask file 2 | 3 | ;; Copyright (C) 2016 Nicolas Lamirault 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 6 | ;; you may not use this file except in compliance with the License. 7 | ;; You may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ;; See the License for the specific language governing permissions and 15 | ;; limitations under the License. 16 | 17 | (source "melpa" "http://melpa.org/packages/") 18 | (source "gnu" "http://elpa.gnu.org/packages/") 19 | 20 | (package-file "timonier.el") 21 | (files "timonier*.el" (:exclude ".dir-locals.el")) 22 | 23 | ;; Development 24 | (development 25 | (depends-on "request" "0.2.0") 26 | (depends-on "hydra" "0.13.6") 27 | (depends-on "all-the-icons" "2.0.0") 28 | (depends-on "s" "1.11.0") 29 | (depends-on "dash" "2.12.1") 30 | (depends-on "ansi" "0.4.0") 31 | (depends-on "pkg-info" "0.5.0") 32 | (depends-on "ert") 33 | (depends-on "ert-runner" "0.6.4") 34 | (depends-on "undercover" "0.6.0")) 35 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Timonier ChangeLog 2 | 3 | # Version 0.1.0 4 | 5 | - Setup unit tests (use [ert-runner][] and [overseer][]) 6 | - Init project 7 | 8 | [ert-runner]: https://github.com/rejeep/ert-runner.el 9 | [overseer]: https://github.com/tonini/overseer.el 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 Nicolas Lamirault 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | APP = timonier 17 | 18 | SHELL = /bin/bash 19 | 20 | EMACS ?= emacs 21 | EMACSFLAGS = -L . 22 | CASK = cask 23 | VAGRANT = vagrant 24 | 25 | VERSION=$(shell \ 26 | grep Version timonier.el \ 27 | |awk -F':' '{print $$2}' \ 28 | |sed -e "s/[^0-9.]//g") 29 | 30 | PACKAGE_FOLDER=$(APP)-$(VERSION) 31 | ARCHIVE=$(PACKAGE_FOLDER).tar 32 | 33 | ELS = $(shell find . -name "*.el") 34 | OBJECTS = $(ELS:.el=.elc) 35 | 36 | NO_COLOR=\033[0m 37 | OK_COLOR=\033[32;01m 38 | ERROR_COLOR=\033[31;01m 39 | WARN_COLOR=\033[33;01m 40 | 41 | all: help 42 | 43 | help: 44 | @echo -e "$(OK_COLOR)==== $(APP) [$(VERSION)]====$(NO_COLOR)" 45 | @echo -e "$(WARN_COLOR)- init$(NO_COLOR) : initialize development environment" 46 | @echo -e "$(WARN_COLOR)- build$(NO_COLOR) : build project" 47 | @echo -e "$(WARN_COLOR)- test$(NO_COLOR) : launch unit tests" 48 | @echo -e "$(WARN_COLOR)- clean$(NO_COLOR) : cleanup" 49 | @echo -e "$(WARN_COLOR)- package$(NO_COLOR) : packaging" 50 | 51 | init: 52 | @echo -e "$(OK_COLOR)[$(APP)] Initialize environment$(NO_COLOR)" 53 | @$(CASK) --dev install 54 | 55 | elpa: 56 | @echo -e "$(OK_COLOR)[$(APP)] Build$(NO_COLOR)" 57 | @$(CASK) install 58 | @$(CASK) update 59 | @touch $@ 60 | 61 | .PHONY: build 62 | build : elpa $(OBJECTS) 63 | 64 | test: build 65 | @echo -e "$(OK_COLOR)[$(APP)] Unit tests$(NO_COLOR)" 66 | @$(CASK) exec ert-runner 67 | 68 | .PHONY: virtual-test 69 | virtual-test: check-env 70 | @$(VAGRANT) up 71 | @$(VAGRANT) ssh -c "source /tmp/.emacs-timonier.rc && make -C /vagrant EMACS=$(EMACS) clean init test" 72 | 73 | .PHONY: virtual-clean 74 | virtual-clean: 75 | @$(VAGRANT) destroy 76 | 77 | .PHONY: clean 78 | clean : 79 | @echo -e "$(OK_COLOR)[$(APP)] Cleanup$(NO_COLOR)" 80 | @rm -fr $(OBJECTS) elpa $(APP)-pkg.el $(APP)-pkg.elc $(ARCHIVE).gz 81 | 82 | reset : clean 83 | @rm -rf .cask 84 | 85 | pkg-file: 86 | $(CASK) pkg-file 87 | 88 | pkg-el: pkg-file 89 | $(CASK) package 90 | 91 | package: clean pkg-el 92 | @echo -e "$(OK_COLOR)[$(APP)] Packaging$(NO_COLOR)" 93 | cp dist/$(ARCHIVE) . 94 | gzip $(ARCHIVE) 95 | rm -fr dist 96 | 97 | %.elc : %.el 98 | @$(CASK) exec $(EMACS) --no-site-file --no-site-lisp --batch \ 99 | $(EMACSFLAGS) \ 100 | -f batch-byte-compile $< 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Timonier 2 | 3 | [![Coverage Status](https://coveralls.io/repos/nlamirault/timonier/badge.png?branch=master)](https://coveralls.io/r/nlamirault/timonier?branch=master) 4 | 5 | Master : 6 | * [![MELPA Stable](https://stable.melpa.org/packages/timonier-badge.svg)](https://stable.melpa.org/#/timonier) 7 | * [![Circle CI](https://circleci.com/gh/nlamirault/timonier/tree/master.svg?style=svg)](https://circleci.com/gh/nlamirault/timonier/tree/master) 8 | 9 | Develop: 10 | * [![Melpa Status](https://melpa.org/packages/timonier-badge.svg)](https://melpa.org/#/timonier) 11 | * [![Circle CI](https://circleci.com/gh/nlamirault/timonier/tree/develop.svg?style=svg)](https://circleci.com/gh/nlamirault/timonier/tree/develop) 12 | 13 | ``timonier`` is an Emacs frontend for a [Kubernetes][] cluster. 14 | 15 | 16 | ## Installation 17 | 18 | The recommended way to install ``timonier`` is via [MELPA][]: 19 | 20 | M-x package-install timonier 21 | 22 | or [Cask][]: 23 | 24 | (depends-on "timonier") 25 | 26 | 27 | ## Usage 28 | 29 | * Setup the Kubernetes proxy endpoint: 30 | 31 | (setq timonier-k8s-proxy "http://localhost:8001") 32 | 33 | * Display the dashboard: 34 | 35 | M-x timonier-k8s 36 | 37 | * In the buffer: 38 | 39 | Launch the timonier menu using the key : C-c C-k 40 | 41 | Keybinding | Description 42 | ---------------------|------------------------------------------------------------ 43 | g | go to the news pod 44 | h | go to the previous pod 45 | P | describe current pod 46 | k | go to the next service 47 | l | go to the previous service 48 | S | describe the current service 49 | i | go to the next node 50 | j | go to the previous node 51 | N | describe the current service 52 | q | quit 53 | 54 | 55 | ![Timonier](timonier-0.1.0.png) 56 | 57 | 58 | ## Development 59 | 60 | ### Cask 61 | 62 | ``timonier`` use [Cask][] for dependencies management. Install it and 63 | retrieve dependencies : 64 | 65 | $ curl -fsSkL https://raw.github.com/cask/cask/master/go | python 66 | $ export PATH="$HOME/.cask/bin:$PATH" 67 | $ cask 68 | 69 | 70 | ### Testing 71 | 72 | * Launch unit tests from shell 73 | 74 | $ make clean test 75 | 76 | * Using [overseer][] : 77 | 78 | Keybinding | Description 79 | ---------------------|------------------------------------------------------------ 80 | C-c , t | launch unit tests from buffer 81 | C-c , b | launch unit tests 82 | C-c , g | launch unit tests with tag (backend, ...) 83 | 84 | * Tips: 85 | 86 | If you want to launch a single unit test, add a specify tag : 87 | 88 | ```lisp 89 | (ert-deftest test-foobar () 90 | :tags '(current) 91 | ``` 92 | 93 | And launch it using : C-c , g and specify tag : *current* 94 | 95 | 96 | ## Support / Contribute 97 | 98 | See [here](CONTRIBUTING.md) 99 | 100 | 101 | ## Changelog 102 | 103 | A changelog is available [here](ChangeLog.md). 104 | 105 | 106 | ## License 107 | 108 | See [LICENSE](LICENSE). 109 | 110 | 111 | ## Contact 112 | 113 | Nicolas Lamirault 114 | 115 | 116 | 117 | 118 | [badge-license]: https://img.shields.io/badge/license-GPL_2-green.svg?style=flat 119 | [LICENSE]: https://github.com/nlamirault/ripgrep.el/blob/master/LICENSE 120 | 121 | [GNU Emacs]: https://www.gnu.org/software/emacs/ 122 | [MELPA]: https://melpa.org/ 123 | [Cask]: http://cask.github.io/ 124 | [Issue tracker]: https://github.com/nlamirault/ripgrep.el/issues 125 | 126 | [overseer]: https://github.com/tonini/overseer.el 127 | 128 | [ag]: https://github.com/ggreer/the_silver_searcher 129 | [pt]: https://github.com/monochromegane/the_platinum_searcher 130 | [sift]: https://sift-tool.org/ 131 | [ripgrep]: https://github.com/BurntSushi/ripgrep 132 | -------------------------------------------------------------------------------- /test/test-helper.el: -------------------------------------------------------------------------------- 1 | ;; test-helper.el --- Test helpers for Timonier 2 | 3 | ;; Copyright (C) 2016 Nicolas Lamirault 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 6 | ;; you may not use this file except in compliance with the License. 7 | ;; You may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ;; See the License for the specific language governing permissions and 15 | ;; limitations under the License. 16 | 17 | ;;; Commentary: 18 | 19 | ;;; Code: 20 | 21 | (require 'ansi) 22 | (require 'cl) ;; http://emacs.stackexchange.com/questions/2864/symbols-function-definition-is-void-cl-macroexpand-all-when-trying-to-instal 23 | (require 'ert) 24 | (require 'f) 25 | (require 'undercover) 26 | 27 | (setq debugger-batch-max-lines (+ 50 max-lisp-eval-depth) 28 | debug-on-error t) 29 | 30 | (defvar timonier--username (getenv "HOME")) 31 | 32 | (defconst timonier-testsuite-dir 33 | (f-parent (f-this-file)) 34 | "The testsuite directory.") 35 | 36 | (defconst timonier-source-dir 37 | (f-parent timonier-testsuite-dir) 38 | "The timonier.el source directory.") 39 | 40 | (defconst timonier-sandbox-path 41 | (f-expand "sandbox" timonier-testsuite-dir) 42 | "The sandbox path for timonier.") 43 | 44 | (defun cleanup-load-path () 45 | "Remove home directory from 'load-path." 46 | (message (ansi-green "[timonier] Cleanup path")) 47 | (mapc #'(lambda (path) 48 | (when (string-match (s-concat timonier--username "/.emacs.d") path) 49 | (message (ansi-yellow "Suppression path %s" path)) 50 | (setq load-path (delete path load-path)))) 51 | load-path) 52 | (add-to-list 'load-path timonier-source-dir)) 53 | 54 | (defun load-unit-tests (path) 55 | "Load all unit test from PATH." 56 | (message (ansi-green "[timonier] Execute unit tests %s" 57 | path)) 58 | (dolist (test-file (or argv (directory-files path t "-test.el$"))) 59 | (load test-file nil t))) 60 | 61 | 62 | (defun load-library (file) 63 | "Load current library from FILE." 64 | (let ((path (s-concat timonier-source-dir file))) 65 | (message (ansi-yellow "[timonier] Load library from %s" path)) 66 | (undercover "*.el" (:exclude "*-test.el")) 67 | (require 'timonier path))) 68 | 69 | 70 | (defmacro with-test-sandbox (&rest body) 71 | "Evaluate BODY in an empty sandbox directory." 72 | `(unwind-protect 73 | (condition-case nil ;ex 74 | (let ((default-directory timonier-source-dir)) 75 | (cleanup-load-path) 76 | ;; (message "Load path: %s" load-path) 77 | (load-library "/timonier.el") 78 | ,@body)))) 79 | 80 | 81 | ;;; test-helper.el ends here 82 | -------------------------------------------------------------------------------- /test/timonier-k8s-test.el: -------------------------------------------------------------------------------- 1 | ;;; timonier-k8s-test.el --- Tests for Kubernetes API 2 | 3 | ;; Copyright (C) 2016 Nicolas Lamirault 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 6 | ;; you may not use this file except in compliance with the License. 7 | ;; You may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ;; See the License for the specific language governing permissions and 15 | ;; limitations under the License. 16 | 17 | ;;; Commentary: 18 | 19 | ;;; Code: 20 | 21 | 22 | (ert-deftest test-timonier-k8s-api-version () 23 | :tags '(k8s) 24 | (with-test-sandbox 25 | (let ((response (timonier--k8s-get-api))) 26 | (assert (string-equal "v1" (elt (cdadr (timonier--k8s-get-api)) 0)))))) 27 | 28 | 29 | 30 | (provide 'timonier-k8s-test) 31 | ;;; timonier-k8s-test.el ends here 32 | -------------------------------------------------------------------------------- /test/timonier-version-test.el: -------------------------------------------------------------------------------- 1 | ;;; timonier-version-test.el --- Tests for version information 2 | 3 | ;; Copyright (C) 2016 Nicolas Lamirault 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 6 | ;; you may not use this file except in compliance with the License. 7 | ;; You may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ;; See the License for the specific language governing permissions and 15 | ;; limitations under the License. 16 | 17 | ;;; Commentary: 18 | 19 | ;;; Code: 20 | 21 | (require 'pkg-info) 22 | 23 | (setq current-version "0.1.0") 24 | 25 | 26 | (ert-deftest test-timonier-library-version () 27 | :tags '(version) 28 | (with-test-sandbox 29 | (should (string= current-version (timonier--library-version))))) 30 | 31 | (ert-deftest test-timonier-version () 32 | :tags '(version) 33 | (with-test-sandbox 34 | (should (string= current-version (timonier-version))))) 35 | 36 | 37 | (provide 'timonier-version-test) 38 | ;;; timonier-version-test.el ends here 39 | -------------------------------------------------------------------------------- /timonier-0.1.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nlamirault/timonier/0a150ea87bf695b43cf1740dfd7e553e0ae7601c/timonier-0.1.0.png -------------------------------------------------------------------------------- /timonier-custom.el: -------------------------------------------------------------------------------- 1 | ;;; timonier-custom.el --- Customization for timonier 2 | 3 | ;; Copyright (C) 2016 Nicolas Lamirault 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 6 | ;; you may not use this file except in compliance with the License. 7 | ;; You may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ;; See the License for the specific language governing permissions and 15 | ;; limitations under the License. 16 | 17 | ;;; Commentary: 18 | 19 | ;;; Code: 20 | 21 | 22 | (require 'timonier-version) 23 | 24 | 25 | 26 | (defgroup timonier nil 27 | "Timonier" 28 | :group 'applications 29 | :link '(url-link :tag "Socyl" "https://github.com/nlamirault/timonier") 30 | :link '(emacs-commentary-link :tag "Commentary" "timonier")) 31 | 32 | 33 | (defcustom timonier-k8s-proxy "http://localhost:8001" 34 | "The Kubernetes proxy." 35 | :type 'string 36 | :group 'timonier) 37 | 38 | 39 | (defconst timonier--user-agent "timonier" 40 | "The user agent for Kubernetes.") 41 | 42 | 43 | 44 | (provide 'timonier-custom) 45 | ;;; timonier-custom.el ends here 46 | -------------------------------------------------------------------------------- /timonier-io.el: -------------------------------------------------------------------------------- 1 | ;;; timonier-io.el --- I/O tools for Timonier 2 | 3 | ;; Copyright (C) 2016 Nicolas Lamirault 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 6 | ;; you may not use this file except in compliance with the License. 7 | ;; You may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ;; See the License for the specific language governing permissions and 15 | ;; limitations under the License. 16 | ;;; Commentary: 17 | 18 | ;;; Code: 19 | 20 | 21 | (defun timonier--assoc-cdr (key list) 22 | (or (cdr (assoc key list)) "")) 23 | 24 | 25 | (provide 'timonier-io) 26 | ;;; timonier-io.el ends here 27 | -------------------------------------------------------------------------------- /timonier-k8s.el: -------------------------------------------------------------------------------- 1 | ;;; timonier-k8s.el --- Kubernetes API for Timonier 2 | 3 | ;; Copyright (C) 2016 Nicolas Lamirault 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 6 | ;; you may not use this file except in compliance with the License. 7 | ;; You may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ;; See the License for the specific language governing permissions and 15 | ;; limitations under the License. 16 | 17 | ;;; Commentary: 18 | 19 | ;;; Code: 20 | 21 | (require 'cl-lib) 22 | 23 | (require 'timonier-custom) 24 | (require 'timonier-utils) 25 | (require 'timonier-io) 26 | 27 | 28 | (defmacro timonier--with-k8s (&rest body) 29 | `(condition-case err 30 | ,@body 31 | (error (message "[Kubernetes] Error with API: %s" err)))) 32 | 33 | 34 | (defun timonier--k8s-get-uri (uri) 35 | "Retrieve the Kubernetes API complete url using the Kubernetes proxy. 36 | `URI' is the api path." 37 | (if timonier-k8s-proxy 38 | (s-concat timonier-k8s-proxy "/" uri) 39 | (error (signal 'timonier-k8s-error '("Kubernetes proxy unknown."))))) 40 | 41 | 42 | (defun timonier--k8s-get-api () 43 | "Retrieve the Kubernetes API." 44 | (timonier--perform-http-request 45 | "GET" (timonier--k8s-get-uri "/api") '() 200)) 46 | 47 | 48 | (defmacro timonier--with-k8s-api-version (api-version &rest body) 49 | "Retrieve Kubernetes API and set into `API-VERSION' and execute the forms in `BODY'." 50 | (declare (indent 1) (debug t)) 51 | `(let* ((response (timonier--k8s-get-api)) 52 | (,api-version (elt (cdadr response) 0))) 53 | (message "[k8s] API version: %s" ,api-version) 54 | (if ,api-version 55 | ,@body 56 | (message "[Timonier] Can't retrieve Kubernetes version: %s" response)))) 57 | 58 | 59 | (defun timonier--k8s-get-namespaces () 60 | "Retrieve namespaces from a Kubernetes cluster." 61 | (timonier--with-k8s-api-version api-version 62 | (timonier--perform-http-request 63 | "GET" (timonier--k8s-get-uri (s-concat "/api/" api-version "/namespaces")) '() 200))) 64 | 65 | (defun timonier--k8s-extract-namespace-informations (namespace) 66 | "Extract commons informations from `NAMESPACE'. 67 | Result is a property list. Keys are : 'name and 'status." 68 | (let ((metadata (timonier--assoc-cdr 'metadata namespace)) 69 | (status (timonier--assoc-cdr 'status namespace)) 70 | properties) 71 | (setq properties 72 | (list 'name (timonier--assoc-cdr 'name metadata) 73 | 'status (timonier--assoc-cdr 'phase status))) 74 | properties)) 75 | 76 | 77 | (defun timonier--k8s-get-pods () 78 | "Retrieve pods from a Kubernetes cluster." 79 | (timonier--with-k8s-api-version api-version 80 | (timonier--perform-http-request 81 | "GET" (timonier--k8s-get-uri (s-concat "/api/" api-version "/pods")) '() 200))) 82 | 83 | 84 | (defun timonier--k8s-extract-pod-informations (pod) 85 | "Extract commons informations from `POD'. 86 | Result is a property list. Keys are : 'name, 'namespace and 'status." 87 | (let ((metadata (timonier--assoc-cdr 'metadata pod)) 88 | (status (timonier--assoc-cdr 'status pod)) 89 | properties) 90 | (setq properties 91 | (list 'name (timonier--assoc-cdr 'name metadata) 92 | 'namespace (timonier--assoc-cdr 'namespace metadata) 93 | 'cluster-ip (timonier--assoc-cdr 'podIP status) 94 | 'status (timonier--assoc-cdr 'phase status))) 95 | properties)) 96 | 97 | 98 | (defun timonier--k8s-get-nodes () 99 | "Retrieve nodes from a Kubernetes cluster.." 100 | (timonier--with-k8s-api-version api-version 101 | (timonier--perform-http-request 102 | "GET" (timonier--k8s-get-uri (s-concat "/api/" api-version "/nodes")) '() 200))) 103 | 104 | 105 | (defun timonier--k8s-extract-node-informations (node) 106 | "Extract commons informations from `NODE'. 107 | Result is a property list. Keys are : 'name, 'labels and 'creation." 108 | (let ((metadata (timonier--assoc-cdr 'metadata node)) 109 | (infos (timonier--assoc-cdr 'nodeInfo node)) 110 | properties) 111 | (setq properties 112 | (list 'name (timonier--assoc-cdr 'name metadata) 113 | 'labels (mapcar 'cdr (timonier--assoc-cdr 'labels metadata)) 114 | 'creation (timonier--assoc-cdr 'creationTimestamp metadata))) 115 | properties)) 116 | 117 | 118 | (defun timonier--k8s-extract-node-description (node) 119 | "Extract complete description from `NODE'." 120 | (let* ((metadata (timonier--assoc-cdr 'metadata node)) 121 | (spec (timonier--assoc-cdr 'spec node)) 122 | (status (timonier--assoc-cdr 'status node)) 123 | (addresses (timonier--assoc-cdr 'addresses status)) 124 | (node-info (timonier--assoc-cdr 'nodeInfo status)) 125 | properties) 126 | (setq properties 127 | (list 'name (timonier--assoc-cdr 'name metadata) 128 | 'labels (mapcar 'cdr (timonier--assoc-cdr 'labels metadata)) 129 | 'creation (timonier--assoc-cdr 'creationTimestamp metadata) 130 | 'external-id (timonier--assoc-cdr 'externalID spec) 131 | 'addresses (mapcar (lambda (adr) 132 | (mapcar 'cdr adr)) 133 | addresses) 134 | 'os-image (timonier--assoc-cdr 'osImage node-info) 135 | 'system-uuid (timonier--assoc-cdr 'systemUUID node-info) 136 | 'boot-id (timonier--assoc-cdr 'bootID node-info) 137 | 'kernel-version (timonier--assoc-cdr 'kernelVersion node-info) 138 | 'container-runtime (timonier--assoc-cdr 'containerRuntimeVersion node-info) 139 | 'kubelet-version (timonier--assoc-cdr 'kubeletVersion node-info) 140 | 'kubeproxy-version (timonier--assoc-cdr 'kubeProxyVersion node-info) 141 | 'os (timonier--assoc-cdr 'operatingSystem node-info) 142 | 'architecture (timonier--assoc-cdr 'architecture node-info))) 143 | properties)) 144 | 145 | (defun timonier--k8s-get-services () 146 | "Retrieve services from a Kubernetes cluster." 147 | (timonier--with-k8s-api-version api-version 148 | (timonier--perform-http-request 149 | "GET" (timonier--k8s-get-uri (s-concat "/api/" api-version "/services")) '() 200))) 150 | 151 | 152 | (defun timonier--k8s-extract-service-informations (service) 153 | "Extract commons informations from `SERVICE'. 154 | Result is a property list. Keys are : 'name, 'namespace." 155 | (let ((metadata (timonier--assoc-cdr 'metadata service)) 156 | (spec (timonier--assoc-cdr 'spec service)) 157 | properties) 158 | (setq properties 159 | (list 'name (timonier--assoc-cdr 'name metadata) 160 | 'namespace (timonier--assoc-cdr 'namespace metadata) 161 | 'labels (mapcar 'cdr (timonier--assoc-cdr 'labels metadata)) 162 | 'ports (mapcar (lambda (port) 163 | (mapcar 'cdr port)) 164 | (timonier--assoc-cdr 'ports spec)) 165 | 'cluster-ip (timonier--assoc-cdr 'clusterIP spec))) 166 | properties)) 167 | 168 | 169 | 170 | (provide 'timonier-k8s) 171 | ;;; timonier-k8s.el ends here 172 | -------------------------------------------------------------------------------- /timonier-mode.el: -------------------------------------------------------------------------------- 1 | ;;; timonier-mode.el --- Mode for timonier 2 | 3 | ;; Copyright (C) 2016 Nicolas Lamirault 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 6 | ;; you may not use this file except in compliance with the License. 7 | ;; You may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ;; See the License for the specific language governing permissions and 15 | ;; limitations under the License. 16 | 17 | ;;; Commentary: 18 | 19 | ;;; Code: 20 | 21 | (require 'widget) 22 | (require 'cl-lib) 23 | 24 | (require 'all-the-icons) 25 | (require 'f) 26 | (require 'hydra) 27 | (require 's) 28 | 29 | (require 'timonier-custom) 30 | (require 'timonier-io) 31 | (require 'timonier-k8s) 32 | 33 | 34 | ;; ------------------ 35 | ;; Customization 36 | ;; ------------------ 37 | 38 | (defgroup timonier-k8s-mode nil 39 | "Customization group for `timonier-k8s-mode'." 40 | :prefix "timonier-k8s-mode-" 41 | :tag "Timonier Kubernetes Mode" 42 | :group 'timonier) 43 | 44 | (defcustom timonier-k8s-mode-buffer "*timonier-k8s*" 45 | "The Timonier kubernetes buffer name." 46 | :type 'string 47 | :group 'timonier-k8s-mode) 48 | 49 | (defcustom timonier-k8s-description-mode-buffer "*timonier-k8s-desc*" 50 | "The Timonier kubernetes entity description buffer name." 51 | :type 'string 52 | :group 'timonier-k8s-mode) 53 | 54 | (defcustom timonier-k8s-keymap-prefix "C-c C-k" 55 | "Prefix for `timonier-k8s-mode'." 56 | :group 'timonier-k8s-mode) 57 | 58 | (defcustom timonier-k8s-mode-line 59 | " Timonier/Kubernetes " 60 | "Mode line lighter for Timonier." 61 | :group 'timonier-k8s-mode 62 | :type 'sexp 63 | :risky t) 64 | 65 | 66 | ;; ------------------ 67 | ;; Faces 68 | ;; ------------------ 69 | 70 | (defgroup timonier-k8s-mode-faces '((timonier-k8s-mode custom-group)) 71 | "Customization group for the faces of `timonier-k8s-mode'." 72 | :prefix "timonier-k8s-mode-" 73 | :tag "Timonier Kubernetes mode faces" 74 | :group 'timonier-k8s-mode) 75 | 76 | (defface timonier-k8s-mode-title-face 77 | '((t :inherit font-lock-builtin-face)) 78 | "Face used for buffer's title." 79 | :group 'timonier-k8s-mode) 80 | 81 | (defface timonier-k8s-mode-key-face 82 | '((t :weight bold :inherit font-lock-keyword-face)) 83 | "Face used in the Timonier buffer." 84 | :group 'timonier-k8s-mode-faces) 85 | 86 | (defface timonier-k8s-mode-pod-face 87 | '((t :weight bold :inherit font-lock-warning-name-face)) 88 | "Face used in the Timonier buffer." 89 | :group 'timonier-k8s-mode-faces) 90 | 91 | (defface timonier-k8s-mode-service-face 92 | '((t :weight bold :inherit font-lock-warning-name-face)) 93 | "Face used in the Timonier buffer." 94 | :group 'timonier-k8s-mode-faces) 95 | 96 | (defface timonier-k8s-mode-node-face 97 | '((t :weight bold :inherit font-lock-warning-name-face)) 98 | "Face used in the Timonier buffer." 99 | :group 'timonier-k8s-mode-faces) 100 | 101 | (defface timonier-k8s-mode-namespace-face 102 | '((t :inherit font-lock-doc-face)) 103 | "Face used in the Timonier buffer" 104 | :group 'timonier-k8s-mode-faces) 105 | 106 | (defface timonier-k8s-mode-pod-status-face 107 | '((t :inherit font-lock-string-face)) 108 | "Face used in the Timonier buffer" 109 | :group 'timonier-k8s-mode-faces) 110 | 111 | (defface timonier-k8s-mode-namespace-status-face 112 | '((t :inherit font-lock-string-face)) 113 | "Face used in the Timonier buffer" 114 | :group 'timonier-k8s-mode-faces) 115 | 116 | (defvar timonier-k8s-mode-padding 2 117 | "The number of columns used for padding on the left side of the buffer.") 118 | 119 | 120 | ;; ------------------ 121 | ;; Modes 122 | ;; ------------------ 123 | 124 | 125 | (defmacro timonier-k8s-mode-with-widget (title &rest body) 126 | `(progn 127 | (set-buffer (get-buffer-create timonier-k8s-mode-buffer)) 128 | (switch-to-buffer timonier-k8s-mode-buffer) 129 | (kill-all-local-variables) 130 | (let ((inhibit-read-only t)) 131 | (erase-buffer) 132 | (remove-overlays) 133 | (widget-insert (format "\n[%s]\n\n" ,title)) 134 | ,@body) 135 | (use-local-map widget-keymap) 136 | (widget-setup) 137 | (timonier-k8s-mode) 138 | (widget-minor-mode) 139 | (goto-char 0))) 140 | 141 | 142 | (defmacro timonier-k8s-mode-description-with-widget (title &rest body) 143 | `(progn 144 | (set-buffer (get-buffer-create timonier-k8s-description-mode-buffer)) 145 | (switch-to-buffer timonier-k8s-description-mode-buffer) 146 | (kill-all-local-variables) 147 | (let ((inhibit-read-only t)) 148 | (erase-buffer) 149 | (remove-overlays) 150 | (widget-insert (format "\n[%s]\n\n" ,title)) 151 | ,@body) 152 | (use-local-map widget-keymap) 153 | (widget-setup) 154 | (timonier-k8s-description-mode) 155 | (widget-minor-mode) 156 | (goto-char 0))) 157 | 158 | 159 | (defvar timonier-k8s-mode-hook nil) 160 | 161 | 162 | (defun timonier-k8s-mode-quit () 163 | "Timonier exit." 164 | (interactive) 165 | (kill-buffer timonier-k8s-mode-buffer)) 166 | 167 | 168 | (defun timonier--k8s-mode-current-entity (type) 169 | "Return the current Kubernetes entities at point using `TYPE'." 170 | (get-text-property (point) type)) 171 | 172 | 173 | (defun timonier--k8s-mode-next-entity (type) 174 | "Move point to the next Kubernetes entity specified by `TYPE'." 175 | (interactive) 176 | (let ((pos (next-single-property-change (point) type))) 177 | (if pos 178 | (progn 179 | (goto-char pos) 180 | (unless (timonier--k8s-mode-current-entity type) 181 | (let ((pos (next-single-property-change pos type))) 182 | (when pos 183 | (goto-char pos))))) 184 | (message "No current position: %s" type)))) 185 | 186 | 187 | (defun timonier--k8s-mode-prev-entity (type) 188 | "Move point to the previous Kubernetes entity specified by `TYPE'." 189 | (interactive) 190 | (let ((pos (previous-single-property-change (point) type))) 191 | (if pos 192 | (progn 193 | (goto-char pos) 194 | (unless (timonier--k8s-mode-current-entity type) 195 | (let ((pos (previous-single-property-change pos type))) 196 | (when pos 197 | (goto-char pos))))) 198 | (message "No current position: %s" type)))) 199 | 200 | 201 | (defun timonier-k8s-mode-next-pod () 202 | "Move point to the next Kubernetes pod." 203 | (interactive) 204 | (timonier--k8s-mode-next-entity :k8s-pod)) 205 | 206 | 207 | (defun timonier-k8s-mode-prev-pod () 208 | "Move point to the previous Kubernetes pod." 209 | (interactive) 210 | (timonier--k8s-mode-prev-entity :k8s-pod)) 211 | 212 | 213 | (defun timonier-k8s-mode-next-service () 214 | "Move point to the next Kubernetes service." 215 | (interactive) 216 | (timonier--k8s-mode-next-entity :k8s-service)) 217 | 218 | 219 | (defun timonier-k8s-mode-prev-service () 220 | "Move point to the previous Kubernetes service." 221 | (interactive) 222 | (timonier--k8s-mode-prev-entity :k8s-service)) 223 | 224 | (defun timonier-k8s-mode-next-node () 225 | "Move point to the next Kubernetes node." 226 | (interactive) 227 | (timonier--k8s-mode-next-entity :k8s-node)) 228 | 229 | 230 | (defun timonier-k8s-mode-prev-node () 231 | "Move point to the previous Kubernetes node." 232 | (interactive) 233 | (timonier--k8s-mode-prev-entity :k8s-node)) 234 | 235 | 236 | (defun timonier-k8s-mode-describe-node () 237 | (interactive) 238 | (let ((node (timonier--k8s-mode-current-entity :k8s-node))) 239 | (if node 240 | (progn 241 | (let ((node-data (timonier--k8s-extract-node-description node))) 242 | (timonier-k8s-mode-description-with-widget 243 | (propertize "Kubernetes / Nodes" 244 | 'face 'timonier-k8s-mode-title-face) 245 | (widget-insert 246 | (format "\n%s:" 247 | (propertize "Details" 248 | 'face 'timonier-k8s-mode-title-face)) 249 | (format "\n%s: %s" 250 | (propertize "Name" 251 | 'face 'timonier-k8s-mode-key-face) 252 | (propertize (plist-get node-data 'name) 253 | 'face 'timonier-k8s-mode-pod-face)) 254 | (format "\n%s: %s" 255 | (propertize "Labels" 256 | 'face 'timonier-k8s-mode-key-face) 257 | (propertize 258 | (s-join " " (plist-get node-data 'labels)))) 259 | (format "\n%s: %s" 260 | (propertize "External ID" 261 | 'face 'timonier-k8s-mode-key-face) 262 | (propertize (plist-get node-data 'external-id) 263 | 'face 'timonier-k8s-mode-pod-face)) 264 | (format "\n\n%s:" 265 | (propertize "System info" 266 | 'face 'timonier-k8s-mode-title-face)) 267 | (format "\n%s: %s" 268 | (propertize "System UUID" 269 | 'face 'timonier-k8s-mode-key-face) 270 | (propertize (plist-get node-data 'system-uuid) 271 | 'face 'timonier-k8s-mode-pod-face)) 272 | (format "\n%s: %s" 273 | (propertize "Boot ID" 274 | 'face 'timonier-k8s-mode-key-face) 275 | (propertize (plist-get node-data 'boot-id) 276 | 'face 'timonier-k8s-mode-pod-face)) 277 | (format "\n%s: %s" 278 | (propertize "Kernel Version" 279 | 'face 'timonier-k8s-mode-key-face) 280 | (propertize (plist-get node-data 'kernel-version) 281 | 'face 'timonier-k8s-mode-pod-face)) 282 | (format "\n%s: %s" 283 | (propertize "OS Image" 284 | 'face 'timonier-k8s-mode-key-face) 285 | (propertize (plist-get node-data 'os-image) 286 | 'face 'timonier-k8s-mode-pod-face)) 287 | (format "\n%s: %s" 288 | (propertize "Container Runtime Version" 289 | 'face 'timonier-k8s-mode-key-face) 290 | (propertize (plist-get node-data 'container-runtime) 291 | 'face 'timonier-k8s-mode-pod-face)) 292 | (format "\n%s: %s" 293 | (propertize "Kubelet Version" 294 | 'face 'timonier-k8s-mode-key-face) 295 | (propertize (plist-get node-data 'kubelet-version) 296 | 'face 'timonier-k8s-mode-pod-face)) 297 | (format "\n%s: %s" 298 | (propertize "Kube-Proxy Version" 299 | 'face 'timonier-k8s-mode-key-face) 300 | (propertize (plist-get node-data 'kubeproxy-version) 301 | 'face 'timonier-k8s-mode-pod-face)) 302 | (format "\n%s: %s" 303 | (propertize "Operation system" 304 | 'face 'timonier-k8s-mode-key-face) 305 | (propertize (plist-get node-data 'os) 306 | 'face 'timonier-k8s-mode-pod-face)) 307 | (format "\n%s: %s" 308 | (propertize "Architecture" 309 | 'face 'timonier-k8s-mode-key-face) 310 | (propertize (plist-get node-data 'architecture) 311 | 'face 'timonier-k8s-mode-pod-face)) 312 | )))) 313 | (message "No node available.")))) 314 | 315 | 316 | (defun timonier-k8s-mode-describe-pod () 317 | (interactive) 318 | (let ((pod (timonier--k8s-mode-current-entity :k8s-pod))) 319 | (if pod 320 | (message "Pod %s" pod) 321 | (message "No pod available.")))) 322 | 323 | 324 | 325 | (defun timonier-k8s-mode-describe-service () 326 | (interactive) 327 | (let ((service (timonier--k8s-mode-current-entity :k8s-service))) 328 | (if service 329 | (message "%s" service) 330 | (message "No service available.")))) 331 | 332 | 333 | 334 | (defhydra timonier-k8s-hydra (:color blue :hint none) 335 | " 336 | [ Timonier / Kubernetes ] 337 | 338 | ^Node^ ^Service^ ^Pod^ 339 | -------------------------------------------------------------------------------------- 340 | _i_: go to next node _k_: go to next service _g_: go to next pod 341 | _j_: go to previous node _l_: go to previous service _h_: go to previous pod 342 | _N_: describe current node _S_: describe current service _P_: describe current pod 343 | 344 | _q_: quit 345 | " 346 | ("g" timonier-k8s-mode-next-pod) 347 | ("h" timonier-k8s-mode-prev-pod) 348 | ("P" timonier-k8s-mode-describe-pod) 349 | 350 | ("k" timonier-k8s-mode-next-service) 351 | ("l" timonier-k8s-mode-prev-service) 352 | ("S" timonier-k8s-mode-describe-service) 353 | 354 | ("i" timonier-k8s-mode-next-node) 355 | ("j" timonier-k8s-mode-prev-node) 356 | ("N" timonier-k8s-mode-describe-node) 357 | 358 | ("q" nil "quit" :hint t :color red)) 359 | 360 | 361 | (defvar timonier-k8s-mode-map 362 | (let ((map (make-keymap))) 363 | (define-key map (kbd timonier-k8s-keymap-prefix) 'timonier-k8s-hydra/body) 364 | map)) 365 | 366 | 367 | (define-derived-mode timonier-k8s-mode tabulated-list-mode 368 | "Timonier Kubernetes mode" 369 | "Major mode for Timonier." 370 | :group 'timonier 371 | ) 372 | 373 | 374 | (defun timonier-k8s-description-mode-quit () 375 | "Quit the Kubernetes description mode." 376 | (interactive) 377 | (kill-buffer timonier-k8s-description-mode-buffer)) 378 | 379 | 380 | (defvar timonier-k8s-description-mode-map 381 | (let ((map (make-keymap))) 382 | (define-key map (kbd "q") 'timonier-k8s-description-mode-quit) 383 | map)) 384 | 385 | 386 | (define-derived-mode timonier-k8s-description-mode tabulated-list-mode 387 | "Timonier Kubernetes mode" 388 | "Major mode for Timonier." 389 | :group 'timonier 390 | ) 391 | 392 | 393 | (defun timonier--k8s-mode-render-pod (pod) 394 | "Render a Kubernetes `POD' to the Timonier buffer." 395 | ;; (message "Pod: %s" pod) 396 | (let* ((pod-data (timonier--k8s-extract-pod-informations pod))) 397 | (insert (all-the-icons-octicon "package")) 398 | (let ((start (point))) 399 | (widget-insert 400 | (format " %s %s" 401 | (propertize (plist-get pod-data 'name) 402 | 'face 'timonier-k8s-mode-pod-face) 403 | (propertize (plist-get pod-data 'status) 404 | 'face 'timonier-k8s-mode-pod-status-face))) 405 | (put-text-property start (point) :k8s-pod pod) 406 | (widget-insert 407 | (format "\n %s: %s\n\n" 408 | (propertize "Namespace" 409 | 'face 'timonier-k8s-mode-key-face) 410 | (propertize (plist-get pod-data 'namespace) 411 | 'face 'timonier-k8s-mode-namespace-face)))))) 412 | 413 | 414 | (defun timonier--k8s-mode-render-pods (pods) 415 | "Render Kubernetes `PODS'." 416 | (widget-insert (format "\n== PODS ==\n\n")) 417 | (dotimes (i (length pods)) 418 | (let ((pod (elt pods i))) 419 | (timonier--k8s-mode-render-pod pod))) 420 | (widget-insert "\n")) 421 | 422 | 423 | (defun timonier--k8s-mode-render-service (service) 424 | "Render a Kubernetes `SERVICE' to the Timonier buffer." 425 | (let* ((service-data (timonier--k8s-extract-service-informations service))) 426 | (insert (all-the-icons-octicon "link-external")) 427 | (let ((start (point))) 428 | (widget-insert 429 | (format " %s" 430 | (propertize (plist-get service-data 'name) 431 | 'face 'timonier-k8s-mode-service-face))) 432 | (put-text-property start (point) :k8s-service service) 433 | (widget-insert 434 | (format "\n %s: %s" 435 | (propertize "Namespace" 436 | 'face 'timonier-k8s-mode-key-face) 437 | (propertize (plist-get service-data 'namespace) 438 | 'face 'timonier-k8s-mode-namespace-face)) 439 | (format "\n %s: %s" 440 | (propertize "ClusterIP" 441 | 'face 'timonier-k8s-mode-key-face) 442 | (plist-get service-data 'cluster-ip)) 443 | (format "\n %s: %s" 444 | (propertize "Endpoints" 445 | 'face 'timonier-k8s-mode-key-face) 446 | (propertize 447 | (s-join ":" (mapcar (lambda (elt) 448 | (format "%s" elt)) 449 | (plist-get service-data 'ports))))) 450 | (format "\n %s: %s\n\n" 451 | (propertize "Labels" 452 | 'face 'timonier-k8s-mode-key-face) 453 | (propertize 454 | (s-join " " (plist-get service-data 'labels)))))))) 455 | 456 | 457 | (defun timonier--k8s-mode-render-services (services) 458 | "Render Kubernetes `SERVICES'." 459 | (widget-insert (format "\n== SERVICES ==\n\n")) 460 | (dotimes (i (length services)) 461 | (let ((service (elt services i))) 462 | (timonier--k8s-mode-render-service service))) 463 | (widget-insert "\n")) 464 | 465 | 466 | (defun timonier--k8s-mode-render-node (node) 467 | "Render a Kubernetes `NODE' to the Timonier buffer." 468 | (let* ((node-data (timonier--k8s-extract-node-informations node))) 469 | (insert (all-the-icons-octicon "server")) 470 | (let ((start (point))) 471 | (widget-insert 472 | (format " %s %s" 473 | (propertize (plist-get node-data 'name) 474 | 'face 'timonier-k8s-mode-service-face) 475 | (propertize (plist-get node-data 'creation) 476 | 'face 'timonier-k8s-mode-namespace-face))) 477 | (put-text-property start (point) :k8s-node node) 478 | (widget-insert 479 | (format "\n %s: %s\n\n" 480 | (propertize "Labels" 481 | 'face 'timonier-k8s-mode-key-face) 482 | (propertize 483 | (s-join " " (plist-get node-data 'labels)))))))) 484 | 485 | 486 | (defun timonier--k8s-mode-render-nodes (nodes) 487 | "Render Kubernetes `NODES'." 488 | (widget-insert (format "\n== NODES ==\n\n")) 489 | (dotimes (i (length nodes)) 490 | (let ((node (elt nodes i))) 491 | (timonier--k8s-mode-render-node node))) 492 | (widget-insert "\n")) 493 | 494 | 495 | 496 | (defun timonier--k8s-mode-render-namespace (namespace) 497 | "Render a Kubernetes `NAMESPACE' to the Timonier buffer." 498 | (let* ((namespace-data (timonier--k8s-extract-namespace-informations namespace))) 499 | (insert (all-the-icons-octicon "organization")) 500 | (let ((start (point))) 501 | (widget-insert 502 | (format " %s %s\n" 503 | (propertize (plist-get namespace-data 'name) 504 | 'face 'timonier-k8s-mode-pod-face) 505 | (propertize (plist-get namespace-data 'status) 506 | 'face 'timonier-k8s-mode-namespace-status-face))) 507 | (put-text-property start (point) :k8s-namespace namespace)))) 508 | 509 | 510 | (defun timonier--k8s-mode-render-namespaces (namespaces) 511 | "Render Kubernetes `NAMESPACES'." 512 | (widget-insert (format "\n== NAMESPACES ==\n\n")) 513 | (dotimes (i (length namespaces)) 514 | (let ((namespace (elt namespaces i))) 515 | (timonier--k8s-mode-render-namespace namespace))) 516 | (widget-insert "\n")) 517 | 518 | 519 | ;; ------------------ 520 | ;; API 521 | ;; ------------------ 522 | 523 | (defvar timonier-k8s-mode-history nil) 524 | 525 | 526 | ;;;###autoload 527 | (defun timonier-k8s () 528 | "Display informations about the Kubernetes cluster." 529 | (interactive) 530 | (timonier--with-k8s 531 | (timonier-k8s-mode-with-widget 532 | (propertize "Kubernetes" 533 | 'face 'timonier-k8s-mode-title-face) 534 | (let ((namespaces (timonier--assoc-cdr 'items (timonier--k8s-get-namespaces))) 535 | (nodes (timonier--assoc-cdr 'items (timonier--k8s-get-nodes))) 536 | (services (timonier--assoc-cdr 'items (timonier--k8s-get-services))) 537 | (pods (timonier--assoc-cdr 'items (timonier--k8s-get-pods)))) 538 | (timonier--k8s-mode-render-namespaces namespaces) 539 | (timonier--k8s-mode-render-nodes nodes) 540 | (timonier--k8s-mode-render-services services) 541 | (timonier--k8s-mode-render-pods pods) 542 | )))) 543 | 544 | 545 | (provide 'timonier-mode) 546 | ;;; timonier-mode.el ends here 547 | -------------------------------------------------------------------------------- /timonier-utils.el: -------------------------------------------------------------------------------- 1 | ;;; timonier-utils.el --- Some tools for Timonier 2 | 3 | ;; Copyright (C) 2016 Nicolas Lamirault 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 6 | ;; you may not use this file except in compliance with the License. 7 | ;; You may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ;; See the License for the specific language governing permissions and 15 | ;; limitations under the License. 16 | ;;; Commentary: 17 | 18 | ;;; Code: 19 | 20 | (require 'json) 21 | (require 'request) 22 | (require 's) 23 | 24 | 25 | (require 'timonier-version) 26 | (require 'timonier-custom) 27 | 28 | 29 | ;; Errors 30 | 31 | (define-error 'timonier-error "Timonier error") 32 | 33 | (define-error 'timonier-k8s-error "Timonier Kubernetes Error" 'timonier-error) 34 | 35 | 36 | ;; HTTP tools 37 | 38 | 39 | (defun timonier--get-headers () 40 | "Generate HTTP headers for Travis API." 41 | `(("User-Agent" . ,(concat timonier--user-agent 42 | "/" 43 | (timonier--library-version))))) 44 | 45 | 46 | (defun timonier--perform-http-request (method uri params status-code) 47 | "Do a HTTP METHOD request using URI and PARAMS. 48 | If HTTP return code is STATUS-CODE, send the response content otherwise 49 | raise an error." 50 | (let ((response (request uri 51 | :type method 52 | :headers (timonier--get-headers) 53 | :sync t 54 | :data params 55 | :parser 'json-read))) 56 | (if (= status-code (request-response-status-code response)) 57 | (request-response-data response) 58 | (error 59 | (signal 'travis-http-error 60 | (list (request-response-status-code response) 61 | (request-response-data response))))))) 62 | 63 | 64 | 65 | 66 | 67 | 68 | (provide 'timonier-utils) 69 | ;;; timonier-utils.el ends here 70 | -------------------------------------------------------------------------------- /timonier-version.el: -------------------------------------------------------------------------------- 1 | ;;; timonier.el --- Version tools for Timonier 2 | 3 | ;; Copyright (C) 2016 Nicolas Lamirault 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 6 | ;; you may not use this file except in compliance with the License. 7 | ;; You may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ;; See the License for the specific language governing permissions and 15 | ;; limitations under the License. 16 | 17 | ;;; Commentary: 18 | 19 | ;;; Code: 20 | 21 | 22 | (require 'dash) 23 | (require 'pkg-info) 24 | (require 's) 25 | 26 | 27 | (defun timonier--library-version () 28 | "Get the version in the timonier library." 29 | (-when-let (version (pkg-info-library-version 'timonier)) 30 | (pkg-info-format-version version))) 31 | 32 | 33 | ;;;###autoload 34 | (defun timonier-version (&optional show-version) 35 | "Get the timonier version as string. 36 | If called interactively or if SHOW-VERSION is non-nil, show the 37 | version in the echo area and the messages buffer. 38 | The returned string includes both, the version from package.el 39 | and the library version, if both a present and different. 40 | If the version number could not be determined, signal an error, 41 | if called interactively, or if SHOW-VERSION is non-nil, otherwise 42 | just return nil." 43 | (interactive (list (not (or executing-kbd-macro noninteractive)))) 44 | (let* ((version (timonier--library-version))) 45 | (unless version 46 | (error "Could not find out timonier version")) 47 | (message "timonier %s" version) 48 | version)) 49 | 50 | 51 | 52 | 53 | (provide 'timonier-version) 54 | ;;; timonier-version.el ends here 55 | -------------------------------------------------------------------------------- /timonier.el: -------------------------------------------------------------------------------- 1 | ;;; timonier.el --- Manage Kubernetes Applications 2 | 3 | ;; Author: Nicolas Lamirault 4 | ;; URL: https://github.com/nlamirault/timonier 5 | ;; Version: 0.1.0 6 | ;; Keywords: kubernetes, docker 7 | 8 | ;; Package-Requires: ((emacs "24.4") (s "1.11.0") (f "0.19.0") (dash "2.12.0") (pkg-info "0.5.0") (hydra "0.13.6") (request "0.2.0") (all-the-icons "2.0.0")) 9 | 10 | ;; Copyright (C) 2016 Nicolas Lamirault 11 | 12 | ;; Licensed under the Apache License, Version 2.0 (the "License"); 13 | ;; you may not use this file except in compliance with the License. 14 | ;; You may obtain a copy of the License at 15 | ;; 16 | ;; http://www.apache.org/licenses/LICENSE-2.0 17 | ;; 18 | ;; Unless required by applicable law or agreed to in writing, software 19 | ;; distributed under the License is distributed on an "AS IS" BASIS, 20 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | ;; See the License for the specific language governing permissions and 22 | ;; limitations under the License. 23 | 24 | 25 | ;;; Commentary: 26 | 27 | ;;; Installation: 28 | 29 | ;; Available as a package in melpa 30 | 31 | ;; (add-to-list 'package-archives 32 | ;; '("melpa" . "https://stable.melpa.org/packages/") t) 33 | ;; 34 | ;; M-x package-install timonier 35 | 36 | ;;; Usage: 37 | 38 | 39 | ;;; Code: 40 | 41 | 42 | (require 'timonier-version) 43 | (require 'timonier-custom) 44 | (require 'timonier-io) 45 | (require 'timonier-utils) 46 | (require 'timonier-k8s) 47 | (require 'timonier-mode) 48 | 49 | 50 | (provide 'timonier) 51 | ;;; timonier.el ends here 52 | --------------------------------------------------------------------------------