From 0eb83b22f0201b881f0d7ed431087bb8fa7a713f Mon Sep 17 00:00:00 2001 From: Ryan Yin Date: Sat, 16 Mar 2024 19:45:36 +0800 Subject: [PATCH] chore(All Markdown Files): auto wrap text, fix typos --- .github/FUNDING.yml | 2 +- .github/workflows/flake_evaltests.yml | 4 +- .github/workflows/mirror_to_gitee.yml | 2 +- .prettierrc.yaml | 3 +- .typos.toml | 12 + README.md | 118 +-- home/README.md | 1 - home/base/README.md | 1 - home/base/core/editors/README.md | 1 - home/base/gui/terminal/README.md | 51 +- home/base/tui/editors/Glossary.md | 39 +- home/base/tui/editors/README.md | 33 +- home/base/tui/editors/Structured-Editing.md | 17 +- home/base/tui/editors/emacs/README.md | 27 +- home/base/tui/editors/helix/README.md | 79 +- home/base/tui/editors/neovim/README.md | 43 +- home/base/tui/encryption/README.md | 27 +- home/base/tui/gpg/README.md | 172 ++-- home/base/tui/password-store/README.md | 55 +- home/base/tui/zellij/README.md | 48 +- home/darwin/README.md | 1 - home/linux/README.md | 10 +- home/linux/desktop/README.md | 16 +- .../desktop/hyprland/conf/waybar/config.jsonc | 189 ++--- .../desktop/hyprland/conf/waybar/mocha.css | 2 - .../desktop/hyprland/conf/wlogout/style.css | 45 +- home/linux/desktop/i3/conf/scripts/README.md | 3 +- hosts/12kingdoms-rakushun/README.md | 8 +- hosts/12kingdoms-shoukei/README.md | 5 +- hosts/12kingdoms-suzu/README.md | 11 +- hosts/README.md | 42 +- hosts/idols-ai/README.md | 8 +- hosts/idols-aquamarine/README.md | 28 +- hosts/idols-kana/README.md | 6 +- hosts/idols-kana/homepage/README.md | 1 - .../idols-kana/homepage/config/bookmarks.yaml | 1 - .../homepage/config/kubernetes.yaml | 2 - .../idols-kana/homepage/config/services.yaml | 9 +- .../idols-kana/homepage/config/settings.yaml | 9 +- hosts/idols-ruby/README.md | 1 - hosts/idols-ruby/grafana/dashboards.yml | 2 +- hosts/idols-ruby/grafana/dashboards/README.md | 3 +- .../homelab/alertmanager-9578_rev4.json | 126 +-- .../node-exporter-full-1860_rev33.json | 789 +++--------------- .../kubernetes/k8s-addons-prometheus.json | 127 +-- .../kubernetes/k8s-addons-trivy-operator.json | 181 ++-- .../kubernetes/k8s-system-api-server.json | 34 +- .../kubernetes/k8s-system-coredns.json | 17 +- .../kubernetes/k8s-views-global.json | 106 +-- .../kubernetes/k8s-views-namespaces.json | 57 +- .../kubernetes/k8s-views-nodes.json | 67 +- .../dashboards/kubernetes/k8s-views-pods.json | 59 +- hosts/idols-ruby/grafana/datasources.yml | 6 +- hosts/idols-ruby/prometheus/README.md | 5 +- .../alert_rules/coredns_embedded-exporter.yml | 23 +- .../alert_rules/etcd_embedded-exporter.yml | 256 +++--- .../alert_rules/istio_embedded-exporter.yml | 196 +++-- .../alert_rules/kubestate-exporter.yml | 676 +++++++++------ .../prometheus/alert_rules/node-exporter.yml | 777 ++++++++++------- hosts/k8s/README.md | 17 +- hosts/k8s/disko-config/README.md | 2 - lib/README.md | 14 +- modules/README.md | 1 - modules/darwin/README.md | 3 +- .../nixos/desktop/remote-desktop/README.md | 17 +- nixos-installer/README.md | 60 +- nixos-installer/README.shoukei.md | 33 +- outputs/README.md | 31 +- outputs/default.nix | 2 +- overlays/README.md | 10 +- overlays/fcitx5/README.md | 16 +- .../share/rime-data/default.custom.yaml | 79 +- .../share/rime-data/default.yaml | 131 ++- .../share/rime-data/flypy.schema.yaml | 59 +- .../share/rime-data/squirrel.custom.yaml | 77 +- .../share/rime-data/squirrel.yaml | 124 +-- secrets/README.md | 54 +- secrets/nixos.nix | 2 +- vars/README.md | 2 - 79 files changed, 2477 insertions(+), 2896 deletions(-) create mode 100644 .typos.toml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 6d174892..d5bcf115 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,2 @@ patreon: ryan4yin -custom: ['https://buymeacoffee.com/ryan4yin', 'https://afdian.net/a/ryan4yin'] +custom: ["https://buymeacoffee.com/ryan4yin", "https://afdian.net/a/ryan4yin"] diff --git a/.github/workflows/flake_evaltests.yml b/.github/workflows/flake_evaltests.yml index 893d1751..525d0c05 100644 --- a/.github/workflows/flake_evaltests.yml +++ b/.github/workflows/flake_evaltests.yml @@ -8,7 +8,7 @@ on: - "scripts/**" - "**.md" - "**.nu" - - 'Justfile' + - "Justfile" pull_request: branches: - main @@ -16,7 +16,7 @@ on: - "scripts/**" - "**.md" - "**.nu" - - 'Justfile' + - "Justfile" jobs: checks: diff --git a/.github/workflows/mirror_to_gitee.yml b/.github/workflows/mirror_to_gitee.yml index 9ce74a71..e01027d8 100644 --- a/.github/workflows/mirror_to_gitee.yml +++ b/.github/workflows/mirror_to_gitee.yml @@ -4,7 +4,7 @@ on: branches: - main tags: - - '*' + - "*" jobs: mirror: diff --git a/.prettierrc.yaml b/.prettierrc.yaml index cf12abe5..aed70417 100644 --- a/.prettierrc.yaml +++ b/.prettierrc.yaml @@ -1,5 +1,6 @@ # https://prettier.io/docs/en/options semi: false singleQuote: false -printWidth: 80 +printWidth: 100 +proseWrap: always # always change wrapping in markdown text trailingComma: es5 diff --git a/.typos.toml b/.typos.toml new file mode 100644 index 00000000..4407ba01 --- /dev/null +++ b/.typos.toml @@ -0,0 +1,12 @@ +[files] +ignore-dot = true +ignore-files = true +extend-exclude = ["themes/", "data/", "static-surprises/", "resources/"] + +[default] +binary = false +# ignore some special identifiers(sha256, mac address, crypto keys, etc) +extend-ignore-re = [ + "iterm2", + "iHgEIBYKACAWIQSizQe9ljFEyyclWmtVhZllwnQrSwUCZZ1T9wIdAAAKCRBVhZll", # crypto keys +] diff --git a/README.md b/README.md index 7b23f009..8b7c13d2 100644 --- a/README.md +++ b/README.md @@ -14,52 +14,64 @@

-> My configuration is becoming more and more complex, and it may be difficult for beginners to read it. -> If you are new to NixOS and want to know how I use NixOS, I would recommend you to take a look at the [ryan4yin/nix-config/releases](https://github.com/ryan4yin/nix-config/releases) first, **checkout to some simpler older versions**, which will be much easier to understand. +> My configuration is becoming more and more complex, and it may be difficult for beginners to read +> it. If you are new to NixOS and want to know how I use NixOS, I would recommend you to take a look +> at the [ryan4yin/nix-config/releases](https://github.com/ryan4yin/nix-config/releases) first, +> **checkout to some simpler older versions**, which will be much easier to understand. This repository is home to the nix code that builds my systems: 1. NixOS Desktops: NixOS with home-manager, i3, hyprland, agenix, etc. -2. macOS Desktops: nix-darwin with home-manager, share the same home-manager configuration with NixOS Desktops. -3. NixOS Servers: virtual machines running on Proxmox, with various services, such as kubernetes, homepage, prometheus, grafana, etc. +2. macOS Desktops: nix-darwin with home-manager, share the same home-manager configuration with + NixOS Desktops. +3. NixOS Servers: virtual machines running on Proxmox, with various services, such as kubernetes, + homepage, prometheus, grafana, etc. See [./hosts](./hosts) for details of each host. ## Why NixOS & Flakes? -Nix allows for easy-to-manage, collaborative, reproducible deployments. This means that once something is setup and configured once, it works (almost) forever. If someone else shares their configuration, anyone else can just use it (if you really understand what you're copying/refering now). +Nix allows for easy-to-manage, collaborative, reproducible deployments. This means that once +something is setup and configured once, it works (almost) forever. If someone else shares their +configuration, anyone else can just use it (if you really understand what you're copying/refering +now). -As for Flakes, refer to [Introduction to Flakes - NixOS & Nix Flakes Book](https://nixos-and-flakes.thiscute.world/nixos-with-flakes/introduction-to-flakes) +As for Flakes, refer to +[Introduction to Flakes - NixOS & Nix Flakes Book](https://nixos-and-flakes.thiscute.world/nixos-with-flakes/introduction-to-flakes) -**Want to know NixOS & Flaks in detail? Looking for a beginner-friendly tutorial or best practices? You don't have to go through the pain I've experienced again! Check out my [NixOS & Nix Flakes Book - 🛠️ ❤️ An unofficial & opinionated :book: for beginners](https://github.com/ryan4yin/nixos-and-flakes-book)!** +**Want to know NixOS & Flaks in detail? Looking for a beginner-friendly tutorial or best practices? +You don't have to go through the pain I've experienced again! Check out my +[NixOS & Nix Flakes Book - 🛠️ ❤️ An unofficial & opinionated :book: for beginners](https://github.com/ryan4yin/nixos-and-flakes-book)!** -> If you're using macOS, check out [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter) for a quick start. +> If you're using macOS, check out +> [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter) for a quick +> start. ## Components -| | NixOS(Wayland) | NixOS(Xorg) | -| --------------------------- | :---------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | -| **Window Manager** | [Hyprland][Hyprland] | [i3][i3] | -| **Terminal Emulator** | [Zellij][Zellij] + [Kitty][Kitty] | [Zellij][Zellij] + [Kitty][Kitty] | -| **Bar** | [Waybar][Waybar] | [polybar][polybar] | -| **Application Launcher** | [anyrun][anyrun] | [rofi][rofi] | -| **Notification Daemon** | [Mako][Mako] | [Dunst][Dunst] | -| **Display Manager** | [GDM][GDM] | [GDM][GDM] | -| **Color Scheme** | [Catppuccin][Catppuccin] | [Catppuccin][Catppuccin] | -| **network management tool** | [NetworkManager][NetworkManager] | [NetworkManager][NetworkManager] | -| **Input method framework** | [Fcitx5][Fcitx5] | [Fcitx5][Fcitx5] | -| **System resource monitor** | [Btop][Btop] | [Btop][Btop] | -| **File Manager** | [Yazi][Yazi] + [thunar][thunar] | [Yazi][Yazi] + [thunar][thunar] | -| **Shell** | [Nushell][Nushell] + [Starship][Starship] | [Nushell][Nushell] + [Starship][Starship] | -| **Music Player** | [mpd][mpd], [ncmpcpp][ncmpcpp], [mpc][mpc], [Netease-cloud-music-gtk][netease-cloud-music-gtk] | [Netease-cloud-music-gtk][netease-cloud-music-gtk] | -| **Media Player** | [mpv][mpv] | [mpv][mpv] | -| **Text Editor** | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] | -| **Fonts** | [Nerd fonts][Nerd fonts] | [Nerd fonts][Nerd fonts] | -| **Image Viewer** | [imv][imv] | [imv][imv] | -| **Screenshot Software** | [flameshot][flameshot] + [grim][grim] | [flameshot][flameshot] | -| **Screen Recording** | [OBS][OBS] | [OBS][OBS] | -| **Filesystem & Encryption** | tmpfs on `/`, [Btrfs][Btrfs] subvolumes on a [LUKS][LUKS] crypted partition for persistent, unlock via passphrase | tmpfs on `/`, [Btrfs][Btrfs] subvolumes on a [LUKS][LUKS] crypted partition for persistent, unlock via passphrase | -| **Secure Boot** | [lanzaboote][lanzaboote] | [lanzaboote][lanzaboote] | +| | NixOS(Wayland) | NixOS(Xorg) | +| --------------------------- | :------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------ | +| **Window Manager** | [Hyprland][Hyprland] | [i3][i3] | +| **Terminal Emulator** | [Zellij][Zellij] + [Kitty][Kitty] | [Zellij][Zellij] + [Kitty][Kitty] | +| **Bar** | [Waybar][Waybar] | [polybar][polybar] | +| **Application Launcher** | [anyrun][anyrun] | [rofi][rofi] | +| **Notification Daemon** | [Mako][Mako] | [Dunst][Dunst] | +| **Display Manager** | [GDM][GDM] | [GDM][GDM] | +| **Color Scheme** | [Catppuccin][Catppuccin] | [Catppuccin][Catppuccin] | +| **network management tool** | [NetworkManager][NetworkManager] | [NetworkManager][NetworkManager] | +| **Input method framework** | [Fcitx5][Fcitx5] | [Fcitx5][Fcitx5] | +| **System resource monitor** | [Btop][Btop] | [Btop][Btop] | +| **File Manager** | [Yazi][Yazi] + [thunar][thunar] | [Yazi][Yazi] + [thunar][thunar] | +| **Shell** | [Nushell][Nushell] + [Starship][Starship] | [Nushell][Nushell] + [Starship][Starship] | +| **Music Player** | [mpd][mpd], [ncmpcpp][ncmpcpp], [mpc][mpc], [Netease-cloud-music-gtk][netease-cloud-music-gtk] | [Netease-cloud-music-gtk][netease-cloud-music-gtk] | +| **Media Player** | [mpv][mpv] | [mpv][mpv] | +| **Text Editor** | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] | +| **Fonts** | [Nerd fonts][Nerd fonts] | [Nerd fonts][Nerd fonts] | +| **Image Viewer** | [imv][imv] | [imv][imv] | +| **Screenshot Software** | [flameshot][flameshot] + [grim][grim] | [flameshot][flameshot] | +| **Screen Recording** | [OBS][OBS] | [OBS][OBS] | +| **Filesystem & Encryption** | tmpfs on `/`, [Btrfs][Btrfs] subvolumes on a [LUKS][LUKS] encrypted partition for persistent, unlock via passphrase | tmpfs on `/`, [Btrfs][Btrfs] subvolumes on a [LUKS][LUKS] encrypted partition for persistent, unlock via passphrase | +| **Secure Boot** | [lanzaboote][lanzaboote] | [lanzaboote][lanzaboote] | Wallpapers: https://github.com/ryan4yin/wallpapers @@ -73,8 +85,7 @@ Wallpapers: https://github.com/ryan4yin/wallpapers ## I3 + AstroNvim -![](./_img/i3_2023-07-29_1.webp) -![](./_img/i3_2023-07-29_2.webp) +![](./_img/i3_2023-07-29_1.webp) ![](./_img/i3_2023-07-29_2.webp) ## Neovim @@ -90,14 +101,19 @@ See [./secrets](./secrets) for details. ## How to Deploy this Flake? -> :red_circle: **IMPORTANT**: **You should NOT deploy this flake directly on your machine :exclamation: It will not succeed.** -> This flake contains my hardware configuration(such as [hardware-configuration.nix](hosts/idols-ai/hardware-configuration.nix), [cifs-mount.nix](https://github.com/ryan4yin/nix-config/blob/v0.1.1/hosts/idols_ai/cifs-mount.nix), [Nvidia Support](https://github.com/ryan4yin/nix-config/blob/v0.1.1/hosts/idols-ai/default.nix#L77-L91), etc.) which is not suitable for your hardwares, -> and requires my private secrets repository [ryan4yin/nix-secrets](https://github.com/ryan4yin/nix-config/tree/main/secrets) to deploy. -> You may use this repo as a reference to build your own configuration. +> :red_circle: **IMPORTANT**: **You should NOT deploy this flake directly on your machine +> :exclamation: It will not succeed.** This flake contains my hardware configuration(such as +> [hardware-configuration.nix](hosts/idols-ai/hardware-configuration.nix), +> [cifs-mount.nix](https://github.com/ryan4yin/nix-config/blob/v0.1.1/hosts/idols_ai/cifs-mount.nix), +> [Nvidia Support](https://github.com/ryan4yin/nix-config/blob/v0.1.1/hosts/idols-ai/default.nix#L77-L91), +> etc.) which is not suitable for your hardwares, and requires my private secrets repository +> [ryan4yin/nix-secrets](https://github.com/ryan4yin/nix-config/tree/main/secrets) to deploy. You +> may use this repo as a reference to build your own configuration. For NixOS: -> To deploy this flake from NixOS's official ISO image(purest installation method), please refer to [./nixos-installer/](./nixos-installer/) +> To deploy this flake from NixOS's official ISO image(purest installation method), please refer to +> [./nixos-installer/](./nixos-installer/) > Need to restart the machine when switching between `wayland` and `xorg`. @@ -136,7 +152,8 @@ just ha debug # just fe debug ``` -> [What y'all will need when Nix drives you to drink.](https://www.youtube.com/watch?v=Eni9PPPPBpg) (copy from hlissner's dotfiles, it really matches my feelings when I first started using NixOS...) +> [What y'all will need when Nix drives you to drink.](https://www.youtube.com/watch?v=Eni9PPPPBpg) +> (copy from hlissner's dotfiles, it really matches my feelings when I first started using NixOS...) ## How to create & managage VM from this flake? @@ -146,14 +163,15 @@ use `aquamarine` as an example, we can create a virtual machine with the followi # 1. generate a proxmox vma image file nom build .#aquamarine # `nom`(nix-output-monitor) can be replaced by the standard command `nix` -# 2. upload the genereated image to proxmox server's backup directory `/var/lib/vz/dump` +# 2. upload the generated image to proxmox server's backup directory `/var/lib/vz/dump` # please replace the vma file name with the one you generated in step 1. rsync -avz --progress --copy-links result root@um560:/var/lib/vz/dump/vzdump-qemu-aquamarine.vma.zst # 3. the image we uploaded will be listed in proxmox web ui's this page: [storage 'local'] -> [backups], we can restore a vm from it via the web ui now. ``` -Once the virtual machine `aquamarine` is created, we can deploy updates to it with the following commands: +Once the virtual machine `aquamarine` is created, we can deploy updates to it with the following +commands: ```shell # 1. add the ssh key to ssh-agent @@ -164,7 +182,8 @@ ssh-add /etc/agenix/ssh-key-romantic colmena apply --on '@dist-build' --show-trace ``` -If you're not familiar with remote deployment, please read this tutorial first: [Remote Deployment - NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/best-practices/remote-deployment) +If you're not familiar with remote deployment, please read this tutorial first: +[Remote Deployment - NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/best-practices/remote-deployment) ## References @@ -179,17 +198,22 @@ Other dotfiles that inspired me: - [davidtwco/veritas](https://github.com/davidtwco/veritas) - [gvolpe/nix-config](https://github.com/gvolpe/nix-config) - [Ruixi-rebirth/flakes](https://github.com/Ruixi-rebirth/flakes) - - [fufexan/dotfiles](https://github.com/fufexan/dotfiles): gtk theme, xdg, git, media, anyrun, etc. - - [nix-community/srvos](https://github.com/nix-community/srvos): a collection of opinionated and sharable NixOS configurations for servers + - [fufexan/dotfiles](https://github.com/fufexan/dotfiles): gtk theme, xdg, git, media, anyrun, + etc. + - [nix-community/srvos](https://github.com/nix-community/srvos): a collection of opinionated and + sharable NixOS configurations for servers - Modularized NixOS Configuration - [hlissner/dotfiles](https://github.com/hlissner/dotfiles) - [viperML/dotfiles](https://github.com/viperML/dotfiles) - Hyprland(wayland) - - [notwidow/hyprland](https://github.com/notwidow/hyprland): This is where I start my hyprland journey. - - [HeinzDev/Hyprland-dotfiles](https://github.com/HeinzDev/Hyprland-dotfiles): Refer to the waybar configuration here. + - [notwidow/hyprland](https://github.com/notwidow/hyprland): This is where I start my hyprland + journey. + - [HeinzDev/Hyprland-dotfiles](https://github.com/HeinzDev/Hyprland-dotfiles): Refer to the waybar + configuration here. - [linuxmobile/kaku](https://github.com/linuxmobile/kaku) - I3 Window Manager - - [endeavouros-i3wm-setup](https://github.com/endeavouros-team/endeavouros-i3wm-setup): I started using i3 here, and my i3 configuration is also based on it, but made a lot of changes. + - [endeavouros-i3wm-setup](https://github.com/endeavouros-team/endeavouros-i3wm-setup): I started + using i3 here, and my i3 configuration is also based on it, but made a lot of changes. - [denisse-dev/dotfiles](https://github.com/denisse-dev/dotfiles) - Neovim/AstroNvim - [maxbrunet/dotfiles](https://github.com/maxbrunet/dotfiles): astronvim with nix flakes. diff --git a/home/README.md b/home/README.md index e10704cf..096fe0bc 100644 --- a/home/README.md +++ b/home/README.md @@ -3,4 +3,3 @@ 1. `base`: The base module that is suitable for both Linux and macOS. 2. `linux`: Linux-specific configuration. 3. `darwin`: macOS-specific configuration. - diff --git a/home/base/README.md b/home/base/README.md index d132c6fb..b420cf92 100644 --- a/home/base/README.md +++ b/home/base/README.md @@ -3,4 +3,3 @@ 1. `server`: Configuration which is suitable for both servers and desktops. 1. `desktop`: Configuration for desktop environments, such as Hyprland, I3, etc. 1. `core.nix`: Minimal home-manager's config - diff --git a/home/base/core/editors/README.md b/home/base/core/editors/README.md index 20a82f7b..8db0eb14 100644 --- a/home/base/core/editors/README.md +++ b/home/base/core/editors/README.md @@ -1,4 +1,3 @@ # Editors See [desktop/editors/](../../desktop/editors/) for more details. - diff --git a/home/base/gui/terminal/README.md b/home/base/gui/terminal/README.md index 6c251c15..5ae5f616 100644 --- a/home/base/gui/terminal/README.md +++ b/home/base/gui/terminal/README.md @@ -1,21 +1,25 @@ -# Termianl Emulators +# Terminal Emulators -I used to spend a lot of time on terminal emulators, to make them match my taste, -but now I found that it's not worth it, **Zellij can provide a user-friendly and unified user experience for all terminal emulators! without any pain**! +I used to spend a lot of time on terminal emulators, to make them match my taste, but now I found +that it's not worth it, **Zellij can provide a user-friendly and unified user experience for all +terminal emulators! without any pain**! -Currently, I only use the most basic features of terminal emulators, such as true color, graphics protocol, etc. -Other features such as tabs, scrollback buffer, select/search/copy, etc, are all provided by zellij! +Currently, I only use the most basic features of terminal emulators, such as true color, graphics +protocol, etc. Other features such as tabs, scrollback buffer, select/search/copy, etc, are all +provided by zellij! My current terminal emulators are: 1. kitty: My main terminal emulator. - 1. to select/copy a large mount of text, We should do some tricks via kitty's `scrollback_pager` with neovim, it's really painful: + 1. to select/copy a large mount of text, We should do some tricks via kitty's `scrollback_pager` + with neovim, it's really painful: 2. wezterm: My secondary terminal emulator. - 1. its search ability is very basic, and it's not easy to use. - 1. its scrollback buffer's copy mode is very like vim, which is nice, but zellij's even better, it can use neovim as its default scrollback buffer's editor without any pain! + 1. its search ability is very basic, and it's not easy to use. + 1. its scrollback buffer's copy mode is very like vim, which is nice, but zellij's even better, + it can use neovim as its default scrollback buffer's editor without any pain! 3. foot: a fast, lightweight and minimalistic Wayland terminal emulator. - 1. foot only do the things a terminal emulator should do, no more, no less. - 1. It's really suitable for tiling window manager or zellij users! + 1. foot only do the things a terminal emulator should do, no more, no less. + 1. It's really suitable for tiling window manager or zellij users! ## 'xterm-kitty': unknown terminal type when `ssh` into a remote host or `sudo xxx` @@ -23,45 +27,55 @@ My current terminal emulators are: > https://wezfurlong.org/wezterm/config/lua/config/term.html -kitty set `TERM` to `xterm-kitty` by default, and TUI apps like `viu`, `yazi`, `curses` will try to search in the host's [terminfo(terminal capability data base)](https://linux.die.net/man/5/terminfo) for value of `TERM` to determine the capabilities of the terminal. +kitty set `TERM` to `xterm-kitty` by default, and TUI apps like `viu`, `yazi`, `curses` will try to +search in the host's [terminfo(terminal capability data base)](https://linux.die.net/man/5/terminfo) +for value of `TERM` to determine the capabilities of the terminal. -But when you `ssh` into a remote host, the remote host is very likely to not have `xterm-kitty` in its terminfo, so you will get this error: +But when you `ssh` into a remote host, the remote host is very likely to not have `xterm-kitty` in +its terminfo, so you will get this error: ``` 'xterm-kitty': unknown terminal type ``` -Or when you `sudo xxx`, `sudo` won't preserve the `TERM` variable, it will be reset to root's default `TERM` value, which is `xterm` or `xterm-256color` in most linux distributions, so you will get this error: +Or when you `sudo xxx`, `sudo` won't preserve the `TERM` variable, it will be reset to root's +default `TERM` value, which is `xterm` or `xterm-256color` in most linux distributions, so you will +get this error: ``` 'xterm-256color': unknown terminal type ``` -or +or ``` Error opening terminal: xterm-kitty. ``` -NixOS preserve the `TERMINFO` and `TERMINFO_DIRS` environment variables, for `root` and the `wheel` group: [nixpkgs/nixos/modules/config/terminfo.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/modules/config/terminfo.nix#L18) +NixOS preserve the `TERMINFO` and `TERMINFO_DIRS` environment variables, for `root` and the `wheel` +group: +[nixpkgs/nixos/modules/config/terminfo.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/modules/config/terminfo.nix#L18) For nix-darwin, take a look at ### Solutions -Simplest solution, it will automatically copy over the terminfo files and also magically enable shell integration on the remote machine: +Simplest solution, it will automatically copy over the terminfo files and also magically enable +shell integration on the remote machine: ``` kitten ssh user@host ``` -Or if you do not care about kitty's features(such as true color & graphics protocol), you can simply set `TERM` to `xterm-256color`, which is built-in in most linux distributions: +Or if you do not care about kitty's features(such as true color & graphics protocol), you can simply +set `TERM` to `xterm-256color`, which is built-in in most linux distributions: ``` export TERM=xterm-256color ``` -If you need kitty's features, but do not like the magic of `kitten`, you can manually install kitty's terminfo on the remote host: +If you need kitty's features, but do not like the magic of `kitten`, you can manually install +kitty's terminfo on the remote host: ```bash # install on ubuntu / debian @@ -70,4 +84,3 @@ sudo apt-get install kitty-terminfo # or copy from local machine infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin ``` - diff --git a/home/base/tui/editors/Glossary.md b/home/base/tui/editors/Glossary.md index 90538acc..a31b5fcf 100644 --- a/home/base/tui/editors/Glossary.md +++ b/home/base/tui/editors/Glossary.md @@ -6,7 +6,9 @@ > https://langserver.org/ -The Language Server Protocol (LSP) is an open, JSON-RPC-based protocol for use between source code editors or integrated development environments (IDEs) and servers that provide programming language-specific features like: +The Language Server Protocol (LSP) is an open, JSON-RPC-based protocol for use between source code +editors or integrated development environments (IDEs) and servers that provide programming +language-specific features like: - motions such as go-to-definition, find-references, hover. - **code completion** @@ -15,10 +17,11 @@ The Language Server Protocol (LSP) is an open, JSON-RPC-based protocol for use b - syntax highlighting (use Tree-sitter instead) - code formatting (use a dedicated formatter instead) -The goal of the protocol is to allow programming language support to be implemented and distributed independently of any given editor or IDE. +The goal of the protocol is to allow programming language support to be implemented and distributed +independently of any given editor or IDE. -LSP was originally developed for Microsoft Visual Studio Code and is now an open standard. -In the early 2020s LSP quickly became a "norm" for language intelligence tools providers. +LSP was originally developed for Microsoft Visual Studio Code and is now an open standard. In the +early 2020s LSP quickly became a "norm" for language intelligence tools providers. ### Tree-sitter @@ -26,7 +29,9 @@ In the early 2020s LSP quickly became a "norm" for language intelligence tools p > https://www.reddit.com/r/neovim/comments/1109wgr/treesitter_vs_lsp_differences_ans_overlap/ -Tree-sitter is a parser generator tool and an **incremental parsing** library. It can build a concrete syntax tree for a source file and efficiently update the syntax tree as the source file is edited. +Tree-sitter is a parser generator tool and an **incremental parsing** library. It can build a +concrete syntax tree for a source file and efficiently update the syntax tree as the source file is +edited. It is used by many editors and IDEs to provide: @@ -38,17 +43,22 @@ It is used by many editors and IDEs to provide: - such as join/split lines, structural editing, cursor motion, etc. **Treesitter process each file independently**, and it is not aware of the semantics of your code. -For example, it does not know does a function/variable really exist, or what is the type/return-type of a variable. This is where LSP comes in. +For example, it does not know does a function/variable really exist, or what is the type/return-type +of a variable. This is where LSP comes in. -The LSP server parses the code much more deeply and it **not only parses a single file but your whole project**. -So, the LSP server will know whether a function/variable does exist with the same type/return-type. If it does not, it will mark it as an error. +The LSP server parses the code much more deeply and it **not only parses a single file but your +whole project**. So, the LSP server will know whether a function/variable does exist with the same +type/return-type. If it does not, it will mark it as an error. **LSP does understand the code semantically, while Treesitter only cares about correct syntax**. #### LSP vs Tree-sitter -- Tree-sitter: lightweight, fast, but limited knowledge of your code. mainly used for **syntax highlighting, indentation, and folding/refactoring in a single file**. -- LSP: heavy and slow on large projects, but it has a deep understanding of your code. mainly used for **code completion, refactoring in the projects, errors/warnings, and other semantic-aware features**. +- Tree-sitter: lightweight, fast, but limited knowledge of your code. mainly used for **syntax + highlighting, indentation, and folding/refactoring in a single file**. +- LSP: heavy and slow on large projects, but it has a deep understanding of your code. mainly used + for **code completion, refactoring in the projects, errors/warnings, and other semantic-aware + features**. ### Formatter vs Linter @@ -56,7 +66,10 @@ Linting is distinct from Formatting because: 1. **formatting** only restructures how code appears. 1. `prettier` is a popular formatter. -1. **linting** analyzes how the code runs and detects errors, it may also suggest improvements such as replace `var` with `let` or `const`. +1. **linting** analyzes how the code runs and detects errors, it may also suggest improvements such + as replace `var` with `let` or `const`. -Formatters and Linters process each file independently, they do not need to know about other files in the project. - * [ ] +Formatters and Linters process each file independently, they do not need to know about other files +in the project. + +- [ ] diff --git a/home/base/tui/editors/README.md b/home/base/tui/editors/README.md index 7ae348ab..bb3cf686 100644 --- a/home/base/tui/editors/README.md +++ b/home/base/tui/editors/README.md @@ -10,15 +10,18 @@ And `Zellij` for a smooth and stable terminal experience. ## Tips -1. Many useful keys are already provided by vim, check vim/neovim's docs before you install a new plugin / reinvent the wheel. -1. After using Emacs/Neovim more skillfully, I strongly recommend that you read the official documentation of Neovim/vim: +1. Many useful keys are already provided by vim, check vim/neovim's docs before you install a new + plugin / reinvent the wheel. +1. After using Emacs/Neovim more skillfully, I strongly recommend that you read the official + documentation of Neovim/vim: 1. : The official vim documentation. 1. : Neovim's official user documentation. 1. Use Zellij for terminal related operations, and use Neovim/Helix for editing. 1. As for Emacs, Use its GUI version & terminal emulator `vterm` for terminal related operations. 1. Two powerful file search & jump tools: 1. Tree-view plugins are beginner-friendly and intuitive, but they're not very efficient. -1. **Search by the file path**: Useful when you're familiar with the project structure, especially on a large project. +1. **Search by the file path**: Useful when you're familiar with the project structure, especially + on a large project. 1. **Search by the content**: Useful when you're familiar with the code. ## Tutorial @@ -27,13 +30,16 @@ Type `:tutor`(`:Tutor` in Neovim) to learn the basics usage of vim/neovim. ## VIM's Cheetsheet -> Here only record my commonly used keys, to see **a more comprehensive cheetsheet**: +> Here only record my commonly used keys, to see **a more comprehensive cheetsheet**: +> -Both Emacs-Evil & Neovim are compatible with vim, sothe key-bindings described here are common in both Emacs-Evil, Neovim & vim. +Both Emacs-Evil & Neovim are compatible with vim, sothe key-bindings described here are common in +both Emacs-Evil, Neovim & vim. ### Terminal Related -I mainly use Zellij for terminal related operations, here is its terminal shortcuts I use frequently now: +I mainly use Zellij for terminal related operations, here is its terminal shortcuts I use frequently +now: | Action | Zellij's Shortcut | | ------------------------- | ----------------- | @@ -76,10 +82,12 @@ I mainly use Zellij for terminal related operations, here is its terminal shortc Text Objects: -- **sentence**: text ending at a '.', '!' or '?' followed by either the end of a line, or by a space or tab. +- **sentence**: text ending at a '.', '!' or '?' followed by either the end of a line, or by a space + or tab. - **paragraph**: text ending at a blank line. -- **section**: text starting with a section header and ending at the start of the next section header (or at the end of the file). - The "`]]`" and "`[[`" commands stop at the '`{`' in the first column. This is - useful to find the start of a function in a C/Go/Java/... program. +- **section**: text starting with a section header and ending at the start of the next section + header (or at the end of the file). - The "`]]`" and "`[[`" commands stop at the '`{`' in the + first column. This is useful to find the start of a function in a C/Go/Java/... program. ### Text Manipulation @@ -99,7 +107,7 @@ Basics: | Toggle text's case | `~` | | Convert to uppercase | `U` (visual mode) | | Convert to lowercase | `u` (visual mode) | -| Align the selected conent | `:center`/`:left`/`:right` | +| Align the selected content | `:center`/`:left`/`:right` | Misc: @@ -116,7 +124,7 @@ Misc: | Action | | | ------------------------------------------------------------------------- | -------------- | -| Sort tye selected lines | `:sort` | +| Sort the selected lines | `:sort` | | Join Selection of Lines With Space | `:join` or `J` | | Join without spaces | `:join!` | | Enter Insert mode at the start/end of the line | `I` / `A` | @@ -161,7 +169,8 @@ Advance Techs: | Replace all the lines | `:% s/old/new/g` | | Replace all the lines with regex | `:% s@\vhttp://(\w+)@https://\1@gc` | -1. `\v` means means that in the regex pattern after it can be used without backslash escaping(similar to python's raw string). +1. `\v` means means that in the regex pattern after it can be used without backslash + escaping(similar to python's raw string). 2. `\1` means the first matched group in the pattern. ### Replace in the specific lines diff --git a/home/base/tui/editors/Structured-Editing.md b/home/base/tui/editors/Structured-Editing.md index 601a724d..84cc0ad3 100644 --- a/home/base/tui/editors/Structured-Editing.md +++ b/home/base/tui/editors/Structured-Editing.md @@ -2,23 +2,24 @@ ## S-expression data(Lisp) -- paredit/[lispy](https://github.com/doomemacs/doomemacs/tree/master/modules/editor/lispy): too complex. +- paredit/[lispy](https://github.com/doomemacs/doomemacs/tree/master/modules/editor/lispy): too + complex. - [evil-cleverparens](https://github.com/emacs-evil/evil-cleverparens): simple and useful. -- [parinfer(par-in-fer)](https://shaunlebron.github.io/parinfer/): morden, simple, elegant and useful, but works not well with some other completion plugins... - - to make parinfer works, you should disable sexp & smartparens in any lisp mode. +- [parinfer(par-in-fer)](https://shaunlebron.github.io/parinfer/): morden, simple, elegant and + useful, but works not well with some other completion plugins... + - to make parinfer works, you should disable sexp & smartparens in any lisp mode. Some plugins: - Emacs - - [parinfer-rusT-mode](https://github.com/justinbarclay/parinfer-rust-mode) + - [parinfer-rusT-mode](https://github.com/justinbarclay/parinfer-rust-mode) - Neovim - - [parinfer-rust](https://github.com/eraserhd/parinfer-rust) - - + - [parinfer-rust](https://github.com/eraserhd/parinfer-rust) + - - Helix - - [parinfer #4090 - Helix](https://github.com/helix-editor/helix/discussions/4090) + - [parinfer #4090 - Helix](https://github.com/helix-editor/helix/discussions/4090) ## Other Languages 1. treesitter 1. ... - diff --git a/home/base/tui/editors/emacs/README.md b/home/base/tui/editors/emacs/README.md index e299ddde..e3bc9fb7 100644 --- a/home/base/tui/editors/emacs/README.md +++ b/home/base/tui/editors/emacs/README.md @@ -6,17 +6,19 @@ 2. Org Mode 3. Lisp Coding 4. A top-level tutorial for Emacs(Chinese): -5. A Beginner's Guide to Emacs(Chinese): +5. A Beginner's Guide to Emacs(Chinese): + ## Screenshot ![](/_img/emacs-2024-01-07.webp) -## Usefull Links +## Useful Links - Framework: - key bindings: - - source code: + - source code: + - docs: - module index: - LSP Client: @@ -44,7 +46,7 @@ when in doubt, run `doom sync`! ```bash # testing just emacs-test -jsut emacs-purge +just emacs-purge just emacs-reload # clear test data @@ -59,14 +61,16 @@ just emacs-clean - So vim/neovim is still the best choice for servers. - Emacs's markdown-mode works not well with tables, see: - https://github.com/jrblevin/markdown-mode/issues/380 -- I use git command frequently, but doomemacs only autoupdates status of git diff / treemacs when using magit. +- I use git command frequently, but doomemacs only autoupdates status of git diff / treemacs when + using magit. - I have to learn magit to avoid this issue... - GitHub's orgmode support is not well, Markdown is better for GitHub. - Use markdown for repo's README.md, and use orgmode for my personal notes and docs only. ## Cheetsheet -Here is the cheetsheet related to my DoomEmacs configs. Please read vim's common cheetsheet at [../README.md](../README.md) before reading the following. +Here is the cheetsheet related to my DoomEmacs configs. Please read vim's common cheetsheet at +[../README.md](../README.md) before reading the following. ### Basics @@ -98,7 +102,8 @@ Here is the cheetsheet related to my DoomEmacs configs. Please read vim's common ### File Tree - treemacs: -- treemacs-evil: +- treemacs-evil: + | Action | Shortcut | | ------------------------------------- | --------- | @@ -199,8 +204,9 @@ Magit is a powerful tool that make git operations easy and intuitive. Shortcuts in magit's pane: -> When run `git commit` / `git add` / `git push` /... via magit, multiple Arguments can be set. -> Set arguments won't trigger a git command immediately. Magit will try to run a git command only after an Action key is pressed. +> When run `git commit` / `git add` / `git push` /... via magit, multiple Arguments can be set. Set +> arguments won't trigger a git command immediately. Magit will try to run a git command only after +> an Action key is pressed. | Action | Shortcut | | -------------------------------------------------- | --------------------------------------------- | @@ -220,4 +226,5 @@ Shortcuts in magit's pane: | Fold/Unfold | `TAB` | | Show details of the current unit(commit/stage/...) | `` | -KeyBinding full list: +KeyBinding full list: + diff --git a/home/base/tui/editors/helix/README.md b/home/base/tui/editors/helix/README.md index b9788744..0325e87e 100644 --- a/home/base/tui/editors/helix/README.md +++ b/home/base/tui/editors/helix/README.md @@ -1,11 +1,14 @@ # Helix Editor -Neovim is really powerful, and have a very active community. I use it as my main editor, and I'm very happy with it. I use it for everything, from writing code to writing this document. +Neovim is really powerful, and have a very active community. I use it as my main editor, and I'm +very happy with it. I use it for everything, from writing code to writing this document. -But its configuration is a bit complex, and finding the right plugins, writing configurations, and keeping everything up to date is not easy. +But its configuration is a bit complex, and finding the right plugins, writing configurations, and +keeping everything up to date is not easy. -That's why I'm interested in Helix, Helix is similar to Neovim, but it's more opinionated, and it's batteries included. -Whether I'll switch my main editor to Helix or not, it gives me a lot of ideas on how to improve my Neovim workflow. +That's why I'm interested in Helix, Helix is similar to Neovim, but it's more opinionated, and it's +batteries included. Whether I'll switch my main editor to Helix or not, it gives me a lot of ideas +on how to improve my Neovim workflow. ## Tutorial @@ -14,30 +17,48 @@ Use `:tutor` in helix to start the tutorial. ## Differences between Neovim and Helixer 1. Selecting first, then action. - 1. Helix: delete 2 word: `2w` then `x`. You can always see what you're selecting before you apply the action. - 2. Neovim: delete 2 word: `d`. then `2w`. No visual feedback before you apply the action. -1. Helix - Morden builtin features: LSP, tree-sitter, fuzzy finder, multi cursors, surround and more. - 1. They're all available in Neovim too, but you need to find and use the right plugins manually, which takes time and effort. -1. Helix is built in Rust from scratch. The result is a much smaller codebase and a modern set of defaults. No VimScript. No Lua. - 1. Neovim contains a lot of VimScript, and lua is too dynamic, it's hard to debug. - 1. Personally I'm glad to take a look at a Rust codebase, but not a VimScript/Lua codebase. -1. Neovim have a very activate plugin ecosystem, and it's easy to find plugins for almost everything. - 1. Helix is still new, and it even do have a stable plugin system yet. A PR to add a plugin system is still envolving: -2. Neovim has intergrated terminal, and it's very powerful. It's quite similar to VSCode's intergrated terminal. I use it a lot. - 1. Helix doesn't have a intergrated terminal yet, as it's complicated to implement. Users are recommended to use tmux/Zellij or Wezterm/Kitty to implement this feature instead. - 1. - 1. - 1. **My Neovim often gets stuck when I switch to [toggleterm.nvim](https://github.com/akinsho/toggleterm.nvim), this Helix issue made me consider to switch from this Neovim plugin to Zellij**. -1. Helix do not have a tree-view panel, it's recommended to use Yazi/ranger/Broot instead, and open Helix in them. - 1. a tree-view plugin may be added after the plugin system is stable, but no one knows when it will be. - 2. and some Helix users stated that they don't need a tree-view plugin, Helix's file picker is useful and good enough. -1. It seems Helix lacks a global substitution command, you should run it in another window(via wm or Zellij). - 1. - 1. Neovim's substitution command allow you to preview the changes before you apply it, and it's very useful. if I switch to Helix, I'll need to find some other tools with similar feature(such as https://github.com/ms-jpq/sad). -1. Complexity and Maintenance Costs vs Batteries Included: + 1. Helix: delete 2 word: `2w` then `x`. You can always see what you're selecting before you apply + the action. + 2. Neovim: delete 2 word: `d`. then `2w`. No visual feedback before you apply the action. +1. Helix - Morden builtin features: LSP, tree-sitter, fuzzy finder, multi cursors, surround and + more. + 1. They're all available in Neovim too, but you need to find and use the right plugins manually, + which takes time and effort. +1. Helix is built in Rust from scratch. The result is a much smaller codebase and a modern set of + defaults. No VimScript. No Lua. + 1. Neovim contains a lot of VimScript, and lua is too dynamic, it's hard to debug. + 1. Personally I'm glad to take a look at a Rust codebase, but not a VimScript/Lua codebase. +1. Neovim have a very activate plugin ecosystem, and it's easy to find plugins for almost + everything. + 1. Helix is still new, and it even do have a stable plugin system yet. A PR to add a plugin + system is still envolving: +1. Neovim has integrated terminal, and it's very powerful. It's quite similar to VSCode's integrated + terminal. I use it a lot. + 1. Helix doesn't have a integrated terminal yet, as it's complicated to implement. Users are + recommended to use tmux/Zellij or Wezterm/Kitty to implement this feature instead. + 1. + 1. + 1. **My Neovim often gets stuck when I switch to + [toggleterm.nvim](https://github.com/akinsho/toggleterm.nvim), this Helix issue made me + consider to switch from this Neovim plugin to Zellij**. +1. Helix do not have a tree-view panel, it's recommended to use Yazi/ranger/Broot instead, and open + Helix in them. + 1. a tree-view plugin may be added after the plugin system is stable, but no one knows when it + will be. + 2. and some Helix users stated that they don't need a tree-view plugin, Helix's file picker is + useful and good enough. +1. It seems Helix lacks a global substitution command, you should run it in another window(via wm or + Zellij). + 1. + 1. Neovim's substitution command allow you to preview the changes before you apply it, and it's + very useful. if I switch to Helix, I'll need to find some other tools with similar + feature(such as https://github.com/ms-jpq/sad). +1. Complexity and Maintenance Costs vs Batteries Included: + +I think Use Helix/Neovim within a terminal file manager(Yazi/ranger/Broot) and Zellij is a good +idea. It's quite different from the workflow I migrated from VSCode/JetBrains before, I'm very +interested in it. -I think Use Helix/Neovim within a terminal file manager(Yazi/ranger/Broot) and Zellij is a good idea. -It's quite different from the workflow I migrated from VSCode/JetBrains before, I'm very interested in it. - -In Neovim I can make the workflow similar to VSCode/JetBrains by using some plugins, but Helix forces me to get out of my comfort zone, and try something new. +In Neovim I can make the workflow similar to VSCode/JetBrains by using some plugins, but Helix +forces me to get out of my comfort zone, and try something new. diff --git a/home/base/tui/editors/neovim/README.md b/home/base/tui/editors/neovim/README.md index 0187ec15..b2c5873a 100644 --- a/home/base/tui/editors/neovim/README.md +++ b/home/base/tui/editors/neovim/README.md @@ -1,14 +1,14 @@ # Neovim Editor -My Neovim config based on [AstroNvim](https://github.com/AstroNvim/AstroNvim). -For more details, visit the [AstroNvim website](https://astronvim.com/). +My Neovim config based on [AstroNvim](https://github.com/AstroNvim/AstroNvim). For more details, +visit the [AstroNvim website](https://astronvim.com/). -This document outlines neovim's configuration structure and various shortcuts/commands for efficient usage. +This document outlines neovim's configuration structure and various shortcuts/commands for efficient +usage. ## Screenshots -![](/_img/astronvim_2023-07-13_00-39.webp) -![](/_img/hyprland_2023-07-29_2.webp) +![](/_img/astronvim_2023-07-13_00-39.webp) ![](/_img/hyprland_2023-07-29_2.webp) ## Configuration Structure @@ -47,7 +47,8 @@ just nvim-clear ## Cheetsheet -Here is the cheetsheet related to my Neovim configs. Please read vim's common cheetsheet at [../README.md](../README.md) before reading the following. +Here is the cheetsheet related to my Neovim configs. Please read vim's common cheetsheet at +[../README.md](../README.md) before reading the following. ### Incremental Selection @@ -62,15 +63,16 @@ Provided by nvim-treesitter. ### Search and Jump -Provided by [flash.nvim](https://github.com/folke/flash.nvim), it's a intelligent search and jump plugin. +Provided by [flash.nvim](https://github.com/folke/flash.nvim), it's a intelligent search and jump +plugin. -1. It enhaces the default search and jump behavior of neovim.(search with prefix `/`) +1. It enhances the default search and jump behavior of neovim.(search with prefix `/`) -| Action | Shortcut | -| ----------------- | ------------------------------------------------------------------------------------------------------------- | -| Search | `/`(normal search), `s`(disable all code highlight, only highlight matches) | -| Treesitter Search | `yR`,`dR`, `cR`, `vR`, `ctrl+v+R`(arround your matches, all the surrounding Treesitter nodes will be labeled) | -| Remote Flash | `yr`, `dr`, `cr`, (arround your matches, all the surrounding Treesitter nodes will be labeled) | +| Action | Shortcut | +| ----------------- | ------------------------------------------------------------------------------------------------------------ | +| Search | `/`(normal search), `s`(disable all code highlight, only highlight matches) | +| Treesitter Search | `yR`,`dR`, `cR`, `vR`, `ctrl+v+R`(around your matches, all the surrounding Treesitter nodes will be labeled) | +| Remote Flash | `yr`, `dr`, `cr`, (around your matches, all the surrounding Treesitter nodes will be labeled) | ### Commands & Shortcuts @@ -92,12 +94,8 @@ Provided by [flash.nvim](https://github.com/folke/flash.nvim), it's a intelligen ### Splitting and Buffers -| -| Action | Shortcut | -| --------------------- | ------------- | -| Horizontal Split | `\` | -| Vertical Split | `\|` | -| Close Buffer | ` + c` | +| | Action | Shortcut | | --------------------- | ------------- | | Horizontal Split | `\` | | +Vertical Split | `\|` | | Close Buffer | ` + c` | ### Editing and Formatting @@ -129,9 +127,9 @@ Press ` + D` to view available bindings and options. ### Search and Replace Globally -| Description | Shortcut | -| ------------------------------------------------------------ | ---------------------------------------------------------------- | -| Open spectre.nvim search and replace panel | ` + ss` | +| Description | Shortcut | +| ------------------------------------------ | -------------- | +| Open spectre.nvim search and replace panel | ` + ss` | Search and replace via cli(fd + sad + delta): @@ -139,7 +137,6 @@ Search and replace via cli(fd + sad + delta): fd "\\.nix$" . | sad '' '' | delta ``` - ### Surrounding Characters Provided by mini.surround plugin. diff --git a/home/base/tui/encryption/README.md b/home/base/tui/encryption/README.md index abaf2abb..57fc413e 100644 --- a/home/base/tui/encryption/README.md +++ b/home/base/tui/encryption/README.md @@ -1,30 +1,31 @@ # Encryption -We have GnuPG & password-store installed by default, mainly for password management, authentication & communication encryption. +We have GnuPG & password-store installed by default, mainly for password management, authentication +& communication encryption. -We also have LUKS2 for disk encryption on Linux, and [rclone](https://rclone.org/crypt/) for cross-platform data encryption & syncing. +We also have LUKS2 for disk encryption on Linux, and [rclone](https://rclone.org/crypt/) for +cross-platform data encryption & syncing. [age](https://github.com/FiloSottile/age) may be more general for file encryption. -[Sops](https://github.com/getsops/sops/tree/main) can be used for file encryption too, if you prefer +[Sops](https://github.com/getsops/sops/tree/main) can be used for file encryption too, if you prefer using a Cloud provider for key management. - ## Asymmetric Encryption -Both age, Sops & GnuPG provide asymmetric encryption, which is useful for encrypting files for a specific user. +Both age, Sops & GnuPG provide asymmetric encryption, which is useful for encrypting files for a +specific user. -For morden use, age is recommended, as it use [AEAD encryption function - ChaCha20-Poly1305][age Format v1], -If you do not want to manage the keys by yourself, Sops is recommended, as it use KMS for key management. +For morden use, age is recommended, as it use [AEAD encryption function - +ChaCha20-Poly1305][age Format v1], If you do not want to manage the keys by yourself, Sops is +recommended, as it use KMS for key management. ## Symmetric Encryption -Both age & GnuPG provide symmetric encryption, which is useful for encrypting files for a specific user. - -As described in [age Format v1][age Format v1], age use scrypt to encrypt and decrypt the file key with a provided passphrase, -which is more secure than GnuPG's symmetric encryption. - +Both age & GnuPG provide symmetric encryption, which is useful for encrypting files for a specific +user. +As described in [age Format v1][age Format v1], age use scrypt to encrypt and decrypt the file key +with a provided passphrase, which is more secure than GnuPG's symmetric encryption. [age Format v1]: https://age-encryption.org/v1 - diff --git a/home/base/tui/gpg/README.md b/home/base/tui/gpg/README.md index 1be8627b..5dbec231 100644 --- a/home/base/tui/gpg/README.md +++ b/home/base/tui/gpg/README.md @@ -1,10 +1,14 @@ # GNU Privacy Guard(GnuPG) -> Offical Website: https://www.gnupg.org/ +> Official Website: https://www.gnupg.org/ -The GNU Privacy Guard is a complete and free implementation of the OpenPGP standard as defined by RFC4880 (also known as **PGP**). GnuPG allows to encrypt and sign your data and communication, features a versatile key management system as well as access modules for all kind of public key directories. +The GNU Privacy Guard is a complete and free implementation of the OpenPGP standard as defined by +RFC4880 (also known as **PGP**). GnuPG allows to encrypt and sign your data and communication, +features a versatile key management system as well as access modules for all kind of public key +directories. -> In the following content, we will use GPG to refer to GnuPG tool, and PGP to refer to various concepts defined in the OepnPGP standard(e.g. PGP key, PGP key server). +> In the following content, we will use GPG to refer to GnuPG tool, and PGP to refer to various +> concepts defined in the OepnPGP standard(e.g. PGP key, PGP key server). Key functions of GnuPG: @@ -20,18 +24,21 @@ Main usage scenarios of GnuPG: 3. Manage your ssh key 4. Encrypt your data and store it somewhere. -GnuPG/OpenPGP is complex, so while using it, I have been looking forward to finding an encryption tool that is simple enough, functional enough, and widely adopted. +GnuPG/OpenPGP is complex, so while using it, I have been looking forward to finding an encryption +tool that is simple enough, functional enough, and widely adopted. Currently I use both age & GnuPG: 1. Age for secrets encryption(ssh key & other secret files), it's simple and easy to use. 2. GnuPG for password-store and email encryption. -> At present, the safe and efficient use of GPG is probably combined with hardware keys such as yubikey. but I don't have one, so I won't talk about it here. +> At present, the safe and efficient use of GPG is probably combined with hardware keys such as +> yubikey. but I don't have one, so I won't talk about it here. ## Practical Cryptography for Developers -To use GnuGP without seamlessly, Some Practical Cryptography knowledge is required, here is dome tutorials: +To use GnuGP without seamlessly, Some Practical Cryptography knowledge is required, here is dome +tutorials: - English version: - Chinese version: @@ -50,12 +57,14 @@ Related Docs: - [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys] - [OpenPGP - The almost perfect key pair][OpenPGP - The almost perfect key pair] +GnuPG generate every secret key separately, and encrypt them with a symmetric key derived from your +passphrase. OpenPGP standard defines +[String-to-Key (S2K)](https://datatracker.ietf.org/doc/html/rfc4880#section-3.7) algorithm to derive +a symmetric key from your passphrase. -GnuPG generate every secret key separately, and encrypt them with a symmetric key derived from your passphrase. -OpenPGP standard defines [String-to-Key (S2K)](https://datatracker.ietf.org/doc/html/rfc4880#section-3.7) -algorithm to derive a symmetric key from your passphrase. - -GnuPG's [OpenPGP protocol specific options](https://gnupg.org/documentation/manuals/gnupg/OpenPGP-Options.html#OpenPGP-Options) shows that: +GnuPG's +[OpenPGP protocol specific options](https://gnupg.org/documentation/manuals/gnupg/OpenPGP-Options.html#OpenPGP-Options) +shows that: ``` --s2k-cipher-algo name @@ -81,24 +90,31 @@ gpg --s2k-mode 3 --s2k-count 65011712 --s2k-digest-algo SHA512 --s2k-cipher-algo To use the strongest options globally, you can specify these options in your `~/.gnupg/gpg.conf`. I've added them to my Home Manager's `programs.gpg.settings` option. - ### 1. PGP Key(Primary Key) generation Key management is the core of OpenPGP standard / GnuPG. -GnuPG uses public-key cryptography so that users may communicate securely. In a public-key system, each user has a pair of keys consisting of a private key and a public key. **A user's private key is kept secret; it need **never be revealed. The public key may be given to anyone with whom the user wants to communicate**. GnuPG uses a somewhat more sophisticated scheme in which a user has a primary keypair and then zero or more additional subordinate keypairs. The primary and subordinate keypairs are bundled to facilitate key management and the bundle can often be considered simply as one keypair, or a keyring/keychain(which contains multiple sub key-pairs). +GnuPG uses public-key cryptography so that users may communicate securely. In a public-key system, +each user has a pair of keys consisting of a private key and a public key. **A user's private key is +kept secret; it need **never be revealed. The public key may be given to anyone with whom the user +wants to communicate\*\*. GnuPG uses a somewhat more sophisticated scheme in which a user has a +primary keypair and then zero or more additional subordinate keypairs. The primary and subordinate +keypairs are bundled to facilitate key management and the bundle can often be considered simply as +one keypair, or a keyring/keychain(which contains multiple sub key-pairs). Let's generate a keypair interactively: -> Now in 2024, GnuPG 2.4.1 defaults to ECC algorithm (9) and Curve 25519 for ECC, which is morden and safe, I would recommend to use these defaults directly. +> Now in 2024, GnuPG 2.4.1 defaults to ECC algorithm (9) and Curve 25519 for ECC, which is morden +> and safe, I would recommend to use these defaults directly. ```bash gpg --full-gen-key ``` -This command will ask you for some algorithm related settings(ECC & Curve 25519), your personal info, and a strong passphrase to protect your PGP key. e.g. +This command will ask you for some algorithm related settings(ECC & Curve 25519), your personal +info, and a strong passphrase to protect your PGP key. e.g. -``` bash +```bash › gpg --full-gen-key gpg (GnuPG) 2.4.1; Copyright (C) 2023 g10 Code GmbH This is free software: you are free to change and redistribute it. @@ -131,9 +147,9 @@ Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. -Real name: -Email address: -Comment: +Real name: +Email address: +Comment: You selected this USER-ID: "Ryan Yin (For pass For Work ssh only) " @@ -163,7 +179,7 @@ sub cv25519 2024-01-09 [E] [expires: 2034-01-04] The generated keys are stored in `~/.gnupg` by default, the functions of each file are as follows: -``` bash +```bash › tree ~/.gnupg/ /Users/ryan/.gnupg/ |-- S.gpg-agent # socket file @@ -185,28 +201,41 @@ The generated keys are stored in `~/.gnupg` by default, the functions of each fi 4 directories, 12 files ``` -The functions of most files are quite clear at a glance, but the `trustdb.gpg` in them is a bit difficult to understand. Here are the details: +The functions of most files are quite clear at a glance, but the `trustdb.gpg` in them is a bit +difficult to understand. Here are the details: -Home Manager will manage all the things in `~/.gnupg/` EXCEPT `~/.gnupg/openpgp-revocs.d/` and `~/.gnupg/private-keys-v1.d/`, which is expected. +Home Manager will manage all the things in `~/.gnupg/` EXCEPT `~/.gnupg/openpgp-revocs.d/` and +`~/.gnupg/private-keys-v1.d/`, which is expected. ### 3. Sub Key Generation & Best Practice In PGP, every keys has a **usage flag** to indicate its usage: -- `C` means this key can be used to **Certify** other keys, which means this key can be used to **create/delete/revoke/modify** other keys. +- `C` means this key can be used to **Certify** other keys, which means this key can be used to + **create/delete/revoke/modify** other keys. - `S` means this key can be used to **Sign** data. -- `E` means this key can be used to **Encrypt** data. -- `A` means this key can be used to **Authenticate** data with various non-GnuPG programs. The key can be used as e.g. an **SSH key**. +- `E` means this key can be used to **Encrypt** data. +- `A` means this key can be used to **Authenticate** data with various non-GnuPG programs. The key + can be used as e.g. an **SSH key**. The **best practice** is: 1. Generate a primary key with strong cryptography arguments(such as ECC + Curve 25519). 2. Then generate 3 sub keys with `E`, `S` and `A` usage flag respectively. -3. **The Primary Key is extremely important**, Backup the primary key to somewhere absolutely safe(such as two encryptd USB drivers, keep them in different places), and then **delete it from your computer immediately**. -4. The sub key is also important, but you can generate a new one and replace it easily. You can backup it to somewhere else, and import it to another machine to use your keypair. -5. Backup your Primary key's revocation certificate to somewhere safe, it's the last way to rescure your safety if your primary key is compromised! - 1. It's a big problem if your revocation certificate is compromised, but not the bigest one. because it's only used to revoke your keypair, your data is still safe. But you should generate a new keypair and revoke the old one immediately. - 1. It will be a big problem if your primary key is compromised, and you don't have a revocation certificate to revoke it. But since OpenPGP do not have a good way to distribute revocation certificate, even you have a revocation certificate, it's still hard to distribute it to others... +3. **The Primary Key is extremely important**, Backup the primary key to somewhere absolutely + safe(such as two encryptd USB drivers, keep them in different places), and then **delete it from + your computer immediately**. +4. The sub key is also important, but you can generate a new one and replace it easily. You can + backup it to somewhere else, and import it to another machine to use your keypair. +5. Backup your Primary key's revocation certificate to somewhere safe, it's the last way to rescure + your safety if your primary key is compromised! +6. It's a big problem if your revocation certificate is compromised, but not the bigest one. because + it's only used to revoke your keypair, your data is still safe. But you should generate a new + keypair and revoke the old one immediately. +7. It will be a big problem if your primary key is compromised, and you don't have a revocation + certificate to revoke it. But since OpenPGP do not have a good way to distribute revocation + certificate, even you have a revocation certificate, it's still hard to distribute it to + others... To keep your keypair safe, you should backup your keypair according to the following steps. @@ -216,7 +245,7 @@ Now let's add the sub keys to the keypair we generated above: > GnuPG will ask you to input your passphrase to unlock your primary key. -``` bash +```bash › gpg --expert --edit-key ryan4yin@linux.com gpg (GnuPG) 2.4.1; Copyright (C) 2023 g10 Code GmbH This is free software: you are free to change and redistribute it. @@ -380,7 +409,7 @@ ssb ed25519 2024-01-09 [A] [expires: 2034-01-04] › gpg --list-public-keys ... ``` - + ### 4. Backup & Restore Export Public Keys(Both Primary Key & Sub Keys): @@ -393,10 +422,12 @@ nix run nixpkgs#pgpdump ryan4yin-gpg-keys.pub Export Primary Key(The exported key is still encrypted by your passphrase): -> the `!` at the end of the key ID is to force GnuPG to export only the specified key, not the subkeys. +> the `!` at the end of the key ID is to force GnuPG to export only the specified key, not the +> subkeys. -> GnuPG will ask you to input your passphrase to unlock your keypair, -> because GnuPG need to convert the secret key's format from its internal protection format to the one specified by the OpenPGP protocol. +> GnuPG will ask you to input your passphrase to unlock your keypair, because GnuPG need to convert +> the secret key's format from its internal protection format to the one specified by the OpenPGP +> protocol. ```bash # replace the key ID with your own sec key's ID @@ -416,16 +447,20 @@ Old: Secret Key Packet(tag 5)(134 bytes) Hash alg - SHA1(hash 2) Salt - 8c 78 58 c0 87 83 8c 2c Count - 65011712(coded count 255) - IV - xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx + IV - xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx Encrypted EdDSA x Encrypted SHA1 hash ... ``` -As [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys] says, we'll find that gpg ignored the `--s2k-count` option we specified when generating the keypair, and the `--s2k` related options we specified in `~/.gnupg/gpg.conf`, -the exported primary key is protectd by `SHA1` and `AES128`, which is not secure enough! +As [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys] says, we'll +find that gpg ignored the `--s2k-count` option we specified when generating the keypair, and the +`--s2k` related options we specified in `~/.gnupg/gpg.conf`, the exported primary key is protectd by +`SHA1` and `AES128`, which is not secure enough! -So to increase the security of the exported primary key, we need to encrypt it again with a stronger algorithm, I choose `age` here(which use `scrypt` to encrypt the file key with a provided passphrase): +So to increase the security of the exported primary key, we need to encrypt it again with a stronger +algorithm, I choose `age` here(which use `scrypt` to encrypt the file key with a provided +passphrase): ```bash # for simplicity, use the same passphrase as your gpg keypair here @@ -446,11 +481,14 @@ age --passphrase -o ryan4yin-gpg-subkeys.priv.age ryan4yin-gpg-subkeys.priv rm ryan4yin-gpg-subkeys.priv ``` -Your can import the exported Private Key via `gpg --import ` to restore it, but you need to decrypt it via age first. +Your can import the exported Private Key via `gpg --import ` to restore it, but you need to +decrypt it via age first. -As for Public Keys, please import your publicKeys via Home Manager's `programs.gpg.publicKeys` option, DO NOT import it manually(via `gpg --import `). +As for Public Keys, please import your publicKeys via Home Manager's `programs.gpg.publicKeys` +option, DO NOT import it manually(via `gpg --import `). -To ensure security, delete the master key and revoke the certificate immediately after the backup is completed: +To ensure security, delete the master key and revoke the certificate immediately after the backup is +completed: ```bash # delete the primary key and all its sub keys @@ -522,7 +560,8 @@ gpg --decrypt gpg -d ``` -If you just want to encrypt/decrypt a file quickly, you can use `age` with a passphrase, `gpg` can also do this, but it's not recommended(as age(scrypt)'s more secure): +If you just want to encrypt/decrypt a file quickly, you can use `age` with a passphrase, `gpg` can +also do this, but it's not recommended(as age(scrypt)'s more secure): ```bash # Encrypt a file via symmetric encryption(AES256), and output cleartext. @@ -538,27 +577,41 @@ gpg -d ### 7. Public Key Exchange & Revocation -In the case of many users, it is very difficult to exchange public keys securely and reliably with each other. -In the Web world, There is a **Chain of Trust**** to resolve this problem: +In the case of many users, it is very difficult to exchange public keys securely and reliably with +each other. In the Web world, There is a **Chain of Trust\*\*** to resolve this problem: - A Certificate Authority(CA) is responsible to verify & sign all the certificate signing request. - Web Server can safely transmit its Web Certificate to the client via TLS protocol. -- Client can verify the recevied Web Certificate via the CA's root certificate(which is built in Browser/OS). +- Client can verify the received Web Certificate via the CA's root certificate(which is built in + Browser/OS). But in OpenPGP: -- There is key servers to distribute(exchange) public keys, but it **do not verify the identity of the key owner**, and any uploaded data is **not allowed to be deleted**. Which make it **insecure and dangerous**. +- There is key servers to distribute(exchange) public keys, but it **do not verify the identity of + the key owner**, and any uploaded data is **not allowed to be deleted**. Which make it **insecure + and dangerous**. - Why key server is dangerous? - - Many PGP novices follow various tutorials to upload various key with personal privacy (such as real names) to the public key server, and then find that they can't delete them, which is very embarrassing. - - Anyone can upload a key to the key server, and claim that it is the key of a certain person(such as Linus), which is very insecure. + - Many PGP novices follow various tutorials to upload various key with personal privacy (such as + real names) to the public key server, and then find that they can't delete them, which is very + embarrassing. + - Anyone can upload a key to the key server, and claim that it is the key of a certain + person(such as Linus), which is very insecure. - **key server** is not recommend to use. -- GnuPG will generate revocation certificate when generating keypair(`~/.gnupg/private-keys-v1.d/`), anyone can import this certificate to revoke the keypair. But OpenPGP standard **DO NOT provide a way to distribute this certificate to others**. +- GnuPG will generate revocation certificate when generating + keypair(`~/.gnupg/private-keys-v1.d/`), anyone can import this certificate to revoke + the keypair. But OpenPGP standard **DO NOT provide a way to distribute this certificate to + others**. - Not to mention some key status query protocol like OCSP in Web PKI. - - Users has to pulish their revocation certificate to their blog, github profile or somewhere else, and others has to check it and run `gpg --import ` to revoke the keypair manually. + - Users has to pulish their revocation certificate to their blog, github profile or somewhere + else, and others has to check it and run `gpg --import ` to revoke the + keypair manually. -In summary, **there is no good way to distribute public keys and revoke them in OpenPGP**, which is a big problem. +In summary, **there is no good way to distribute public keys and revoke them in OpenPGP**, which is +a big problem. -Currently, You have to distribute your public key or revocation certificate via your blog, github profile, or somewhere else, and others has to check it and run `gpg --import` to import your public key or revocation certificate manually. +Currently, You have to distribute your public key or revocation certificate via your blog, github +profile, or somewhere else, and others has to check it and run `gpg --import` to import your public +key or revocation certificate manually. Anyway, let's try to revoke a keypair: @@ -615,7 +668,8 @@ STuJCp+gru6OtbTCu8Y2LugQeDh7UicM7Ak= -----END PGP PUBLIC KEY BLOCK----- ``` -As the revocation certificate says, we need to remove the first colon(`:`) before the 5 dashes(`-----BEGIN PGP PUBLIC KEY BLOCK-----`), then import it: +As the revocation certificate says, we need to remove the first colon(`:`) before the 5 +dashes(`-----BEGIN PGP PUBLIC KEY BLOCK-----`), then import it: ```bash › gpg --import gpg-test-revoke.rev @@ -646,7 +700,8 @@ gpg: 9E78E897B6490D6B: skipped: Unusable public key gpg: README.md: encryption failed: Unusable public key ``` -But if you delete the `trustdb.gpg` and `pubring.kbx`, then import the revoked public key again, it will be valid and usable again... which is very dangerous. +But if you delete the `trustdb.gpg` and `pubring.kbx`, then import the revoked public key again, it +will be valid and usable again... which is very dangerous. ## References @@ -654,7 +709,8 @@ But if you delete the `trustdb.gpg` and `pubring.kbx`, then import the revoked p - [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys] - [OpenPGP - The almost perfect key pair][OpenPGP - The almost perfect key pair] -[2021年,用更现代的方法使用PGP(上)]: https://ulyc.github.io/2021/01/13/2021%E5%B9%B4-%E7%94%A8%E6%9B%B4%E7%8E%B0%E4%BB%A3%E7%9A%84%E6%96%B9%E6%B3%95%E4%BD%BF%E7%94%A8PGP-%E4%B8%8A/ +[2021年,用更现代的方法使用PGP(上)]: + https://ulyc.github.io/2021/01/13/2021%E5%B9%B4-%E7%94%A8%E6%9B%B4%E7%8E%B0%E4%BB%A3%E7%9A%84%E6%96%B9%E6%B3%95%E4%BD%BF%E7%94%A8PGP-%E4%B8%8A/ [Predictable, Passphrase-Derived PGP Keys]: https://nullprogram.com/blog/2019/07/10/ -[OpenPGP - The almost perfect key pair]: https://blog.eleven-labs.com/en/openpgp-almost-perfect-key-pair-part-1/ - +[OpenPGP - The almost perfect key pair]: + https://blog.eleven-labs.com/en/openpgp-almost-perfect-key-pair-part-1/ diff --git a/home/base/tui/password-store/README.md b/home/base/tui/password-store/README.md index bd1daa11..2ebe61b8 100644 --- a/home/base/tui/password-store/README.md +++ b/home/base/tui/password-store/README.md @@ -16,32 +16,31 @@ To ensure security, we should change the GPG key every two or three years. Here 3. Update `./default.nix` to use the new GPG sub keys. 4. Check which Key `pass` currently uses: - ```bash - cd ~/.local/share/password-store/ - # check which key is used by pass - cat .gpg-id - # check which key is really used to encrypt the password - gpg --list-packets path/to/any/password.gpg - ``` -4. Change the key used by `pass`: - ```bash - # change the key used by pass, see `man pass` for more details - # you will be asked to enter the password of both the new and old keys - # then pass will re-encrypt all the passwords with the new key - pass init - ``` -5. Check if the key is changed: - ```bash - # check which key is used by pass - cat .gpg-id - # check which key is really used to encrypt the password - gpg --list-packets path/to/any/password.gpg - ``` -6. Delete the old GPG key pair: - ```bash - # delete the old key pair - gpg --delete-secret-keys - gpg --delete-keys - ``` - + ```bash + cd ~/.local/share/password-store/ + # check which key is used by pass + cat .gpg-id + # check which key is really used to encrypt the password + gpg --list-packets path/to/any/password.gpg + ``` +5. Change the key used by `pass`: + ```bash + # change the key used by pass, see `man pass` for more details + # you will be asked to enter the password of both the new and old keys + # then pass will re-encrypt all the passwords with the new key + pass init + ``` +6. Check if the key is changed: + ```bash + # check which key is used by pass + cat .gpg-id + # check which key is really used to encrypt the password + gpg --list-packets path/to/any/password.gpg + ``` +7. Delete the old GPG key pair: + ```bash + # delete the old key pair + gpg --delete-secret-keys + gpg --delete-keys + ``` diff --git a/home/base/tui/zellij/README.md b/home/base/tui/zellij/README.md index 3c6acec9..629d7edc 100644 --- a/home/base/tui/zellij/README.md +++ b/home/base/tui/zellij/README.md @@ -1,32 +1,39 @@ # Zellij - A workspace lives in your terminal -Zellij is a terminal workspace with batteries included. -At its core, it is a terminal multiplexer (similar to tmux and screen), but this is merely its infrastructure layer. +Zellij is a terminal workspace with batteries included. At its core, it is a terminal multiplexer +(similar to tmux and screen), but this is merely its infrastructure layer. -Zellij is very user-friendly and easy to use, with a step-by-step hint system that will help you get to know the keybindings, which is very like the Neovim or helix. +Zellij is very user-friendly and easy to use, with a step-by-step hint system that will help you get +to know the keybindings, which is very like the Neovim or helix. -> By contrast, tmux's key design is counterintuitive, there is no prompt system, and the plug-in performance is rubbish. It's really a pain to use. -> tmux's inital release was in 2007, it's too old, I would recommend any users that do not have a experience with multiplexer to use zellij instead of tmux. +> By contrast, tmux's key design is counterintuitive, there is no prompt system, and the plug-in +> performance is rubbish. It's really a pain to use. tmux's initial release was in 2007, it's too +> old, I would recommend any users that do not have a experience with multiplexer to use zellij +> instead of tmux. -## Why use zellij as the detault terminal environment? +## Why use zellij as the default terminal environment? -By auto start zellij on shell login, and exit the shell session on zellij exit, we can use zellij as the default terminal environment. +By auto start zellij on shell login, and exit the shell session on zellij exit, we can use zellij as +the default terminal environment. -By this way, We will only use the most basic features of the terminal emulator(kitty/alacritty/wezterm/...), -while most of the functions of terminal are provided by zellij. -Thus we can easily switch to any terminal emulator without losing any key functions, -and do not need to take care of the differences between different terminal emulators. +By this way, We will only use the most basic features of the terminal +emulator(kitty/alacritty/wezterm/...), while most of the functions of terminal are provided by +zellij. Thus we can easily switch to any terminal emulator without losing any key functions, and do +not need to take care of the differences between different terminal emulators. -And Zellij can be used not only locally, but also on any remote server, which is very convenient. Learn once and use everywhere! +And Zellij can be used not only locally, but also on any remote server, which is very convenient. +Learn once and use everywhere! > Yeah, you didn't misread it, zellij is very suitable for not only remotely, but also locally! -Some features such as search/copy/scrollback in different terminal emulators are implemented in different ways, and has different user experience. -For example, Wezterm's default search function is very basic, and it's not easy to use. Kitty's scrollback search/copy is really tricky to use. -As for some Editor such as Neovim, its intergrated terminal is really useful, but zellij is more powerful and useful than it, and more stable! -Zellij overcomes these problems, and provides a unified user experience for all terminal emulators! +Some features such as search/copy/scrollback in different terminal emulators are implemented in +different ways, and has different user experience. For example, Wezterm's default search function is +very basic, and it's not easy to use. Kitty's scrollback search/copy is really tricky to use. As for +some Editor such as Neovim, its integrated terminal is really useful, but zellij is more powerful +and useful than it, and more stable! Zellij overcomes these problems, and provides a unified user +experience for all terminal emulators! -Teminal emulators should only be responsible for displaying characters. +Terminal emulators should only be responsible for displaying characters. ## Passthrough mode(Lock Mode) @@ -34,6 +41,7 @@ Teminal emulators should only be responsible for displaying characters. It's extremely useful when you want to: -1. Use zellij locally for daily work, and use a remote zellij via ssh to do some work on the remote server. -1. To avoid the key conflicts between zellij and the program running in the terminal, such as vim, tmux, etc. - +1. Use zellij locally for daily work, and use a remote zellij via ssh to do some work on the remote + server. +1. To avoid the key conflicts between zellij and the program running in the terminal, such as vim, + tmux, etc. diff --git a/home/darwin/README.md b/home/darwin/README.md index fc3d4098..9fc4d1db 100644 --- a/home/darwin/README.md +++ b/home/darwin/README.md @@ -4,4 +4,3 @@ 2. `shell.nix`: shell related. 3. `rime-squirrel.nix`: [rime-squirrel](https://github.com/rime/squirrel)'s configuration. 4. `default.nix`: the entrypoint of darwin's configuration, it import all the submodules above. - diff --git a/home/linux/README.md b/home/linux/README.md index 4f73767b..0a301ab7 100644 --- a/home/linux/README.md +++ b/home/linux/README.md @@ -2,7 +2,9 @@ 1. `base`: The base module that is suitable for any NixOS environment. 2. `desktop`: Configuration for desktop environments, such as Hyprland, I3, etc. -6. `server.nix`: Configuration which is suitable for both servers and desktops. It import only `base` as its submodule. - 1. used by all my nixos servers. -7. `desktop.nix`: the entrypoint of desktop's configuration, it import both `base` and `desktop` as its submodules. - 1. used by all my nixos desktops. +3. `server.nix`: Configuration which is suitable for both servers and desktops. It import only + `base` as its submodule. + 1. used by all my nixos servers. +4. `desktop.nix`: the entrypoint of desktop's configuration, it import both `base` and `desktop` as + its submodules. + 1. used by all my nixos desktops. diff --git a/home/linux/desktop/README.md b/home/linux/desktop/README.md index c796d9a7..2568cf88 100644 --- a/home/linux/desktop/README.md +++ b/home/linux/desktop/README.md @@ -1,16 +1,18 @@ # Desktop Related - 3. `base`: all common configurations for all desktops. 4. `hyprland`: Hyprland's configuration. 5. `i3`: i3's configuration. - ## Why install I3/Hyprland in Home Manager instead of a NixOS Module? -1. I3 & Hyprland's configuration file is located in `~/.config`, which can be easily managed by Home Manager. -2. I have many user-specific systemd servcies, such gammastep, wallpaper-switcher, etc. Which can be easily managed by Home Manager, but if we add i3/hyprland in a NixOS Module, those user-level services may failed to start automatically. With i3/hyprland in a Home Manager Module, we can control their systemd service's dependent order more easily, so we can avoid issues like this. +1. I3 & Hyprland's configuration file is located in `~/.config`, which can be easily managed by Home + Manager. +2. I have many user-specific systemd services, such gammastep, wallpaper-switcher, etc. Which can be + easily managed by Home Manager, but if we add i3/hyprland in a NixOS Module, those user-level + services may failed to start automatically. With i3/hyprland in a Home Manager Module, we can + control their systemd service's dependent order more easily, so we can avoid issues like this. 3. By install packages as less as possible in NixOS Module, we can: - 1. Make the NixOS system more secure and stable. - 2. Make this flake more portable to other non-NixOS systems, as home-manager can be installed on any Linux system. - + 1. Make the NixOS system more secure and stable. + 2. Make this flake more portable to other non-NixOS systems, as home-manager can be installed on + any Linux system. diff --git a/home/linux/desktop/hyprland/conf/waybar/config.jsonc b/home/linux/desktop/hyprland/conf/waybar/config.jsonc index b9347d82..1afda573 100644 --- a/home/linux/desktop/hyprland/conf/waybar/config.jsonc +++ b/home/linux/desktop/hyprland/conf/waybar/config.jsonc @@ -2,15 +2,8 @@ "position": "top", "layer": "top", - "modules-left": [ - "custom/launcher", - "temperature", - "backlight", - "hyprland/workspaces" - ], - "modules-center": [ - "custom/playerctl" - ], + "modules-left": ["custom/launcher", "temperature", "backlight", "hyprland/workspaces"], + "modules-center": ["custom/playerctl"], "modules-right": [ "mpd", "pulseaudio", @@ -21,7 +14,7 @@ "clock", "idle_inhibitor", "custom/powermenu", - "tray" + "tray", ], "hyprland/workspaces": { "format": "{icon}", @@ -38,8 +31,8 @@ "9": "", "10": "〇", "focused": "", - "default": "" - } + "default": "", + }, }, "clock": { @@ -48,137 +41,123 @@ "rotate": 0, "tooltip-format": "{:%B %Y}\n{calendar}", "format": " {:%H:%M}", - "format-alt": " {:%a %b %d, %G}" + "format-alt": " {:%a %b %d, %G}", }, "cpu": { "format": "\udb80\udf5b {usage}%", "interval": 1, "on-click-middle": "kitty btop", - "on-click-right": "kitty btop" + "on-click-right": "kitty btop", }, "custom/launcher": { "format": "\uf313 ", "on-click": "$HOME/.config/hypr/scripts/menu", "on-click-middle": "exec default_wall", "on-click-right": "exec wallpaper_random", - "tooltip": false + "tooltip": false, }, "custom/powermenu": { "format": "\uf011", "on-click": "$HOME/.config/hypr/scripts/wlogout", - "tooltip": false + "tooltip": false, }, "idle_inhibitor": { "format": "{icon}", "format-icons": { "activated": "\uf06e", - "deactivated": "\uf070" + "deactivated": "\uf070", }, - "tooltip": false + "tooltip": false, }, "memory": { "format": "\udb83\udee0 {percentage}%", "interval": 1, "states": { - "warning": 85 - } + "warning": 85, + }, }, "mpd": { - "interval": 2, - "unknown-tag": "N/A", - "format": "{stateIcon} {artist} - {title}", - "format-disconnected": " Disconnected", - "format-paused": "{stateIcon} {artist} - {title}", - "format-stopped": "Stopped ", - "state-icons": { - "paused": "", - "playing": "" - }, - "tooltip-format": "MPD (connected)", - "tooltip-format-disconnected": "MPD (disconnected)", - // Commands to execute on events - "on-click": "mpc toggle", - "on-click-middle": "mpc prev", - "on-click-right": "mpc next", - "on-update": "", - "on-scroll-up": "mpc seek +00:00:01", - "on-scroll-down": "mpc seek -00:00:01", - "smooth-scrolling-threshold": 1 + "interval": 2, + "unknown-tag": "N/A", + "format": "{stateIcon} {artist} - {title}", + "format-disconnected": " Disconnected", + "format-paused": "{stateIcon} {artist} - {title}", + "format-stopped": "Stopped ", + "state-icons": { + "paused": "", + "playing": "", + }, + "tooltip-format": "MPD (connected)", + "tooltip-format-disconnected": "MPD (disconnected)", + // Commands to execute on events + "on-click": "mpc toggle", + "on-click-middle": "mpc prev", + "on-click-right": "mpc next", + "on-update": "", + "on-scroll-up": "mpc seek +00:00:01", + "on-scroll-down": "mpc seek -00:00:01", + "smooth-scrolling-threshold": 1, }, "custom/playerctl": { - "format": "{icon} {}", - "return-type": "json", - "max-length": 55, - "exec": "playerctl -a metadata --format '{\"text\": \" {{markup_escape(title)}}\", \"tooltip\": \"{{playerName}} : {{markup_escape(title)}}\", \"alt\": \"{{status}}\", \"class\": \"{{status}}\"}' -F", - "on-click-middle": "playerctl previous", - "on-click": "playerctl play-pause", - "on-click-right": "playerctl next", - "format-icons": { - "Paused": "", - "Playing": "" - } + "format": "{icon} {}", + "return-type": "json", + "max-length": 55, + "exec": "playerctl -a metadata --format '{\"text\": \" {{markup_escape(title)}}\", \"tooltip\": \"{{playerName}} : {{markup_escape(title)}}\", \"alt\": \"{{status}}\", \"class\": \"{{status}}\"}' -F", + "on-click-middle": "playerctl previous", + "on-click": "playerctl play-pause", + "on-click-right": "playerctl next", + "format-icons": { + "Paused": "", + "Playing": "", + }, }, "network": { - "interval": 5, - //"interface": "wlan*", // (Optional) To force the use of this interface, set it for netspeed to work - "format-wifi": " {essid}", - "format-ethernet": " {ipaddr}/{cidr}", - "format-linked": " {ifname} (No IP)", - "format-disconnected": "睊 Disconnected", - "format-disabled": "睊 Disabled", - "format-alt": " {bandwidthUpBytes} |  {bandwidthDownBytes}", - "tooltip-format": " {ifname} via {gwaddr}", - "on-click-middle": "nm-connection-editor", - "on-click-right": "kitty nmtui" + "interval": 5, + //"interface": "wlan*", // (Optional) To force the use of this interface, set it for netspeed to work + "format-wifi": " {essid}", + "format-ethernet": " {ipaddr}/{cidr}", + "format-linked": " {ifname} (No IP)", + "format-disconnected": "睊 Disconnected", + "format-disabled": "睊 Disabled", + "format-alt": " {bandwidthUpBytes} |  {bandwidthDownBytes}", + "tooltip-format": " {ifname} via {gwaddr}", + "on-click-middle": "nm-connection-editor", + "on-click-right": "kitty nmtui", }, "pulseaudio": { - //"format": "{volume}% {icon} {format_source}", - "format": "{icon} {volume}%", - "format-muted": " Mute", - "format-bluetooth": " {volume}% {format_source}", - "format-bluetooth-muted": " Mute", - "format-source": " {volume}%", - "format-source-muted": "", - "format-icons": { - "headphone": "", - "hands-free": "", - "headset": "", - "phone": "", - "portable": "", - "car": "", - "default": [ - "", - "", - "" - ] - }, - "scroll-step": 5.0, - // Commands to execute on events - "on-click": "amixer set Master toggle", - "on-click-right": "pavucontrol", - "smooth-scrolling-threshold": 1, + //"format": "{volume}% {icon} {format_source}", + "format": "{icon} {volume}%", + "format-muted": " Mute", + "format-bluetooth": " {volume}% {format_source}", + "format-bluetooth-muted": " Mute", + "format-source": " {volume}%", + "format-source-muted": "", + "format-icons": { + "headphone": "", + "hands-free": "", + "headset": "", + "phone": "", + "portable": "", + "car": "", + "default": ["", "", ""], + }, + "scroll-step": 5.0, + // Commands to execute on events + "on-click": "amixer set Master toggle", + "on-click-right": "pavucontrol", + "smooth-scrolling-threshold": 1, }, "temperature": { "format": "\uf2c9 {temperatureC}\u00b0C", - "tooltip": false + "tooltip": false, }, "backlight": { "format": "{icon} {percent}%", - "format-icons": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ] + "format-icons": ["", "", "", "", "", "", "", "", ""], }, "tray": { "icon-size": 15, - "spacing": 5 + "spacing": 5, }, "battery": { "bat": "BAT0", @@ -186,7 +165,7 @@ "interval": 60, "states": { "warning": 30, - "critical": 15 + "critical": 15, }, "max-length": 20, "format": "{icon} {capacity}%", @@ -196,12 +175,6 @@ "format-plugged": " {capacity}%", "format-alt": "{icon} {time}", "format-full": " {capacity}%", - "format-icons": [ - " ", - " ", - " ", - " ", - " " - ] + "format-icons": [" ", " ", " ", " ", " "], }, } diff --git a/home/linux/desktop/hyprland/conf/waybar/mocha.css b/home/linux/desktop/hyprland/conf/waybar/mocha.css index 913e59f2..4388cd34 100644 --- a/home/linux/desktop/hyprland/conf/waybar/mocha.css +++ b/home/linux/desktop/hyprland/conf/waybar/mocha.css @@ -36,5 +36,3 @@ @define-color pink #f5c2e7; @define-color flamingo #f2cdcd; @define-color rosewater #f5e0dc; - - diff --git a/home/linux/desktop/hyprland/conf/wlogout/style.css b/home/linux/desktop/hyprland/conf/wlogout/style.css index 967a4a6c..22b73a5d 100644 --- a/home/linux/desktop/hyprland/conf/wlogout/style.css +++ b/home/linux/desktop/hyprland/conf/wlogout/style.css @@ -1,52 +1,57 @@ /** ********** Fonts ********** **/ * { - font-family: "JetBrains Mono", "Iosevka Nerd Font", sans-serif; - font-size: 14px; - font-weight: bold; + font-family: "JetBrains Mono", "Iosevka Nerd Font", sans-serif; + font-size: 14px; + font-weight: bold; } /** ********** Main Window ********** **/ window { - background-color: #1E1E2E; + background-color: #1e1e2e; } /** ********** Buttons ********** **/ button { - background-color: #242434; - color: #FFFFFF; - border: 2px solid #282838; - border-radius: 20px; - background-repeat: no-repeat; - background-position: center; - background-size: 35%; + background-color: #242434; + color: #ffffff; + border: 2px solid #282838; + border-radius: 20px; + background-repeat: no-repeat; + background-position: center; + background-size: 35%; } -button:focus, button:active, button:hover { - background-color: #89B4FA; - outline-style: none; +button:focus, +button:active, +button:hover { + background-color: #89b4fa; + outline-style: none; } /** ********** Icons ********** **/ #lock { - background-image: image(url("icons/lock.png"), url("/usr/share/wlogout/icons/lock.png")); + background-image: image(url("icons/lock.png"), url("/usr/share/wlogout/icons/lock.png")); } #logout { - background-image: image(url("icons/logout.png"), url("/usr/share/wlogout/icons/logout.png")); + background-image: image(url("icons/logout.png"), url("/usr/share/wlogout/icons/logout.png")); } #suspend { - background-image: image(url("icons/suspend.png"), url("/usr/share/wlogout/icons/suspend.png")); + background-image: image(url("icons/suspend.png"), url("/usr/share/wlogout/icons/suspend.png")); } #hibernate { - background-image: image(url("icons/hibernate.png"), url("/usr/share/wlogout/icons/hibernate.png")); + background-image: image( + url("icons/hibernate.png"), + url("/usr/share/wlogout/icons/hibernate.png") + ); } #shutdown { - background-image: image(url("icons/shutdown.png"), url("/usr/share/wlogout/icons/shutdown.png")); + background-image: image(url("icons/shutdown.png"), url("/usr/share/wlogout/icons/shutdown.png")); } #reboot { - background-image: image(url("icons/reboot.png"), url("/usr/share/wlogout/icons/reboot.png")); + background-image: image(url("icons/reboot.png"), url("/usr/share/wlogout/icons/reboot.png")); } diff --git a/home/linux/desktop/i3/conf/scripts/README.md b/home/linux/desktop/i3/conf/scripts/README.md index 54f89e25..186708b0 100755 --- a/home/linux/desktop/i3/conf/scripts/README.md +++ b/home/linux/desktop/i3/conf/scripts/README.md @@ -1,3 +1,4 @@ # Scripts for I3 Blocks -Mostly copy from [i3blocks-contrib](https://github.com/vivien/i3blocks-contrib), the Official repository for community contributed blocklets. +Mostly copy from [i3blocks-contrib](https://github.com/vivien/i3blocks-contrib), the Official +repository for community contributed blocklets. diff --git a/hosts/12kingdoms-rakushun/README.md b/hosts/12kingdoms-rakushun/README.md index 0a65bbb8..2f51e826 100644 --- a/hosts/12kingdoms-rakushun/README.md +++ b/hosts/12kingdoms-rakushun/README.md @@ -18,7 +18,7 @@ zram0 254:0 0 0B 0 disk nvme0n1 259:0 0 1.8T 0 disk ├─nvme0n1p1 259:1 0 630M 0 part /boot └─nvme0n1p2 259:2 0 1.8T 0 part - └─crypted 253:0 0 1.8T 0 crypt /tmp + └─encrypted 253:0 0 1.8T 0 crypt /tmp /swap /snapshots /home/ryan/tmp @@ -123,7 +123,9 @@ dd bs=512 count=64 iflag=fullblock seek=128 if=$KEYFILE of=$DEVICE ### 2. Partition the SSD & install NixOS via disko -First, follow [UEFI - ryan4yin/nixos-rk3588](https://github.com/ryan4yin/nixos-rk3588/blob/main/UEFI.md) to install UEFI bootloader and boot into NixOS live environment via a USB stick. +First, follow +[UEFI - ryan4yin/nixos-rk3588](https://github.com/ryan4yin/nixos-rk3588/blob/main/UEFI.md) to +install UEFI bootloader and boot into NixOS live environment via a USB stick. Then, run the following commands: @@ -145,5 +147,3 @@ cd ~/nix-config # NOTE: the root password you set here will be discarded when reboot sudo nixos-install --root /mnt --flake .#rakushun --no-root-password --show-trace --verbose ``` - - diff --git a/hosts/12kingdoms-shoukei/README.md b/hosts/12kingdoms-shoukei/README.md index e0b9c67f..05981f25 100644 --- a/hosts/12kingdoms-shoukei/README.md +++ b/hosts/12kingdoms-shoukei/README.md @@ -8,12 +8,9 @@ Related: - - - TODOs: - [ ] Resume from suspend(close the lid) doesn't work - [ ] Show battery percentage in i3blocks/waybar - [ ] Touchbar unusable some times - - It works on boot, but after a while it stops working - - + - It works on boot, but after a while it stops working diff --git a/hosts/12kingdoms-suzu/README.md b/hosts/12kingdoms-suzu/README.md index b2e1d212..04e5e2ea 100644 --- a/hosts/12kingdoms-suzu/README.md +++ b/hosts/12kingdoms-suzu/README.md @@ -2,7 +2,6 @@ LUKS encrypted SSD for NixOS, on Orange Pi 5. - ## Showcases ![](../../_img/2024-03-07_orangepi5_suzu.webp) @@ -19,7 +18,7 @@ zram0 254:0 0 0B 0 disk nvme0n1 259:0 0 238.5G 0 disk ├─nvme0n1p1 259:1 0 630M 0 part /boot └─nvme0n1p2 259:2 0 237.9G 0 part - └─crypted 253:0 0 237.8G 0 crypt /tmp + └─encrypted 253:0 0 237.8G 0 crypt /tmp /snapshots /swap /home/ryan/tmp @@ -97,7 +96,7 @@ Caches (sum of all): L3: 3 MiB (1 instance) ``` -## How to install NixOS on Orange Pi 5 +## How to install NixOS on Orange Pi 5 ### 1. Prepare a USB LUKS key @@ -124,7 +123,9 @@ dd bs=512 count=64 iflag=fullblock seek=128 if=$KEYFILE of=$DEVICE ### 2. Partition the SSD & install NixOS via disko -First, follow [UEFI - ryan4yin/nixos-rk3588](https://github.com/ryan4yin/nixos-rk3588/blob/main/UEFI.md) to install UEFI bootloader and boot into NixOS live environment via a USB stick. +First, follow +[UEFI - ryan4yin/nixos-rk3588](https://github.com/ryan4yin/nixos-rk3588/blob/main/UEFI.md) to +install UEFI bootloader and boot into NixOS live environment via a USB stick. Then, run the following commands: @@ -145,5 +146,3 @@ cd ~/nix-config # NOTE: the root password you set here will be discarded when reboot sudo nixos-install --root /mnt --flake .#suzu --no-root-password --show-trace --verbose ``` - - diff --git a/hosts/README.md b/hosts/README.md index 88e6906c..b338fae5 100644 --- a/hosts/README.md +++ b/hosts/README.md @@ -5,32 +5,42 @@ 1. `harmonica`: MacBook Pro 2020 13-inch i5 16G, for personal use. 2. `idols` 1. `ai`: My main computer, with NixOS + I5-13600KF + RTX 4090 GPU, for gaming & daily use. - 2. `aquamarine`: My NixOS virtual machine as a router(IPv4 only) with a tranparent proxy to bypass the G|F|W. - 3. `ruby`: Another NixOS VM running operation and maintenance related services, such as prometheus, grafana, restic, etc. - 4. `kana`: Yet another NixOS VM running some common applications, such as hompage, file browser, torrent downloader, etc. + 2. `aquamarine`: My NixOS virtual machine as a router(IPv4 only) with a transparent proxy to + bypass the G|F|W. + 3. `ruby`: Another NixOS VM running operation and maintenance related services, such as + prometheus, grafana, restic, etc. + 4. `kana`: Yet another NixOS VM running some common applications, such as hompage, file browser, + torrent downloader, etc. 3. Homelab: - 1. `tailscale-gw`: A tailscale subnet router(gateway) for accessing my homelab remotely. NixOS VM running on Proxmox. + 1. `tailscale-gw`: A tailscale subnet router(gateway) for accessing my homelab remotely. NixOS VM + running on Proxmox. 4. `rolling_girls`: My RISCV64 hosts. 1. `nozomi`: Lichee Pi 4A, TH1520(4xC910@2.0G), 16GB RAM + 32G eMMC + 128G SD Card. 2. `yukina`: Milk-V Mars, JH7110(4xU74@1.5 GHz), 4G RAM + No eMMC + 64G SD Card. 5. `12kingdoms`: 1. `shoukei`: NixOS on Macbook Pro 2020 Intel i5, 13.3-inch, 16G RAM + 512G SSD. - 1. `suzu`: Orange Pi 5, RK3588s(4xA76 + 4xA55), GPU(4Cores, Mail-G610), NPU(6Tops@int8), 8G RAM + 256G SSD. - 1. `rakushun`: Orange Pi 5 Plus, RK3588(4xA76 + 4xA55), GPU(4Cores, Mail-G610), NPU(6Tops@int8), 16G RAM + 2T SSD. + 1. `suzu`: Orange Pi 5, RK3588s(4xA76 + 4xA55), GPU(4Cores, Mail-G610), NPU(6Tops@int8), 8G RAM + + 256G SSD. + 1. `rakushun`: Orange Pi 5 Plus, RK3588(4xA76 + 4xA55), GPU(4Cores, Mail-G610), NPU(6Tops@int8), + 16G RAM + 2T SSD. 6. `k8s`: My Kubernetes Clusters ## How to add a new host 1. Under `hosts/` 1. Create a new folder under `hosts/` with the name of the new host. - 2. Create & add the new host's `hardware-configuration.nix` to the new folder, and add the new host's `configuration.nix` to `hosts//default.nix`. + 2. Create & add the new host's `hardware-configuration.nix` to the new folder, and add the new + host's `configuration.nix` to `hosts//default.nix`. 3. If the new host need to use home-manager, add its custom config into `hosts//home.nix`. 1. Under `outputs/` 1. Add a new nix file named `outputs//src/.nix`. 2. Copy the content from one of the existing similar host, and modify it to fit the new host. 1. Usually, you only need to modify the `name` and `tags` fields. - 3. [Optional] Add a new unit test file under `outputs//tests/.nix` to test the new host's nix file. - 4. [Optional] Add a new integration test file under `outputs//integration-tests/.nix` to test whether the new host's nix config can be built and deployed correctly. + 3. [Optional] Add a new unit test file under `outputs//tests/.nix` to + test the new host's nix file. + 4. [Optional] Add a new integration test file under + `outputs//integration-tests/.nix` to test whether the new host's + nix config can be built and deployed correctly. ## idols - Oshi no Ko @@ -44,9 +54,13 @@ My All RISCV64 hosts. ## Distributed Building -I usually run the build command on `Ai` and nix will distribute the build to other NixOS machines, which is convenient and fast. +I usually run the build command on `Ai` and nix will distribute the build to other NixOS machines, +which is convenient and fast. -When building some packages for riscv64 or aarch64, I often have no cache available because of various changes under the hood, so I need to build much more packages than usual, which is one of the reasons why the cluster was originally built, and another reason is distributed building is cool! +When building some packages for riscv64 or aarch64, I often have no cache available because of +various changes under the hood, so I need to build much more packages than usual, which is one of +the reasons why the cluster was originally built, and another reason is distributed building is +cool! ![](/_img/nix-distributed-building.webp) @@ -56,8 +70,7 @@ When building some packages for riscv64 or aarch64, I often have no cache availa [Oshi no Ko 【推しの子】 - Wikipedia](https://en.wikipedia.org/wiki/Oshi_no_Ko): -![](/_img/idols-famaily.webp) -![](/_img/idols-ai.webp) +![](/_img/idols-famaily.webp) ![](/_img/idols-ai.webp) [The Rolling Girls【ローリング☆ガールズ】 - Wikipedia](https://en.wikipedia.org/wiki/The_Rolling_Girls): @@ -65,7 +78,6 @@ When building some packages for riscv64 or aarch64, I often have no cache availa [List of Twelve Kingdoms characters](https://en.wikipedia.org/wiki/List_of_Twelve_Kingdoms_characters) -![](/_img/12kingdoms-1.webp) -![](/_img/12kingdoms-Youko-Rakushun.webp) +![](/_img/12kingdoms-1.webp) ![](/_img/12kingdoms-Youko-Rakushun.webp) [List of Frieren characters](https://en.wikipedia.org/wiki/List_of_Frieren_characters) diff --git a/hosts/idols-ai/README.md b/hosts/idols-ai/README.md index b8fd891c..be239f77 100644 --- a/hosts/idols-ai/README.md +++ b/hosts/idols-ai/README.md @@ -33,14 +33,14 @@ tmpfs tmpfs 100K 0 100K 0% /var/lib/lxd/shmounts tmpfs tmpfs 100K 0 100K 0% /var/lib/lxd/devlxd /dev/mapper/crypted-nixos btrfs 1.9T 630G 1.3T 34% /tmp -~ +~ › lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS zram0 253:0 0 15.6G 0 disk [SWAP] -nvme0n1 259:0 0 1.8T 0 disk +nvme0n1 259:0 0 1.8T 0 disk ├─nvme0n1p1 259:2 0 598M 0 part /boot -└─nvme0n1p2 259:3 0 1.8T 0 part - └─crypted-nixos 254:0 0 1.8T 0 crypt /tmp +└─nvme0n1p2 259:3 0 1.8T 0 part + └─encrypted-nixos 254:0 0 1.8T 0 crypt /tmp /swap/swapfile /swap /snapshots diff --git a/hosts/idols-aquamarine/README.md b/hosts/idols-aquamarine/README.md index 3a79f330..783fe3fd 100644 --- a/hosts/idols-aquamarine/README.md +++ b/hosts/idols-aquamarine/README.md @@ -1,14 +1,15 @@ # Idols - Aquamarine -A router(IPv4 only) with a tranparent proxy to bypass the G|F|W. +A router(IPv4 only) with a transparent proxy to bypass the G|F|W. -NOTE: dae(running on aquamarine) do not provides a http/socks5 proxy server, so a v2ray server is running on [idols_kana](../idols_kana/proxy.nix) to provides a http/socks5 proxy service. +NOTE: dae(running on aquamarine) do not provides a http/socks5 proxy server, so a v2ray server is +running on [idols_kana](../idols_kana/proxy.nix) to provides a http/socks5 proxy service. ## Troubleshooting ### Can not access the global internet -1. Check wether the subscription url is accessible. +1. Check whether the subscription url is accessible. - If not, then you need to get a new subscription url and update the `dae`'s configuration. 1. Check the `dae` service's log by `journalctl -u dae -n 1000`. @@ -24,19 +25,24 @@ NOTE: dae(running on aquamarine) do not provides a http/socks5 proxy server, so 1. `ss -tunlp`, check if `dnsmasq` is running and listening on udp port 67. 1. `journalctl -u dnsmasq -n 1000` to check the log of `dnsmasq`. 1. Request a new IP address by disconnect and reconnect one of your devices' wifi. -1. `nix shell nixpkgs#dhcpdump` and then `sudo dhcpdump -i br-lan`, check if the DHCP request is received by `dnsmasq`. +1. `nix shell nixpkgs#dhcpdump` and then `sudo dhcpdump -i br-lan`, check if the DHCP request is + received by `dnsmasq`. 1. The server listens on UDP port number 67, and the client listens on UDP port number 68. 1. DHCP operations fall into four phases: - 1. Server **discovery**: The DHCP client broadcasts a DHCPDISCOVER message on the network subnet using the destination address 255.255.255.255 (limited broadcast) or the specific subnet broadcast address (directed broadcast). - 1. IP lease **offer**: When a DHCP server receives a DHCPDISCOVER message from a client, which is an IP address lease request, the DHCP server reserves an IP address for the client and makes a lease offer by sending a DHCPOFFER message to the client. - 1. IP lease **request**: In response to the DHCP offer, the client replies with a DHCPREQUEST message, broadcast to the server,[a] requesting the offered address. - 1. IP lease **acknowledgement**: When the DHCP server receives the DHCPREQUEST message from the client, it sends a DHCPACK packet to the client, which includes the lease duration and any other configuration information that the client might have requested. + 1. Server **discovery**: The DHCP client broadcasts a DHCPDISCOVER message on the network + subnet using the destination address 255.255.255.255 (limited broadcast) or the specific + subnet broadcast address (directed broadcast). + 1. IP lease **offer**: When a DHCP server receives a DHCPDISCOVER message from a client, which + is an IP address lease request, the DHCP server reserves an IP address for the client and + makes a lease offer by sending a DHCPOFFER message to the client. + 1. IP lease **request**: In response to the DHCP offer, the client replies with a DHCPREQUEST + message, broadcast to the server,[a] requesting the offered address. + 1. IP lease **acknowledgement**: When the DHCP server receives the DHCPREQUEST message from + the client, it sends a DHCPACK packet to the client, which includes the lease duration and + any other configuration information that the client might have requested. 1. So if you see only `DISCOVER` messages, the dhsmasq is not working properly. - ## References - - - - diff --git a/hosts/idols-kana/README.md b/hosts/idols-kana/README.md index f6a5fae9..7d382444 100644 --- a/hosts/idols-kana/README.md +++ b/hosts/idols-kana/README.md @@ -2,8 +2,9 @@ Host running some common applications, such as hompage, file browser, torrent downloader, etc. -All the services assumes a reverse proxy to be setup in the front, they are all listening on localhost, -and a caddy service is listening on the local network interface and proxy the requests to the services. +All the services assumes a reverse proxy to be setup in the front, they are all listening on +localhost, and a caddy service is listening on the local network interface and proxy the requests to +the services. ## Services @@ -13,4 +14,3 @@ and a caddy service is listening on the local network interface and proxy the re 1. uptime-kuma: uptime monitoring 1. alist/filebrower: File browser for local/SMB/Cloud 1. excalidraw/DDTV/owncast/jitsi-meet/... - diff --git a/hosts/idols-kana/homepage/README.md b/hosts/idols-kana/homepage/README.md index 3a792589..ceb9c3f4 100644 --- a/hosts/idols-kana/homepage/README.md +++ b/hosts/idols-kana/homepage/README.md @@ -1,4 +1,3 @@ # Homepage for my Homelab > WIP, just a demo for now - diff --git a/hosts/idols-kana/homepage/config/bookmarks.yaml b/hosts/idols-kana/homepage/config/bookmarks.yaml index c1f13c92..75311d16 100644 --- a/hosts/idols-kana/homepage/config/bookmarks.yaml +++ b/hosts/idols-kana/homepage/config/bookmarks.yaml @@ -6,4 +6,3 @@ - Github: - abbr: GH href: https://github.com/ryan4yin - diff --git a/hosts/idols-kana/homepage/config/kubernetes.yaml b/hosts/idols-kana/homepage/config/kubernetes.yaml index 28fcd816..1033f91d 100644 --- a/hosts/idols-kana/homepage/config/kubernetes.yaml +++ b/hosts/idols-kana/homepage/config/kubernetes.yaml @@ -4,5 +4,3 @@ # read kubbecofig from $KUBECONFIG or $HOME/.kube/config # mode: default mode: disabled - - diff --git a/hosts/idols-kana/homepage/config/services.yaml b/hosts/idols-kana/homepage/config/services.yaml index d1d8aebc..06f76f1c 100644 --- a/hosts/idols-kana/homepage/config/services.yaml +++ b/hosts/idols-kana/homepage/config/services.yaml @@ -6,19 +6,19 @@ - PVE-UM560: icon: si-proxmox href: https://192.168.5.173:8006/ - description: 'CPU: R5-5625U / MEM: 32G / DISK: 512G+4T*2' + description: "CPU: R5-5625U / MEM: 32G / DISK: 512G+4T*2" siteMonitor: https://192.168.5.173:8006/ - PVE-S500Plus: icon: si-proxmox href: https://192.168.5.174:8006/ - description: 'CPU: R7-5825U / MEM: 64G / DISK: 1T' + description: "CPU: R7-5825U / MEM: 64G / DISK: 1T" siteMonitor: https://192.168.5.174:8006/ - PVE-GTR5: icon: si-proxmox href: https://192.168.5.172:8006/ - description: 'CPU: R9-5900HX / MEM: 64G / DISK: 1T' + description: "CPU: R9-5900HX / MEM: 64G / DISK: 1T" siteMonitor: https://192.168.5.172:8006/ - Homelab Monitoring: @@ -26,7 +26,7 @@ icon: si-grafana href: http://grafana.writefor.fun description: Data visualised on dashboards - siteMonitor: http://grafana.writefor.fun + siteMonitor: http://grafana.writefor.fun - Prometheus Dashboard: icon: si-prometheus href: http://prometheus.writefor.fun @@ -44,7 +44,6 @@ href: "http://sftpgo.writefor.fun/web/admin/folders" description: WebDAV & SFTP server siteMonitor: http://sftpgo.writefor.fun/ - # - Kubernetes Monitoring: # # TODO: Update this # - Emby: diff --git a/hosts/idols-kana/homepage/config/settings.yaml b/hosts/idols-kana/homepage/config/settings.yaml index d0804fc0..54e8940a 100644 --- a/hosts/idols-kana/homepage/config/settings.yaml +++ b/hosts/idols-kana/homepage/config/settings.yaml @@ -16,9 +16,8 @@ language: zh # You can then pass provider instead of apiKey in your widget configuration. providers: # read api keys from environment variables - openweathermap: {{HOMEPAGE_VAR_WEATHERAPI_APIKEY}} - weatherapi: {{HOMEPAGE_VAR_WEATHERAPI_APIKEY}} - + openweathermap: { { HOMEPAGE_VAR_WEATHERAPI_APIKEY } } + weatherapi: { { HOMEPAGE_VAR_WEATHERAPI_APIKEY } } background: image: /images/rolling-girls.png @@ -29,7 +28,7 @@ background: theme: dark # or light -# Supported colors are: +# Supported colors are: # slate, gray, zinc, neutral, stone, amber, # yellow, lime, green, emerald, teal, cyan, # sky, blue, indigo, violet, purple, fuchsia, pink, rose, red, white @@ -46,7 +45,7 @@ layout: tab: First Group A: - initiallyCollapsed: true # collasped by default + initiallyCollapsed: true # collapsed by default tab: First style: row columns: 4 diff --git a/hosts/idols-ruby/README.md b/hosts/idols-ruby/README.md index 96674a3a..92c90d10 100644 --- a/hosts/idols-ruby/README.md +++ b/hosts/idols-ruby/README.md @@ -11,4 +11,3 @@ Host running operation and maintenance related services: 1. prometheus + alertmanager + grafana + loki: Monitor the metrics/logs of my homelab. 1. restic: Backup my personal data to cloud or NAS. 1. synthing: Sync file between android/macbook/PC and NAS. - diff --git a/hosts/idols-ruby/grafana/dashboards.yml b/hosts/idols-ruby/grafana/dashboards.yml index 15b022c9..bf81ce97 100644 --- a/hosts/idols-ruby/grafana/dashboards.yml +++ b/hosts/idols-ruby/grafana/dashboards.yml @@ -2,7 +2,7 @@ apiVersion: 1 providers: # an unique provider name. Required - - name: 'Dashboards' + - name: "Dashboards" # Org id. Default to 1 orgId: 1 # provider type. Default to 'file' diff --git a/hosts/idols-ruby/grafana/dashboards/README.md b/hosts/idols-ruby/grafana/dashboards/README.md index 117a45bf..65257fdc 100644 --- a/hosts/idols-ruby/grafana/dashboards/README.md +++ b/hosts/idols-ruby/grafana/dashboards/README.md @@ -1,4 +1,4 @@ -# Grafana Dashbaords +# Grafana Dashboards ## Homelab @@ -8,4 +8,3 @@ ## Kubernetes 1. https://github.com/dotdc/grafana-dashboards-kubernetes/ - diff --git a/hosts/idols-ruby/grafana/dashboards/homelab/alertmanager-9578_rev4.json b/hosts/idols-ruby/grafana/dashboards/homelab/alertmanager-9578_rev4.json index d7640e73..3176b7ac 100644 --- a/hosts/idols-ruby/grafana/dashboards/homelab/alertmanager-9578_rev4.json +++ b/hosts/idols-ruby/grafana/dashboards/homelab/alertmanager-9578_rev4.json @@ -128,11 +128,7 @@ "cacheTimeout": null, "colorBackground": false, "colorValue": false, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "datasource": "$datasource", "decimals": 0, "format": "short", @@ -297,7 +293,7 @@ "unit": "s" }, { - "alias": "Last reload sucessfull", + "alias": "Last reload successful", "colorMode": "cell", "colors": [ "rgba(245, 54, 54, 0.9)", @@ -308,10 +304,7 @@ "decimals": 2, "mappingType": 1, "pattern": "Value #C", - "thresholds": [ - "0", - "1" - ], + "thresholds": ["0", "1"], "type": "number", "unit": "short" }, @@ -363,11 +356,7 @@ "cacheTimeout": null, "colorBackground": false, "colorValue": false, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "datasource": "$datasource", "decimals": 0, "description": "Number of peers in the Alertmanager cluster.", @@ -445,11 +434,7 @@ "cacheTimeout": null, "colorBackground": false, "colorValue": false, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "datasource": "$datasource", "description": "Current number of active alerts.", "format": "none", @@ -526,11 +511,7 @@ "cacheTimeout": null, "colorBackground": false, "colorValue": false, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "datasource": "$datasource", "description": "Current number of suppressed alerts.", "format": "none", @@ -607,11 +588,7 @@ "cacheTimeout": null, "colorBackground": false, "colorValue": false, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "datasource": "$datasource", "description": "Current number of active silences.", "format": "none", @@ -2469,7 +2446,7 @@ "expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])", "format": "time_series", "intervalFactor": 1, - "legendFormat": "Sucessful reconnections", + "legendFormat": "Successful reconnections", "refId": "A" }, { @@ -2578,7 +2555,7 @@ "expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])", "format": "time_series", "intervalFactor": 1, - "legendFormat": "Sucessful reconnections", + "legendFormat": "Successful reconnections", "refId": "A" }, { @@ -2687,7 +2664,7 @@ "expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])", "format": "time_series", "intervalFactor": 1, - "legendFormat": "Sucessful reconnections", + "legendFormat": "Successful reconnections", "refId": "A" }, { @@ -2796,7 +2773,7 @@ "expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])", "format": "time_series", "intervalFactor": 1, - "legendFormat": "Sucessful reconnections", + "legendFormat": "Successful reconnections", "refId": "A" }, { @@ -10161,15 +10138,11 @@ "format": "time_series", "groupBy": [ { - "params": [ - "$__interval" - ], + "params": ["$__interval"], "type": "time" }, { - "params": [ - "null" - ], + "params": ["null"], "type": "fill" } ], @@ -10183,9 +10156,7 @@ "select": [ [ { - "params": [ - "value" - ], + "params": ["value"], "type": "field" }, { @@ -10305,15 +10276,11 @@ "format": "time_series", "groupBy": [ { - "params": [ - "$__interval" - ], + "params": ["$__interval"], "type": "time" }, { - "params": [ - "null" - ], + "params": ["null"], "type": "fill" } ], @@ -10327,9 +10294,7 @@ "select": [ [ { - "params": [ - "value" - ], + "params": ["value"], "type": "field" }, { @@ -10449,15 +10414,11 @@ "format": "time_series", "groupBy": [ { - "params": [ - "$__interval" - ], + "params": ["$__interval"], "type": "time" }, { - "params": [ - "null" - ], + "params": ["null"], "type": "fill" } ], @@ -10471,9 +10432,7 @@ "select": [ [ { - "params": [ - "value" - ], + "params": ["value"], "type": "field" }, { @@ -10593,15 +10552,11 @@ "format": "time_series", "groupBy": [ { - "params": [ - "$__interval" - ], + "params": ["$__interval"], "type": "time" }, { - "params": [ - "null" - ], + "params": ["null"], "type": "fill" } ], @@ -10615,9 +10570,7 @@ "select": [ [ { - "params": [ - "value" - ], + "params": ["value"], "type": "field" }, { @@ -11131,11 +11084,7 @@ "refresh": "5m", "schemaVersion": 18, "style": "dark", - "tags": [ - "alertmanager", - "prometheus", - "alerting" - ], + "tags": ["alertmanager", "prometheus", "alerting"], "templating": { "list": [ { @@ -11185,32 +11134,11 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", "title": "Alertmanager", "uid": "eea-9_sik", "version": 27 -} \ No newline at end of file +} diff --git a/hosts/idols-ruby/grafana/dashboards/homelab/node-exporter-full-1860_rev33.json b/hosts/idols-ruby/grafana/dashboards/homelab/node-exporter-full-1860_rev33.json index c28ea749..bf25174c 100644 --- a/hosts/idols-ruby/grafana/dashboards/homelab/node-exporter-full-1860_rev33.json +++ b/hosts/idols-ruby/grafana/dashboards/homelab/node-exporter-full-1860_rev33.json @@ -173,9 +173,7 @@ "options": { "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -261,9 +259,7 @@ "options": { "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -349,9 +345,7 @@ "options": { "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -427,9 +421,7 @@ "options": { "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -531,9 +523,7 @@ "options": { "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -617,9 +607,7 @@ "options": { "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -701,9 +689,7 @@ "justifyMode": "auto", "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -782,9 +768,7 @@ "justifyMode": "auto", "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -869,9 +853,7 @@ "justifyMode": "auto", "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -954,9 +936,7 @@ "justifyMode": "auto", "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1037,9 +1017,7 @@ "justifyMode": "auto", "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -2662,12 +2640,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -3169,12 +3142,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -3448,12 +3416,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -3563,12 +3526,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -3993,12 +3951,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -4220,12 +4173,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -4365,12 +4313,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -4498,12 +4441,7 @@ "id": 319, "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -4894,12 +4832,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -5284,12 +5217,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -5655,12 +5583,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -6084,12 +6007,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -6490,12 +6408,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -6917,12 +6830,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -7302,12 +7210,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -7687,12 +7590,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -8073,12 +7971,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -8443,12 +8336,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -8830,11 +8718,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "lastNotNull", - "max", - "min" - ], + "calcs": ["lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -9226,11 +9110,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "lastNotNull", - "max", - "min" - ], + "calcs": ["lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -9610,11 +9490,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "max", - "min" - ], + "calcs": ["mean", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -9993,12 +9869,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -10394,12 +10265,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -10535,12 +10401,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -10661,12 +10522,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -11050,12 +10906,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -11463,12 +11314,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -11609,12 +11455,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -11741,12 +11582,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -11860,12 +11696,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -11976,12 +11807,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -12119,12 +11945,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -12233,12 +12054,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -12336,12 +12152,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -12452,12 +12263,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -12614,12 +12420,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -12742,12 +12543,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -12878,12 +12674,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -13021,12 +12812,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -13136,12 +12922,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -13261,10 +13042,7 @@ { "id": "custom.lineStyle", "value": { - "dash": [ - 10, - 10 - ], + "dash": [10, 10], "fill": "dash" } }, @@ -13302,10 +13080,7 @@ { "id": "custom.lineStyle", "value": { - "dash": [ - 10, - 10 - ], + "dash": [10, 10], "fill": "dash" } }, @@ -13338,12 +13113,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -13540,12 +13310,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -13743,12 +13508,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -13845,12 +13605,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -13948,12 +13703,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -14049,12 +13799,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -14172,12 +13917,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -14352,12 +14092,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -14529,12 +14264,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -14645,12 +14375,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -14776,12 +14501,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -14954,12 +14674,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -15449,12 +15164,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -15874,12 +15584,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -16301,12 +16006,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -16719,12 +16419,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -17134,12 +16829,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -17548,12 +17238,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -17964,12 +17649,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -18367,12 +18047,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -18509,12 +18184,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -18640,12 +18310,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -18744,12 +18409,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -18859,12 +18519,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -18980,12 +18635,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -19194,12 +18844,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -19323,12 +18968,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -19450,12 +19090,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -19577,12 +19212,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -19704,12 +19334,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -19819,12 +19444,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -19946,12 +19566,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -20049,12 +19664,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -20164,12 +19774,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -20287,12 +19892,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -20401,12 +20001,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -20504,12 +20099,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -20607,12 +20197,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -20710,12 +20295,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -20824,12 +20404,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -20940,12 +20515,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -21043,12 +20613,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -21184,12 +20749,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -21341,12 +20901,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -21471,12 +21026,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -21588,12 +21138,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -21716,12 +21261,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -21859,12 +21399,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -21975,12 +21510,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true, @@ -22091,12 +21621,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -22219,12 +21744,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -22346,12 +21866,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -22461,12 +21976,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -22637,12 +22147,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -22755,12 +22260,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -22936,12 +22436,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -23067,12 +22562,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -23199,12 +22689,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -23312,12 +22797,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -23492,12 +22972,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -23619,12 +23094,7 @@ "links": [], "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "table", "placement": "bottom", "showLegend": true @@ -23686,9 +23156,7 @@ "revision": 1, "schemaVersion": 38, "style": "dark", - "tags": [ - "linux" - ], + "tags": ["linux"], "templating": { "list": [ { @@ -23789,33 +23257,12 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "browser", "title": "Node Exporter Full", "uid": "rYdddlPWk", "version": 87, "weekStart": "" -} \ No newline at end of file +} diff --git a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-addons-prometheus.json b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-addons-prometheus.json index 02b0d4eb..deabdbcf 100644 --- a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-addons-prometheus.json +++ b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-addons-prometheus.json @@ -131,9 +131,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -198,9 +196,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -320,9 +316,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -441,11 +435,7 @@ "id": 93, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -540,11 +530,7 @@ "id": 96, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -643,11 +629,7 @@ "id": 74, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -794,11 +776,7 @@ "id": 84, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -897,11 +875,7 @@ "id": 75, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -1000,11 +974,7 @@ "id": 85, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -1129,11 +1099,7 @@ "id": 59, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -1244,11 +1210,7 @@ "id": 60, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -1347,11 +1309,7 @@ "id": 101, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -1450,11 +1408,7 @@ "id": 102, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -1589,11 +1543,7 @@ "id": 90, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -1692,11 +1642,7 @@ "id": 95, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -1807,11 +1753,7 @@ "id": 73, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -1910,11 +1852,7 @@ "id": 86, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "list", "placement": "right", "showLegend": false @@ -2057,11 +1995,7 @@ "id": 29, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": false @@ -2161,11 +2095,7 @@ "id": 51, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": false @@ -2290,11 +2220,7 @@ "id": 62, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true @@ -2393,11 +2319,7 @@ "id": 87, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true @@ -3007,10 +2929,7 @@ "revision": 1, "schemaVersion": 38, "style": "dark", - "tags": [ - "Kubernetes", - "Prometheus" - ], + "tags": ["Kubernetes", "Prometheus"], "templating": { "list": [ { @@ -3147,4 +3066,4 @@ "uid": "k8s_addons_prometheus", "version": 3, "weekStart": "" -} \ No newline at end of file +} diff --git a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-addons-trivy-operator.json b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-addons-trivy-operator.json index 7cd8d08f..e13de913 100644 --- a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-addons-trivy-operator.json +++ b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-addons-trivy-operator.json @@ -1,47 +1,47 @@ { - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__elements": [], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "8.5.0" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "5.0.0" - }, - { - "type": "panel", - "id": "timeseries", - "name": "Time series", - "version": "" - }, - { - "type": "panel", - "id": "stat", - "name": "Stat", - "version": "" - }, - { - "type": "panel", - "id": "table", - "name": "Table", - "version": "" - } - ], + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.5.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], "annotations": { "list": [ { @@ -129,9 +129,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -197,9 +195,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -265,9 +261,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -333,9 +327,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -401,9 +393,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -469,9 +459,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -863,12 +851,8 @@ "options": { "footer": { "enablePagination": true, - "fields": [ - "Value" - ], - "reducer": [ - "sum" - ], + "fields": ["Value"], + "reducer": ["sum"], "show": false }, "showHeader": true, @@ -1093,9 +1077,7 @@ "footer": { "enablePagination": true, "fields": "", - "reducer": [ - "sum" - ], + "reducer": ["sum"], "show": false }, "showHeader": true, @@ -1182,9 +1164,7 @@ "operation": "groupby" }, "Value": { - "aggregations": [ - "lastNotNull" - ] + "aggregations": ["lastNotNull"] }, "Vulnerability": { "aggregations": [], @@ -1274,9 +1254,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -1342,9 +1320,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -1410,9 +1386,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -1478,9 +1452,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -1546,9 +1518,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -1882,9 +1852,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -1950,9 +1918,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -2018,9 +1984,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -2086,9 +2050,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -2154,9 +2116,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -2550,12 +2510,7 @@ "refresh": "30s", "schemaVersion": 37, "style": "dark", - "tags": [ - "Prometheus", - "Addons", - "Trivy", - "Trivy-operator" - ], + "tags": ["Prometheus", "Addons", "Trivy", "Trivy-operator"], "templating": { "list": [ { @@ -2607,12 +2562,8 @@ { "current": { "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] + "text": ["All"], + "value": ["$__all"] }, "datasource": { "type": "prometheus", diff --git a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-system-api-server.json b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-system-api-server.json index 2fceda85..44179b78 100644 --- a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-system-api-server.json +++ b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-system-api-server.json @@ -114,9 +114,7 @@ "justifyMode": "auto", "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -195,9 +193,7 @@ "footer": { "countRows": false, "fields": "", - "reducer": [ - "sum" - ], + "reducer": ["sum"], "show": false }, "showHeader": true, @@ -227,14 +223,7 @@ { "id": "labelsToFields", "options": { - "keepLabels": [ - "group", - "job", - "removed_release", - "resource", - "version", - "name" - ], + "keepLabels": ["group", "job", "removed_release", "resource", "version", "name"], "mode": "columns" } }, @@ -268,9 +257,7 @@ "options": { "fields": { "group": { - "aggregations": [ - "lastNotNull" - ], + "aggregations": ["lastNotNull"], "operation": "groupby" }, "job": { @@ -278,9 +265,7 @@ "operation": "groupby" }, "namespace": { - "aggregations": [ - "lastNotNull" - ], + "aggregations": ["lastNotNull"], "operation": "groupby" }, "removed_release": { @@ -288,9 +273,7 @@ "operation": "groupby" }, "resource": { - "aggregations": [ - "lastNotNull" - ], + "aggregations": ["lastNotNull"], "operation": "groupby" }, "version": { @@ -1248,10 +1231,7 @@ "refresh": "30s", "schemaVersion": 38, "style": "dark", - "tags": [ - "Kubernetes", - "Prometheus" - ], + "tags": ["Kubernetes", "Prometheus"], "templating": { "list": [ { diff --git a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-system-coredns.json b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-system-coredns.json index b0b1bb40..88d066cb 100644 --- a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-system-coredns.json +++ b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-system-coredns.json @@ -114,9 +114,7 @@ "justifyMode": "auto", "orientation": "vertical", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1431,10 +1429,7 @@ ], "refresh": "30s", "schemaVersion": 38, - "tags": [ - "Kubernetes", - "Prometheus" - ], + "tags": ["Kubernetes", "Prometheus"], "templating": { "list": [ { @@ -1595,12 +1590,8 @@ { "current": { "selected": true, - "text": [ - "coredns" - ], - "value": [ - "coredns" - ] + "text": ["coredns"], + "value": ["coredns"] }, "definition": "label_values(coredns_build_info{cluster=\"$cluster\"},job)", "hide": 0, diff --git a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-global.json b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-global.json index f94e5ed6..bb4500d6 100644 --- a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-global.json +++ b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-global.json @@ -134,9 +134,7 @@ "namePlacement": "auto", "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -234,9 +232,7 @@ "namePlacement": "auto", "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -323,9 +319,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -421,11 +415,7 @@ "id": 52, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -631,9 +621,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -694,9 +682,7 @@ "justifyMode": "center", "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -796,9 +782,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -897,9 +881,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -1121,12 +1103,7 @@ "id": 55, "options": { "legend": { - "calcs": [ - "mean", - "lastNotNull", - "max", - "min" - ], + "calcs": ["mean", "lastNotNull", "max", "min"], "displayMode": "hidden", "placement": "right", "showLegend": false @@ -1229,11 +1206,7 @@ "id": 46, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1332,11 +1305,7 @@ "id": 50, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1432,11 +1401,7 @@ "id": 54, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1531,11 +1496,7 @@ "id": 73, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1637,11 +1598,7 @@ "id": 82, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1743,11 +1700,7 @@ "id": 83, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1857,11 +1810,7 @@ "id": 84, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1970,11 +1919,7 @@ "id": 85, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -2072,11 +2017,7 @@ "id": 87, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -2174,11 +2115,7 @@ "id": 88, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -2880,10 +2817,7 @@ ], "refresh": "30s", "schemaVersion": 39, - "tags": [ - "Kubernetes", - "Prometheus" - ], + "tags": ["Kubernetes", "Prometheus"], "templating": { "list": [ { diff --git a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-namespaces.json b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-namespaces.json index 62d2ce45..9f988e3c 100644 --- a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-namespaces.json +++ b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-namespaces.json @@ -133,9 +133,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -209,9 +207,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -307,11 +303,7 @@ "id": 32, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -475,9 +467,7 @@ "justifyMode": "center", "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -577,9 +567,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -931,11 +919,7 @@ "id": 68, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1047,11 +1031,7 @@ "id": 70, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1162,11 +1142,7 @@ "id": 72, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1266,11 +1242,7 @@ "id": 74, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -1370,11 +1342,7 @@ "id": 75, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -2154,10 +2122,7 @@ ], "refresh": "30s", "schemaVersion": 39, - "tags": [ - "Kubernetes", - "Prometheus" - ], + "tags": ["Kubernetes", "Prometheus"], "templating": { "list": [ { diff --git a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-nodes.json b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-nodes.json index 2a4221a6..8ba962dd 100644 --- a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-nodes.json +++ b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-nodes.json @@ -139,9 +139,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -213,9 +211,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -277,9 +273,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -420,9 +414,7 @@ "footer": { "countRows": false, "fields": "", - "reducer": [ - "sum" - ], + "reducer": ["sum"], "show": false }, "showHeader": true, @@ -506,9 +498,7 @@ "operation": "groupby" }, "namespace": { - "aggregations": [ - "last" - ], + "aggregations": ["last"], "operation": "groupby" }, "pod": { @@ -566,9 +556,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -631,9 +619,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -695,9 +681,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -760,9 +744,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -833,9 +815,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1416,11 +1396,7 @@ "id": 66, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -2795,9 +2771,7 @@ "footer": { "countRows": false, "fields": "", - "reducer": [ - "sum" - ], + "reducer": ["sum"], "show": false }, "showHeader": true, @@ -2839,21 +2813,15 @@ "options": { "fields": { "Value": { - "aggregations": [ - "lastNotNull" - ], + "aggregations": ["lastNotNull"], "operation": "aggregate" }, "Value #A": { - "aggregations": [ - "lastNotNull" - ], + "aggregations": ["lastNotNull"], "operation": "aggregate" }, "Value #B": { - "aggregations": [ - "lastNotNull" - ], + "aggregations": ["lastNotNull"], "operation": "aggregate" }, "persistentvolumeclaim": { @@ -3790,10 +3758,7 @@ ], "refresh": "30s", "schemaVersion": 39, - "tags": [ - "Kubernetes", - "Prometheus" - ], + "tags": ["Kubernetes", "Prometheus"], "templating": { "list": [ { diff --git a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-pods.json b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-pods.json index da694731..96419158 100644 --- a/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-pods.json +++ b/hosts/idols-ruby/grafana/dashboards/kubernetes/k8s-views-pods.json @@ -137,9 +137,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "mean" - ], + "calcs": ["mean"], "fields": "", "values": false }, @@ -205,9 +203,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "mean" - ], + "calcs": ["mean"], "fields": "", "values": false }, @@ -267,9 +263,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "mean" - ], + "calcs": ["mean"], "fields": "", "values": false }, @@ -329,9 +323,7 @@ "justifyMode": "auto", "orientation": "auto", "reduceOptions": { - "calcs": [ - "mean" - ], + "calcs": ["mean"], "fields": "", "values": false }, @@ -660,9 +652,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -732,9 +722,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -808,9 +796,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -880,9 +866,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "last" - ], + "calcs": ["last"], "fields": "", "values": false }, @@ -1000,9 +984,7 @@ "footer": { "countRows": false, "fields": "", - "reducer": [ - "sum" - ], + "reducer": ["sum"], "show": false }, "showHeader": true, @@ -1532,11 +1514,7 @@ "id": 29, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true @@ -1638,11 +1616,7 @@ "id": 51, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true @@ -1744,11 +1718,7 @@ "id": 59, "options": { "legend": { - "calcs": [ - "min", - "max", - "mean" - ], + "calcs": ["min", "max", "mean"], "displayMode": "table", "placement": "right", "showLegend": true, @@ -2475,10 +2445,7 @@ ], "refresh": "30s", "schemaVersion": 38, - "tags": [ - "Kubernetes", - "Prometheus" - ], + "tags": ["Kubernetes", "Prometheus"], "templating": { "list": [ { diff --git a/hosts/idols-ruby/grafana/datasources.yml b/hosts/idols-ruby/grafana/datasources.yml index ed45f397..de03d623 100644 --- a/hosts/idols-ruby/grafana/datasources.yml +++ b/hosts/idols-ruby/grafana/datasources.yml @@ -12,10 +12,10 @@ datasources: manageAlerts: true prometheusType: Prometheus prometheusVersion: 2.49.0 - cacheLevel: 'High' + cacheLevel: "High" disableRecordingRules: false - # As of Grafana 10, the Prometheus data source can be configured to query live dashboards + # As of Grafana 10, the Prometheus data source can be configured to query live dashboards # incrementally, instead of re-querying the entire duration on each dashboard refresh. - # Increasing the duration of the incrementalQueryOverlapWindow will increase the size of every incremental query, + # Increasing the duration of the incrementalQueryOverlapWindow will increase the size of every incremental query, # but might be helpful for instances that have inconsistent results for recent data. incrementalQueryOverlapWindow: 10m diff --git a/hosts/idols-ruby/prometheus/README.md b/hosts/idols-ruby/prometheus/README.md index 8156f6ca..2abb15a7 100644 --- a/hosts/idols-ruby/prometheus/README.md +++ b/hosts/idols-ruby/prometheus/README.md @@ -2,6 +2,5 @@ ## Alert Rules -- [awesome-prometheus-alerts](https://github.com/samber/awesome-prometheus-alerts): Collection of Prometheus alerting rules - - +- [awesome-prometheus-alerts](https://github.com/samber/awesome-prometheus-alerts): Collection of + Prometheus alerting rules diff --git a/hosts/idols-ruby/prometheus/alert_rules/coredns_embedded-exporter.yml b/hosts/idols-ruby/prometheus/alert_rules/coredns_embedded-exporter.yml index eba60e4e..7eb89261 100644 --- a/hosts/idols-ruby/prometheus/alert_rules/coredns_embedded-exporter.yml +++ b/hosts/idols-ruby/prometheus/alert_rules/coredns_embedded-exporter.yml @@ -1,14 +1,13 @@ groups: + - name: EmbeddedExporter -- name: EmbeddedExporter - - rules: - - - alert: CorednsPanicCount - expr: 'increase(coredns_panics_total[1m]) > 0' - for: 0m - labels: - severity: critical - annotations: - summary: CoreDNS Panic Count (instance {{ $labels.instance }}) - description: "Number of CoreDNS panics encountered\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + rules: + - alert: CorednsPanicCount + expr: "increase(coredns_panics_total[1m]) > 0" + for: 0m + labels: + severity: critical + annotations: + summary: CoreDNS Panic Count (instance {{ $labels.instance }}) + description: + "Number of CoreDNS panics encountered\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" diff --git a/hosts/idols-ruby/prometheus/alert_rules/etcd_embedded-exporter.yml b/hosts/idols-ruby/prometheus/alert_rules/etcd_embedded-exporter.yml index eace7ae8..dff630f9 100644 --- a/hosts/idols-ruby/prometheus/alert_rules/etcd_embedded-exporter.yml +++ b/hosts/idols-ruby/prometheus/alert_rules/etcd_embedded-exporter.yml @@ -1,122 +1,162 @@ groups: + - name: EmbeddedExporter -- name: EmbeddedExporter + rules: + - alert: EtcdInsufficientMembers + expr: "count(etcd_server_id) % 2 == 0" + for: 0m + labels: + severity: critical + annotations: + summary: Etcd insufficient Members (instance {{ $labels.instance }}) + description: + "Etcd cluster should have an odd number of members\n VALUE = {{ $value }}\n LABELS = + {{ $labels }}" - rules: + - alert: EtcdNoLeader + expr: "etcd_server_has_leader == 0" + for: 0m + labels: + severity: critical + annotations: + summary: Etcd no Leader (instance {{ $labels.instance }}) + description: + "Etcd cluster have no leader\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: EtcdInsufficientMembers - expr: 'count(etcd_server_id) % 2 == 0' - for: 0m - labels: - severity: critical - annotations: - summary: Etcd insufficient Members (instance {{ $labels.instance }}) - description: "Etcd cluster should have an odd number of members\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdHighNumberOfLeaderChanges + expr: "increase(etcd_server_leader_changes_seen_total[10m]) > 2" + for: 0m + labels: + severity: warning + annotations: + summary: Etcd high number of leader changes (instance {{ $labels.instance }}) + description: + "Etcd leader changed more than 2 times during 10 minutes\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: EtcdNoLeader - expr: 'etcd_server_has_leader == 0' - for: 0m - labels: - severity: critical - annotations: - summary: Etcd no Leader (instance {{ $labels.instance }}) - description: "Etcd cluster have no leader\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdHighNumberOfFailedGrpcRequests + expr: + 'sum(rate(grpc_server_handled_total{grpc_code!="OK"}[1m])) BY (grpc_service, grpc_method) + / sum(rate(grpc_server_handled_total[1m])) BY (grpc_service, grpc_method) > 0.01' + for: 2m + labels: + severity: warning + annotations: + summary: Etcd high number of failed GRPC requests (instance {{ $labels.instance }}) + description: + "More than 1% GRPC request failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = + {{ $labels }}" - - alert: EtcdHighNumberOfLeaderChanges - expr: 'increase(etcd_server_leader_changes_seen_total[10m]) > 2' - for: 0m - labels: - severity: warning - annotations: - summary: Etcd high number of leader changes (instance {{ $labels.instance }}) - description: "Etcd leader changed more than 2 times during 10 minutes\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdHighNumberOfFailedGrpcRequests + expr: + 'sum(rate(grpc_server_handled_total{grpc_code!="OK"}[1m])) BY (grpc_service, grpc_method) + / sum(rate(grpc_server_handled_total[1m])) BY (grpc_service, grpc_method) > 0.05' + for: 2m + labels: + severity: critical + annotations: + summary: Etcd high number of failed GRPC requests (instance {{ $labels.instance }}) + description: + "More than 5% GRPC request failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = + {{ $labels }}" - - alert: EtcdHighNumberOfFailedGrpcRequests - expr: 'sum(rate(grpc_server_handled_total{grpc_code!="OK"}[1m])) BY (grpc_service, grpc_method) / sum(rate(grpc_server_handled_total[1m])) BY (grpc_service, grpc_method) > 0.01' - for: 2m - labels: - severity: warning - annotations: - summary: Etcd high number of failed GRPC requests (instance {{ $labels.instance }}) - description: "More than 1% GRPC request failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdGrpcRequestsSlow + expr: + 'histogram_quantile(0.99, + sum(rate(grpc_server_handling_seconds_bucket{grpc_type="unary"}[1m])) by (grpc_service, + grpc_method, le)) > 0.15' + for: 2m + labels: + severity: warning + annotations: + summary: Etcd GRPC requests slow (instance {{ $labels.instance }}) + description: + "GRPC requests slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: EtcdHighNumberOfFailedGrpcRequests - expr: 'sum(rate(grpc_server_handled_total{grpc_code!="OK"}[1m])) BY (grpc_service, grpc_method) / sum(rate(grpc_server_handled_total[1m])) BY (grpc_service, grpc_method) > 0.05' - for: 2m - labels: - severity: critical - annotations: - summary: Etcd high number of failed GRPC requests (instance {{ $labels.instance }}) - description: "More than 5% GRPC request failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdHighNumberOfFailedHttpRequests + expr: + "sum(rate(etcd_http_failed_total[1m])) BY (method) / + sum(rate(etcd_http_received_total[1m])) BY (method) > 0.01" + for: 2m + labels: + severity: warning + annotations: + summary: Etcd high number of failed HTTP requests (instance {{ $labels.instance }}) + description: + "More than 1% HTTP failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ + $labels }}" - - alert: EtcdGrpcRequestsSlow - expr: 'histogram_quantile(0.99, sum(rate(grpc_server_handling_seconds_bucket{grpc_type="unary"}[1m])) by (grpc_service, grpc_method, le)) > 0.15' - for: 2m - labels: - severity: warning - annotations: - summary: Etcd GRPC requests slow (instance {{ $labels.instance }}) - description: "GRPC requests slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdHighNumberOfFailedHttpRequests + expr: + "sum(rate(etcd_http_failed_total[1m])) BY (method) / + sum(rate(etcd_http_received_total[1m])) BY (method) > 0.05" + for: 2m + labels: + severity: critical + annotations: + summary: Etcd high number of failed HTTP requests (instance {{ $labels.instance }}) + description: + "More than 5% HTTP failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ + $labels }}" - - alert: EtcdHighNumberOfFailedHttpRequests - expr: 'sum(rate(etcd_http_failed_total[1m])) BY (method) / sum(rate(etcd_http_received_total[1m])) BY (method) > 0.01' - for: 2m - labels: - severity: warning - annotations: - summary: Etcd high number of failed HTTP requests (instance {{ $labels.instance }}) - description: "More than 1% HTTP failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdHttpRequestsSlow + expr: + "histogram_quantile(0.99, rate(etcd_http_successful_duration_seconds_bucket[1m])) > 0.15" + for: 2m + labels: + severity: warning + annotations: + summary: Etcd HTTP requests slow (instance {{ $labels.instance }}) + description: + "HTTP requests slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: EtcdHighNumberOfFailedHttpRequests - expr: 'sum(rate(etcd_http_failed_total[1m])) BY (method) / sum(rate(etcd_http_received_total[1m])) BY (method) > 0.05' - for: 2m - labels: - severity: critical - annotations: - summary: Etcd high number of failed HTTP requests (instance {{ $labels.instance }}) - description: "More than 5% HTTP failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdMemberCommunicationSlow + expr: + "histogram_quantile(0.99, rate(etcd_network_peer_round_trip_time_seconds_bucket[1m])) > + 0.15" + for: 2m + labels: + severity: warning + annotations: + summary: Etcd member communication slow (instance {{ $labels.instance }}) + description: + "Etcd member communication slowing down, 99th percentile is over 0.15s\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - - alert: EtcdHttpRequestsSlow - expr: 'histogram_quantile(0.99, rate(etcd_http_successful_duration_seconds_bucket[1m])) > 0.15' - for: 2m - labels: - severity: warning - annotations: - summary: Etcd HTTP requests slow (instance {{ $labels.instance }}) - description: "HTTP requests slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdHighNumberOfFailedProposals + expr: "increase(etcd_server_proposals_failed_total[1h]) > 5" + for: 2m + labels: + severity: warning + annotations: + summary: Etcd high number of failed proposals (instance {{ $labels.instance }}) + description: + "Etcd server got more than 5 failed proposals past hour\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: EtcdMemberCommunicationSlow - expr: 'histogram_quantile(0.99, rate(etcd_network_peer_round_trip_time_seconds_bucket[1m])) > 0.15' - for: 2m - labels: - severity: warning - annotations: - summary: Etcd member communication slow (instance {{ $labels.instance }}) - description: "Etcd member communication slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdHighFsyncDurations + expr: + "histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket[1m])) > 0.5" + for: 2m + labels: + severity: warning + annotations: + summary: Etcd high fsync durations (instance {{ $labels.instance }}) + description: + "Etcd WAL fsync duration increasing, 99th percentile is over 0.5s\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: EtcdHighNumberOfFailedProposals - expr: 'increase(etcd_server_proposals_failed_total[1h]) > 5' - for: 2m - labels: - severity: warning - annotations: - summary: Etcd high number of failed proposals (instance {{ $labels.instance }}) - description: "Etcd server got more than 5 failed proposals past hour\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - - alert: EtcdHighFsyncDurations - expr: 'histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket[1m])) > 0.5' - for: 2m - labels: - severity: warning - annotations: - summary: Etcd high fsync durations (instance {{ $labels.instance }}) - description: "Etcd WAL fsync duration increasing, 99th percentile is over 0.5s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - - alert: EtcdHighCommitDurations - expr: 'histogram_quantile(0.99, rate(etcd_disk_backend_commit_duration_seconds_bucket[1m])) > 0.25' - for: 2m - labels: - severity: warning - annotations: - summary: Etcd high commit durations (instance {{ $labels.instance }}) - description: "Etcd commit duration increasing, 99th percentile is over 0.25s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: EtcdHighCommitDurations + expr: + "histogram_quantile(0.99, rate(etcd_disk_backend_commit_duration_seconds_bucket[1m])) > + 0.25" + for: 2m + labels: + severity: warning + annotations: + summary: Etcd high commit durations (instance {{ $labels.instance }}) + description: + "Etcd commit duration increasing, 99th percentile is over 0.25s\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" diff --git a/hosts/idols-ruby/prometheus/alert_rules/istio_embedded-exporter.yml b/hosts/idols-ruby/prometheus/alert_rules/istio_embedded-exporter.yml index 4ce9f546..63b81d21 100644 --- a/hosts/idols-ruby/prometheus/alert_rules/istio_embedded-exporter.yml +++ b/hosts/idols-ruby/prometheus/alert_rules/istio_embedded-exporter.yml @@ -1,95 +1,123 @@ groups: + - name: EmbeddedExporter -- name: EmbeddedExporter + rules: + - alert: IstioKubernetesGatewayAvailabilityDrop + expr: + 'min(kube_deployment_status_replicas_available{deployment="istio-ingressgateway", + namespace="istio-system"}) without (instance, pod) < 2' + for: 1m + labels: + severity: warning + annotations: + summary: Istio Kubernetes gateway availability drop (instance {{ $labels.instance }}) + description: + "Gateway pods have dropped. Inbound traffic will likely be affected.\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - rules: + - alert: IstioPilotHighTotalRequestRate + expr: "sum(rate(pilot_xds_push_errors[1m])) / sum(rate(pilot_xds_pushes[1m])) * 100 > 5" + for: 1m + labels: + severity: warning + annotations: + summary: Istio Pilot high total request rate (instance {{ $labels.instance }}) + description: + "Number of Istio Pilot push errors is too high (> 5%). Envoy sidecars might have + outdated configuration.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: IstioKubernetesGatewayAvailabilityDrop - expr: 'min(kube_deployment_status_replicas_available{deployment="istio-ingressgateway", namespace="istio-system"}) without (instance, pod) < 2' - for: 1m - labels: - severity: warning - annotations: - summary: Istio Kubernetes gateway availability drop (instance {{ $labels.instance }}) - description: "Gateway pods have dropped. Inbound traffic will likely be affected.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: IstioMixerPrometheusDispatchesLow + expr: 'sum(rate(mixer_runtime_dispatches_total{adapter=~"prometheus"}[1m])) < 180' + for: 1m + labels: + severity: warning + annotations: + summary: Istio Mixer Prometheus dispatches low (instance {{ $labels.instance }}) + description: + "Number of Mixer dispatches to Prometheus is too low. Istio metrics might not be being + exported properly.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: IstioPilotHighTotalRequestRate - expr: 'sum(rate(pilot_xds_push_errors[1m])) / sum(rate(pilot_xds_pushes[1m])) * 100 > 5' - for: 1m - labels: - severity: warning - annotations: - summary: Istio Pilot high total request rate (instance {{ $labels.instance }}) - description: "Number of Istio Pilot push errors is too high (> 5%). Envoy sidecars might have outdated configuration.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: IstioHighTotalRequestRate + expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) > 1000' + for: 2m + labels: + severity: warning + annotations: + summary: Istio high total request rate (instance {{ $labels.instance }}) + description: + "Global request rate in the service mesh is unusually high.\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: IstioMixerPrometheusDispatchesLow - expr: 'sum(rate(mixer_runtime_dispatches_total{adapter=~"prometheus"}[1m])) < 180' - for: 1m - labels: - severity: warning - annotations: - summary: Istio Mixer Prometheus dispatches low (instance {{ $labels.instance }}) - description: "Number of Mixer dispatches to Prometheus is too low. Istio metrics might not be being exported properly.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: IstioLowTotalRequestRate + expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) < 100' + for: 2m + labels: + severity: warning + annotations: + summary: Istio low total request rate (instance {{ $labels.instance }}) + description: + "Global request rate in the service mesh is unusually low.\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: IstioHighTotalRequestRate - expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) > 1000' - for: 2m - labels: - severity: warning - annotations: - summary: Istio high total request rate (instance {{ $labels.instance }}) - description: "Global request rate in the service mesh is unusually high.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: IstioHigh4xxErrorRate + expr: + 'sum(rate(istio_requests_total{reporter="destination", response_code=~"4.*"}[5m])) / + sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5' + for: 1m + labels: + severity: warning + annotations: + summary: Istio high 4xx error rate (instance {{ $labels.instance }}) + description: + "High percentage of HTTP 5xx responses in Istio (> 5%).\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: IstioLowTotalRequestRate - expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) < 100' - for: 2m - labels: - severity: warning - annotations: - summary: Istio low total request rate (instance {{ $labels.instance }}) - description: "Global request rate in the service mesh is unusually low.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: IstioHigh5xxErrorRate + expr: + 'sum(rate(istio_requests_total{reporter="destination", response_code=~"5.*"}[5m])) / + sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5' + for: 1m + labels: + severity: warning + annotations: + summary: Istio high 5xx error rate (instance {{ $labels.instance }}) + description: + "High percentage of HTTP 5xx responses in Istio (> 5%).\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: IstioHigh4xxErrorRate - expr: 'sum(rate(istio_requests_total{reporter="destination", response_code=~"4.*"}[5m])) / sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5' - for: 1m - labels: - severity: warning - annotations: - summary: Istio high 4xx error rate (instance {{ $labels.instance }}) - description: "High percentage of HTTP 5xx responses in Istio (> 5%).\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: IstioHighRequestLatency + expr: + 'rate(istio_request_duration_milliseconds_sum{reporter="destination"}[1m]) / + rate(istio_request_duration_milliseconds_count{reporter="destination"}[1m]) > 100' + for: 1m + labels: + severity: warning + annotations: + summary: Istio high request latency (instance {{ $labels.instance }}) + description: + "Istio average requests execution is longer than 100ms.\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: IstioHigh5xxErrorRate - expr: 'sum(rate(istio_requests_total{reporter="destination", response_code=~"5.*"}[5m])) / sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5' - for: 1m - labels: - severity: warning - annotations: - summary: Istio high 5xx error rate (instance {{ $labels.instance }}) - description: "High percentage of HTTP 5xx responses in Istio (> 5%).\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: IstioLatency99Percentile + expr: + "histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket[1m])) by + (destination_canonical_service, destination_workload_namespace, source_canonical_service, + source_workload_namespace, le)) > 1000" + for: 1m + labels: + severity: warning + annotations: + summary: Istio latency 99 percentile (instance {{ $labels.instance }}) + description: + "Istio 1% slowest requests are longer than 1000ms.\n VALUE = {{ $value }}\n LABELS = + {{ $labels }}" - - alert: IstioHighRequestLatency - expr: 'rate(istio_request_duration_milliseconds_sum{reporter="destination"}[1m]) / rate(istio_request_duration_milliseconds_count{reporter="destination"}[1m]) > 100' - for: 1m - labels: - severity: warning - annotations: - summary: Istio high request latency (instance {{ $labels.instance }}) - description: "Istio average requests execution is longer than 100ms.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - - alert: IstioLatency99Percentile - expr: 'histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket[1m])) by (destination_canonical_service, destination_workload_namespace, source_canonical_service, source_workload_namespace, le)) > 1000' - for: 1m - labels: - severity: warning - annotations: - summary: Istio latency 99 percentile (instance {{ $labels.instance }}) - description: "Istio 1% slowest requests are longer than 1000ms.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - - alert: IstioPilotDuplicateEntry - expr: 'sum(rate(pilot_duplicate_envoy_clusters{}[5m])) > 0' - for: 0m - labels: - severity: critical - annotations: - summary: Istio Pilot Duplicate Entry (instance {{ $labels.instance }}) - description: "Istio pilot duplicate entry error.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: IstioPilotDuplicateEntry + expr: "sum(rate(pilot_duplicate_envoy_clusters{}[5m])) > 0" + for: 0m + labels: + severity: critical + annotations: + summary: Istio Pilot Duplicate Entry (instance {{ $labels.instance }}) + description: + "Istio pilot duplicate entry error.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" diff --git a/hosts/idols-ruby/prometheus/alert_rules/kubestate-exporter.yml b/hosts/idols-ruby/prometheus/alert_rules/kubestate-exporter.yml index e43a1fb2..f9241089 100644 --- a/hosts/idols-ruby/prometheus/alert_rules/kubestate-exporter.yml +++ b/hosts/idols-ruby/prometheus/alert_rules/kubestate-exporter.yml @@ -1,311 +1,435 @@ groups: + - name: KubestateExporter -- name: KubestateExporter + rules: + - alert: KubernetesNodeNotReady + expr: 'kube_node_status_condition{condition="Ready",status="true"} == 0' + for: 10m + labels: + severity: critical + annotations: + summary: Kubernetes Node ready (node {{ $labels.node }}) + description: + "Node {{ $labels.node }} has been unready for a long time\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - rules: + - alert: KubernetesNodeMemoryPressure + expr: 'kube_node_status_condition{condition="MemoryPressure",status="true"} == 1' + for: 2m + labels: + severity: critical + annotations: + summary: Kubernetes memory pressure (node {{ $labels.node }}) + description: + "Node {{ $labels.node }} has MemoryPressure condition\n VALUE = {{ $value }}\n LABELS + = {{ $labels }}" - - alert: KubernetesNodeNotReady - expr: 'kube_node_status_condition{condition="Ready",status="true"} == 0' - for: 10m - labels: - severity: critical - annotations: - summary: Kubernetes Node ready (node {{ $labels.node }}) - description: "Node {{ $labels.node }} has been unready for a long time\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesNodeDiskPressure + expr: 'kube_node_status_condition{condition="DiskPressure",status="true"} == 1' + for: 2m + labels: + severity: critical + annotations: + summary: Kubernetes disk pressure (node {{ $labels.node }}) + description: + "Node {{ $labels.node }} has DiskPressure condition\n VALUE = {{ $value }}\n LABELS = + {{ $labels }}" - - alert: KubernetesNodeMemoryPressure - expr: 'kube_node_status_condition{condition="MemoryPressure",status="true"} == 1' - for: 2m - labels: - severity: critical - annotations: - summary: Kubernetes memory pressure (node {{ $labels.node }}) - description: "Node {{ $labels.node }} has MemoryPressure condition\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesNodeNetworkUnavailable + expr: 'kube_node_status_condition{condition="NetworkUnavailable",status="true"} == 1' + for: 2m + labels: + severity: critical + annotations: + summary: Kubernetes Node network unavailable (instance {{ $labels.instance }}) + description: + "Node {{ $labels.node }} has NetworkUnavailable condition\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: KubernetesNodeDiskPressure - expr: 'kube_node_status_condition{condition="DiskPressure",status="true"} == 1' - for: 2m - labels: - severity: critical - annotations: - summary: Kubernetes disk pressure (node {{ $labels.node }}) - description: "Node {{ $labels.node }} has DiskPressure condition\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesNodeOutOfPodCapacity + expr: + 'sum by (node) ((kube_pod_status_phase{phase="Running"} == 1) + on(uid) group_left(node) + (0 * kube_pod_info{pod_template_hash=""})) / sum by (node) + (kube_node_status_allocatable{resource="pods"}) * 100 > 90' + for: 2m + labels: + severity: warning + annotations: + summary: Kubernetes Node out of pod capacity (instance {{ $labels.instance }}) + description: + "Node {{ $labels.node }} is out of pod capacity\n VALUE = {{ $value }}\n LABELS = {{ + $labels }}" - - alert: KubernetesNodeNetworkUnavailable - expr: 'kube_node_status_condition{condition="NetworkUnavailable",status="true"} == 1' - for: 2m - labels: - severity: critical - annotations: - summary: Kubernetes Node network unavailable (instance {{ $labels.instance }}) - description: "Node {{ $labels.node }} has NetworkUnavailable condition\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesContainerOomKiller + expr: + '(kube_pod_container_status_restarts_total - kube_pod_container_status_restarts_total + offset 10m >= 1) and ignoring (reason) + min_over_time(kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}[10m]) + == 1' + for: 0m + labels: + severity: warning + annotations: + summary: + Kubernetes container oom killer ({{ $labels.namespace }}/{{ $labels.pod }}:{{ + $labels.container }}) + description: + "Container {{ $labels.container }} in pod {{ $labels.namespace }}/{{ $labels.pod }} has + been OOMKilled {{ $value }} times in the last 10 minutes.\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: KubernetesNodeOutOfPodCapacity - expr: 'sum by (node) ((kube_pod_status_phase{phase="Running"} == 1) + on(uid) group_left(node) (0 * kube_pod_info{pod_template_hash=""})) / sum by (node) (kube_node_status_allocatable{resource="pods"}) * 100 > 90' - for: 2m - labels: - severity: warning - annotations: - summary: Kubernetes Node out of pod capacity (instance {{ $labels.instance }}) - description: "Node {{ $labels.node }} is out of pod capacity\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesJobFailed + expr: "kube_job_status_failed > 0" + for: 0m + labels: + severity: warning + annotations: + summary: Kubernetes Job failed ({{ $labels.namespace }}/{{ $labels.job_name }}) + description: + "Job {{ $labels.namespace }}/{{ $labels.job_name }} failed to complete\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesContainerOomKiller - expr: '(kube_pod_container_status_restarts_total - kube_pod_container_status_restarts_total offset 10m >= 1) and ignoring (reason) min_over_time(kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}[10m]) == 1' - for: 0m - labels: - severity: warning - annotations: - summary: Kubernetes container oom killer ({{ $labels.namespace }}/{{ $labels.pod }}:{{ $labels.container }}) - description: "Container {{ $labels.container }} in pod {{ $labels.namespace }}/{{ $labels.pod }} has been OOMKilled {{ $value }} times in the last 10 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesCronjobSuspended + expr: "kube_cronjob_spec_suspend != 0" + for: 0m + labels: + severity: warning + annotations: + summary: Kubernetes CronJob suspended ({{ $labels.namespace }}/{{ $labels.cronjob }}) + description: + "CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is suspended\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: KubernetesJobFailed - expr: 'kube_job_status_failed > 0' - for: 0m - labels: - severity: warning - annotations: - summary: Kubernetes Job failed ({{ $labels.namespace }}/{{ $labels.job_name }}) - description: "Job {{ $labels.namespace }}/{{ $labels.job_name }} failed to complete\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesPersistentvolumeclaimPending + expr: 'kube_persistentvolumeclaim_status_phase{phase="Pending"} == 1' + for: 2m + labels: + severity: warning + annotations: + summary: + Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{ + $labels.persistentvolumeclaim }}) + description: + "PersistentVolumeClaim {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} is + pending\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesCronjobSuspended - expr: 'kube_cronjob_spec_suspend != 0' - for: 0m - labels: - severity: warning - annotations: - summary: Kubernetes CronJob suspended ({{ $labels.namespace }}/{{ $labels.cronjob }}) - description: "CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is suspended\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesVolumeOutOfDiskSpace + expr: + "kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes * 100 < 10" + for: 2m + labels: + severity: warning + annotations: + summary: Kubernetes Volume out of disk space (instance {{ $labels.instance }}) + description: + "Volume is almost full (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesPersistentvolumeclaimPending - expr: 'kube_persistentvolumeclaim_status_phase{phase="Pending"} == 1' - for: 2m - labels: - severity: warning - annotations: - summary: Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }}) - description: "PersistentVolumeClaim {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} is pending\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesVolumeFullInFourDays + expr: "predict_linear(kubelet_volume_stats_available_bytes[6h:5m], 4 * 24 * 3600) < 0" + for: 0m + labels: + severity: critical + annotations: + summary: Kubernetes Volume full in four days (instance {{ $labels.instance }}) + description: + "Volume under {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} is expected to + fill up within four days. Currently {{ $value | humanize }}% is available.\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesVolumeOutOfDiskSpace - expr: 'kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes * 100 < 10' - for: 2m - labels: - severity: warning - annotations: - summary: Kubernetes Volume out of disk space (instance {{ $labels.instance }}) - description: "Volume is almost full (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesPersistentvolumeError + expr: + 'kube_persistentvolume_status_phase{phase=~"Failed|Pending", job="kube-state-metrics"} > 0' + for: 0m + labels: + severity: critical + annotations: + summary: + Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{ + $labels.persistentvolumeclaim }}) + description: + "Persistent volume {{ $labels.persistentvolume }} is in bad state\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: KubernetesVolumeFullInFourDays - expr: 'predict_linear(kubelet_volume_stats_available_bytes[6h:5m], 4 * 24 * 3600) < 0' - for: 0m - labels: - severity: critical - annotations: - summary: Kubernetes Volume full in four days (instance {{ $labels.instance }}) - description: "Volume under {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} is expected to fill up within four days. Currently {{ $value | humanize }}% is available.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesStatefulsetDown + expr: "kube_statefulset_replicas != kube_statefulset_status_replicas_ready > 0" + for: 1m + labels: + severity: critical + annotations: + summary: Kubernetes StatefulSet down ({{ $labels.namespace }}/{{ $labels.statefulset }}) + description: + "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} went down\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesPersistentvolumeError - expr: 'kube_persistentvolume_status_phase{phase=~"Failed|Pending", job="kube-state-metrics"} > 0' - for: 0m - labels: - severity: critical - annotations: - summary: Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }}) - description: "Persistent volume {{ $labels.persistentvolume }} is in bad state\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesHpaScaleInability + expr: + 'kube_horizontalpodautoscaler_status_condition{status="false", condition="AbleToScale"} == + 1' + for: 2m + labels: + severity: warning + annotations: + summary: Kubernetes HPA scale inability (instance {{ $labels.instance }}) + description: + "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is unable to + scale\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesStatefulsetDown - expr: 'kube_statefulset_replicas != kube_statefulset_status_replicas_ready > 0' - for: 1m - labels: - severity: critical - annotations: - summary: Kubernetes StatefulSet down ({{ $labels.namespace }}/{{ $labels.statefulset }}) - description: "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} went down\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesHpaMetricsUnavailability + expr: + 'kube_horizontalpodautoscaler_status_condition{status="false", condition="ScalingActive"} + == 1' + for: 0m + labels: + severity: warning + annotations: + summary: Kubernetes HPA metrics unavailability (instance {{ $labels.instance }}) + description: + "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is unable to collect + metrics\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesHpaScaleInability - expr: 'kube_horizontalpodautoscaler_status_condition{status="false", condition="AbleToScale"} == 1' - for: 2m - labels: - severity: warning - annotations: - summary: Kubernetes HPA scale inability (instance {{ $labels.instance }}) - description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is unable to scale\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesHpaScaleMaximum + expr: + "kube_horizontalpodautoscaler_status_desired_replicas >= + kube_horizontalpodautoscaler_spec_max_replicas" + for: 2m + labels: + severity: info + annotations: + summary: Kubernetes HPA scale maximum (instance {{ $labels.instance }}) + description: + "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} has hit maximum + number of desired pods\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesHpaMetricsUnavailability - expr: 'kube_horizontalpodautoscaler_status_condition{status="false", condition="ScalingActive"} == 1' - for: 0m - labels: - severity: warning - annotations: - summary: Kubernetes HPA metrics unavailability (instance {{ $labels.instance }}) - description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is unable to collect metrics\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesHpaUnderutilized + expr: + "max(quantile_over_time(0.5, kube_horizontalpodautoscaler_status_desired_replicas[1d]) == + kube_horizontalpodautoscaler_spec_min_replicas) by (horizontalpodautoscaler) > 3" + for: 0m + labels: + severity: info + annotations: + summary: Kubernetes HPA underutilized (instance {{ $labels.instance }}) + description: + "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is constantly at + minimum replicas for 50% of the time. Potential cost saving here.\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: KubernetesHpaScaleMaximum - expr: 'kube_horizontalpodautoscaler_status_desired_replicas >= kube_horizontalpodautoscaler_spec_max_replicas' - for: 2m - labels: - severity: info - annotations: - summary: Kubernetes HPA scale maximum (instance {{ $labels.instance }}) - description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} has hit maximum number of desired pods\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesPodNotHealthy + expr: 'sum by (namespace, pod) (kube_pod_status_phase{phase=~"Pending|Unknown|Failed"}) > 0' + for: 15m + labels: + severity: critical + annotations: + summary: Kubernetes Pod not healthy ({{ $labels.namespace }}/{{ $labels.pod }}) + description: + "Pod {{ $labels.namespace }}/{{ $labels.pod }} has been in a non-running state for + longer than 15 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesHpaUnderutilized - expr: 'max(quantile_over_time(0.5, kube_horizontalpodautoscaler_status_desired_replicas[1d]) == kube_horizontalpodautoscaler_spec_min_replicas) by (horizontalpodautoscaler) > 3' - for: 0m - labels: - severity: info - annotations: - summary: Kubernetes HPA underutilized (instance {{ $labels.instance }}) - description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is constantly at minimum replicas for 50% of the time. Potential cost saving here.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesPodCrashLooping + expr: "increase(kube_pod_container_status_restarts_total[1m]) > 3" + for: 2m + labels: + severity: warning + annotations: + summary: Kubernetes pod crash looping ({{ $labels.namespace }}/{{ $labels.pod }}) + description: + "Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash looping\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: KubernetesPodNotHealthy - expr: 'sum by (namespace, pod) (kube_pod_status_phase{phase=~"Pending|Unknown|Failed"}) > 0' - for: 15m - labels: - severity: critical - annotations: - summary: Kubernetes Pod not healthy ({{ $labels.namespace }}/{{ $labels.pod }}) - description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} has been in a non-running state for longer than 15 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesReplicasetReplicasMismatch + expr: "kube_replicaset_spec_replicas != kube_replicaset_status_ready_replicas" + for: 10m + labels: + severity: warning + annotations: + summary: + Kubernetes ReplicasSet mismatch ({{ $labels.namespace }}/{{ $labels.replicaset }}) + description: + "ReplicaSet {{ $labels.namespace }}/{{ $labels.replicaset }} replicas mismatch\n VALUE + = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesPodCrashLooping - expr: 'increase(kube_pod_container_status_restarts_total[1m]) > 3' - for: 2m - labels: - severity: warning - annotations: - summary: Kubernetes pod crash looping ({{ $labels.namespace }}/{{ $labels.pod }}) - description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash looping\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesDeploymentReplicasMismatch + expr: "kube_deployment_spec_replicas != kube_deployment_status_replicas_available" + for: 10m + labels: + severity: warning + annotations: + summary: + Kubernetes Deployment replicas mismatch ({{ $labels.namespace }}/{{ $labels.deployment + }}) + description: + "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} replicas mismatch\n VALUE + = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesReplicasetReplicasMismatch - expr: 'kube_replicaset_spec_replicas != kube_replicaset_status_ready_replicas' - for: 10m - labels: - severity: warning - annotations: - summary: Kubernetes ReplicasSet mismatch ({{ $labels.namespace }}/{{ $labels.replicaset }}) - description: "ReplicaSet {{ $labels.namespace }}/{{ $labels.replicaset }} replicas mismatch\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesStatefulsetReplicasMismatch + expr: "kube_statefulset_status_replicas_ready != kube_statefulset_status_replicas" + for: 10m + labels: + severity: warning + annotations: + summary: Kubernetes StatefulSet replicas mismatch (instance {{ $labels.instance }}) + description: + "StatefulSet does not match the expected number of replicas.\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: KubernetesDeploymentReplicasMismatch - expr: 'kube_deployment_spec_replicas != kube_deployment_status_replicas_available' - for: 10m - labels: - severity: warning - annotations: - summary: Kubernetes Deployment replicas mismatch ({{ $labels.namespace }}/{{ $labels.deployment }}) - description: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} replicas mismatch\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesDeploymentGenerationMismatch + expr: "kube_deployment_status_observed_generation != kube_deployment_metadata_generation" + for: 10m + labels: + severity: critical + annotations: + summary: + Kubernetes Deployment generation mismatch ({{ $labels.namespace }}/{{ $labels.deployment + }}) + description: + "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} has failed but has not been + rolled back.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesStatefulsetReplicasMismatch - expr: 'kube_statefulset_status_replicas_ready != kube_statefulset_status_replicas' - for: 10m - labels: - severity: warning - annotations: - summary: Kubernetes StatefulSet replicas mismatch (instance {{ $labels.instance }}) - description: "StatefulSet does not match the expected number of replicas.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesStatefulsetGenerationMismatch + expr: "kube_statefulset_status_observed_generation != kube_statefulset_metadata_generation" + for: 10m + labels: + severity: critical + annotations: + summary: + Kubernetes StatefulSet generation mismatch ({{ $labels.namespace }}/{{ + $labels.statefulset }}) + description: + "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} has failed but has not + been rolled back.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesDeploymentGenerationMismatch - expr: 'kube_deployment_status_observed_generation != kube_deployment_metadata_generation' - for: 10m - labels: - severity: critical - annotations: - summary: Kubernetes Deployment generation mismatch ({{ $labels.namespace }}/{{ $labels.deployment }}) - description: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} has failed but has not been rolled back.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesStatefulsetUpdateNotRolledOut + expr: + "max without (revision) (kube_statefulset_status_current_revision unless + kube_statefulset_status_update_revision) * (kube_statefulset_replicas != + kube_statefulset_status_replicas_updated)" + for: 10m + labels: + severity: warning + annotations: + summary: + Kubernetes StatefulSet update not rolled out ({{ $labels.namespace }}/{{ + $labels.statefulset }}) + description: + "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} update has not been + rolled out.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesStatefulsetGenerationMismatch - expr: 'kube_statefulset_status_observed_generation != kube_statefulset_metadata_generation' - for: 10m - labels: - severity: critical - annotations: - summary: Kubernetes StatefulSet generation mismatch ({{ $labels.namespace }}/{{ $labels.statefulset }}) - description: "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} has failed but has not been rolled back.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesDaemonsetRolloutStuck + expr: + "kube_daemonset_status_number_ready / kube_daemonset_status_desired_number_scheduled * 100 + < 100 or kube_daemonset_status_desired_number_scheduled - + kube_daemonset_status_current_number_scheduled > 0" + for: 10m + labels: + severity: warning + annotations: + summary: + Kubernetes DaemonSet rollout stuck ({{ $labels.namespace }}/{{ $labels.daemonset }}) + description: + "Some Pods of DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} are not + scheduled or not ready\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesStatefulsetUpdateNotRolledOut - expr: 'max without (revision) (kube_statefulset_status_current_revision unless kube_statefulset_status_update_revision) * (kube_statefulset_replicas != kube_statefulset_status_replicas_updated)' - for: 10m - labels: - severity: warning - annotations: - summary: Kubernetes StatefulSet update not rolled out ({{ $labels.namespace }}/{{ $labels.statefulset }}) - description: "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} update has not been rolled out.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesDaemonsetMisscheduled + expr: "kube_daemonset_status_number_misscheduled > 0" + for: 1m + labels: + severity: critical + annotations: + summary: + Kubernetes DaemonSet misscheduled ({{ $labels.namespace }}/{{ $labels.daemonset }}) + description: + "Some Pods of DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} are running + where they are not supposed to run\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesDaemonsetRolloutStuck - expr: 'kube_daemonset_status_number_ready / kube_daemonset_status_desired_number_scheduled * 100 < 100 or kube_daemonset_status_desired_number_scheduled - kube_daemonset_status_current_number_scheduled > 0' - for: 10m - labels: - severity: warning - annotations: - summary: Kubernetes DaemonSet rollout stuck ({{ $labels.namespace }}/{{ $labels.daemonset }}) - description: "Some Pods of DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} are not scheduled or not ready\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesCronjobTooLong + expr: "time() - kube_cronjob_next_schedule_time > 3600" + for: 0m + labels: + severity: warning + annotations: + summary: Kubernetes CronJob too long ({{ $labels.namespace }}/{{ $labels.cronjob }}) + description: + "CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is taking more than 1h to + complete.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesDaemonsetMisscheduled - expr: 'kube_daemonset_status_number_misscheduled > 0' - for: 1m - labels: - severity: critical - annotations: - summary: Kubernetes DaemonSet misscheduled ({{ $labels.namespace }}/{{ $labels.daemonset }}) - description: "Some Pods of DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} are running where they are not supposed to run\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesJobSlowCompletion + expr: "kube_job_spec_completions - kube_job_status_succeeded - kube_job_status_failed > 0" + for: 12h + labels: + severity: critical + annotations: + summary: Kubernetes job slow completion ({{ $labels.namespace }}/{{ $labels.job_name }}) + description: + "Kubernetes Job {{ $labels.namespace }}/{{ $labels.job_name }} did not complete in + time.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesCronjobTooLong - expr: 'time() - kube_cronjob_next_schedule_time > 3600' - for: 0m - labels: - severity: warning - annotations: - summary: Kubernetes CronJob too long ({{ $labels.namespace }}/{{ $labels.cronjob }}) - description: "CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is taking more than 1h to complete.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesApiServerErrors + expr: + 'sum(rate(apiserver_request_total{job="apiserver",code=~"^(?:5..)$"}[1m])) / + sum(rate(apiserver_request_total{job="apiserver"}[1m])) * 100 > 3' + for: 2m + labels: + severity: critical + annotations: + summary: Kubernetes API server errors (instance {{ $labels.instance }}) + description: + "Kubernetes API server is experiencing high error rate\n VALUE = {{ $value }}\n LABELS + = {{ $labels }}" - - alert: KubernetesJobSlowCompletion - expr: 'kube_job_spec_completions - kube_job_status_succeeded - kube_job_status_failed > 0' - for: 12h - labels: - severity: critical - annotations: - summary: Kubernetes job slow completion ({{ $labels.namespace }}/{{ $labels.job_name }}) - description: "Kubernetes Job {{ $labels.namespace }}/{{ $labels.job_name }} did not complete in time.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesApiClientErrors + expr: + '(sum(rate(rest_client_requests_total{code=~"(4|5).."}[1m])) by (instance, job) / + sum(rate(rest_client_requests_total[1m])) by (instance, job)) * 100 > 1' + for: 2m + labels: + severity: critical + annotations: + summary: Kubernetes API client errors (instance {{ $labels.instance }}) + description: + "Kubernetes API client is experiencing high error rate\n VALUE = {{ $value }}\n LABELS + = {{ $labels }}" - - alert: KubernetesApiServerErrors - expr: 'sum(rate(apiserver_request_total{job="apiserver",code=~"^(?:5..)$"}[1m])) / sum(rate(apiserver_request_total{job="apiserver"}[1m])) * 100 > 3' - for: 2m - labels: - severity: critical - annotations: - summary: Kubernetes API server errors (instance {{ $labels.instance }}) - description: "Kubernetes API server is experiencing high error rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesClientCertificateExpiresNextWeek + expr: + 'apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and + histogram_quantile(0.01, sum by (job, le) + (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) < + 7*24*60*60' + for: 0m + labels: + severity: warning + annotations: + summary: Kubernetes client certificate expires next week (instance {{ $labels.instance }}) + description: + "A client certificate used to authenticate to the apiserver is expiring next + week.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesApiClientErrors - expr: '(sum(rate(rest_client_requests_total{code=~"(4|5).."}[1m])) by (instance, job) / sum(rate(rest_client_requests_total[1m])) by (instance, job)) * 100 > 1' - for: 2m - labels: - severity: critical - annotations: - summary: Kubernetes API client errors (instance {{ $labels.instance }}) - description: "Kubernetes API client is experiencing high error rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesClientCertificateExpiresSoon + expr: + 'apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and + histogram_quantile(0.01, sum by (job, le) + (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) < + 24*60*60' + for: 0m + labels: + severity: critical + annotations: + summary: Kubernetes client certificate expires soon (instance {{ $labels.instance }}) + description: + "A client certificate used to authenticate to the apiserver is expiring in less than + 24.0 hours.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: KubernetesClientCertificateExpiresNextWeek - expr: 'apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and histogram_quantile(0.01, sum by (job, le) (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) < 7*24*60*60' - for: 0m - labels: - severity: warning - annotations: - summary: Kubernetes client certificate expires next week (instance {{ $labels.instance }}) - description: "A client certificate used to authenticate to the apiserver is expiring next week.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - - alert: KubernetesClientCertificateExpiresSoon - expr: 'apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and histogram_quantile(0.01, sum by (job, le) (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) < 24*60*60' - for: 0m - labels: - severity: critical - annotations: - summary: Kubernetes client certificate expires soon (instance {{ $labels.instance }}) - description: "A client certificate used to authenticate to the apiserver is expiring in less than 24.0 hours.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - - alert: KubernetesApiServerLatency - expr: 'histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{subresource!="log",verb!~"^(?:CONNECT|WATCHLIST|WATCH|PROXY)$"} [10m])) WITHOUT (instance, resource)) > 1' - for: 2m - labels: - severity: warning - annotations: - summary: Kubernetes API server latency (instance {{ $labels.instance }}) - description: "Kubernetes API server has a 99th percentile latency of {{ $value }} seconds for {{ $labels.verb }} {{ $labels.resource }}.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: KubernetesApiServerLatency + expr: + 'histogram_quantile(0.99, + sum(rate(apiserver_request_duration_seconds_bucket{subresource!="log",verb!~"^(?:CONNECT|WATCHLIST|WATCH|PROXY)$"} + [10m])) WITHOUT (instance, resource)) > 1' + for: 2m + labels: + severity: warning + annotations: + summary: Kubernetes API server latency (instance {{ $labels.instance }}) + description: + "Kubernetes API server has a 99th percentile latency of {{ $value }} seconds for {{ + $labels.verb }} {{ $labels.resource }}.\n VALUE = {{ $value }}\n LABELS = {{ $labels + }}" diff --git a/hosts/idols-ruby/prometheus/alert_rules/node-exporter.yml b/hosts/idols-ruby/prometheus/alert_rules/node-exporter.yml index de48231e..8ea26f8c 100644 --- a/hosts/idols-ruby/prometheus/alert_rules/node-exporter.yml +++ b/hosts/idols-ruby/prometheus/alert_rules/node-exporter.yml @@ -1,347 +1,508 @@ groups: + - name: NodeExporter -- name: NodeExporter + rules: + - alert: HostOutOfMemory + expr: + '(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 10) * on(instance) + group_left (nodename) node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host out of memory (instance {{ $labels.instance }}) + description: + "Node memory is filling up (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels + }}" - rules: + - alert: HostMemoryUnderMemoryPressure + expr: + '(rate(node_vmstat_pgmajfault[1m]) > 1000) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host memory under memory pressure (instance {{ $labels.instance }}) + description: + "The node is under heavy memory pressure. High rate of major page faults\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - - alert: HostOutOfMemory - expr: '(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 10) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host out of memory (instance {{ $labels.instance }}) - description: "Node memory is filling up (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostMemoryIsUnderutilized + expr: + '(100 - (avg_over_time(node_memory_MemAvailable_bytes[30m]) / node_memory_MemTotal_bytes * + 100) < 20) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 1w + labels: + severity: info + annotations: + summary: Host Memory is underutilized (instance {{ $labels.instance }}) + description: + "Node memory is < 20% for 1 week. Consider reducing memory space. (instance {{ + $labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostMemoryUnderMemoryPressure - expr: '(rate(node_vmstat_pgmajfault[1m]) > 1000) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host memory under memory pressure (instance {{ $labels.instance }}) - description: "The node is under heavy memory pressure. High rate of major page faults\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostUnusualNetworkThroughputIn + expr: + '(sum by (instance) (rate(node_network_receive_bytes_total[2m])) / 1024 / 1024 > 100) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 5m + labels: + severity: warning + annotations: + summary: Host unusual network throughput in (instance {{ $labels.instance }}) + description: + "Host network interfaces are probably receiving too much data (> 100 MB/s)\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - - alert: HostMemoryIsUnderutilized - expr: '(100 - (avg_over_time(node_memory_MemAvailable_bytes[30m]) / node_memory_MemTotal_bytes * 100) < 20) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 1w - labels: - severity: info - annotations: - summary: Host Memory is underutilized (instance {{ $labels.instance }}) - description: "Node memory is < 20% for 1 week. Consider reducing memory space. (instance {{ $labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostUnusualNetworkThroughputOut + expr: + '(sum by (instance) (rate(node_network_transmit_bytes_total[2m])) / 1024 / 1024 > 100) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 5m + labels: + severity: warning + annotations: + summary: Host unusual network throughput out (instance {{ $labels.instance }}) + description: + "Host network interfaces are probably sending too much data (> 100 MB/s)\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - - alert: HostUnusualNetworkThroughputIn - expr: '(sum by (instance) (rate(node_network_receive_bytes_total[2m])) / 1024 / 1024 > 100) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 5m - labels: - severity: warning - annotations: - summary: Host unusual network throughput in (instance {{ $labels.instance }}) - description: "Host network interfaces are probably receiving too much data (> 100 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostUnusualDiskReadRate + expr: + '(sum by (instance) (rate(node_disk_read_bytes_total[2m])) / 1024 / 1024 > 50) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 5m + labels: + severity: warning + annotations: + summary: Host unusual disk read rate (instance {{ $labels.instance }}) + description: + "Disk is probably reading too much data (> 50 MB/s)\n VALUE = {{ $value }}\n LABELS = + {{ $labels }}" - - alert: HostUnusualNetworkThroughputOut - expr: '(sum by (instance) (rate(node_network_transmit_bytes_total[2m])) / 1024 / 1024 > 100) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 5m - labels: - severity: warning - annotations: - summary: Host unusual network throughput out (instance {{ $labels.instance }}) - description: "Host network interfaces are probably sending too much data (> 100 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostUnusualDiskWriteRate + expr: + '(sum by (instance) (rate(node_disk_written_bytes_total[2m])) / 1024 / 1024 > 50) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host unusual disk write rate (instance {{ $labels.instance }}) + description: + "Disk is probably writing too much data (> 50 MB/s)\n VALUE = {{ $value }}\n LABELS = + {{ $labels }}" - - alert: HostUnusualDiskReadRate - expr: '(sum by (instance) (rate(node_disk_read_bytes_total[2m])) / 1024 / 1024 > 50) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 5m - labels: - severity: warning - annotations: - summary: Host unusual disk read rate (instance {{ $labels.instance }}) - description: "Disk is probably reading too much data (> 50 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostOutOfDiskSpace + expr: + '((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes < 10 and ON (instance, + device, mountpoint) node_filesystem_readonly == 0) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host out of disk space (instance {{ $labels.instance }}) + description: + "Disk is almost full (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostUnusualDiskWriteRate - expr: '(sum by (instance) (rate(node_disk_written_bytes_total[2m])) / 1024 / 1024 > 50) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host unusual disk write rate (instance {{ $labels.instance }}) - description: "Disk is probably writing too much data (> 50 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostDiskWillFillIn24Hours + expr: + '((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes < 10 and ON (instance, + device, mountpoint) predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs"}[1h], 24 * + 3600) < 0 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host disk will fill in 24 hours (instance {{ $labels.instance }}) + description: + "Filesystem is predicted to run out of space within the next 24 hours at current write + rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostOutOfDiskSpace - expr: '((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes < 10 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host out of disk space (instance {{ $labels.instance }}) - description: "Disk is almost full (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostOutOfInodes + expr: + '(node_filesystem_files_free{fstype!="msdosfs"} / node_filesystem_files{fstype!="msdosfs"} + * 100 < 10 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host out of inodes (instance {{ $labels.instance }}) + description: + "Disk is almost running out of available inodes (< 10% left)\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: HostDiskWillFillIn24Hours - expr: '((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes < 10 and ON (instance, device, mountpoint) predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs"}[1h], 24 * 3600) < 0 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host disk will fill in 24 hours (instance {{ $labels.instance }}) - description: "Filesystem is predicted to run out of space within the next 24 hours at current write rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostFilesystemDeviceError + expr: "node_filesystem_device_error == 1" + for: 0m + labels: + severity: critical + annotations: + summary: Host filesystem device error (instance {{ $labels.instance }}) + description: + "{{ $labels.instance }}: Device error with the {{ $labels.mountpoint }} + filesystem\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostOutOfInodes - expr: '(node_filesystem_files_free{fstype!="msdosfs"} / node_filesystem_files{fstype!="msdosfs"} * 100 < 10 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host out of inodes (instance {{ $labels.instance }}) - description: "Disk is almost running out of available inodes (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostInodesWillFillIn24Hours + expr: + '(node_filesystem_files_free{fstype!="msdosfs"} / node_filesystem_files{fstype!="msdosfs"} + * 100 < 10 and predict_linear(node_filesystem_files_free{fstype!="msdosfs"}[1h], 24 * + 3600) < 0 and ON (instance, device, mountpoint) + node_filesystem_readonly{fstype!="msdosfs"} == 0) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host inodes will fill in 24 hours (instance {{ $labels.instance }}) + description: + "Filesystem is predicted to run out of inodes within the next 24 hours at current write + rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostFilesystemDeviceError - expr: 'node_filesystem_device_error == 1' - for: 0m - labels: - severity: critical - annotations: - summary: Host filesystem device error (instance {{ $labels.instance }}) - description: "{{ $labels.instance }}: Device error with the {{ $labels.mountpoint }} filesystem\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostUnusualDiskReadLatency + expr: + '(rate(node_disk_read_time_seconds_total[1m]) / rate(node_disk_reads_completed_total[1m]) + > 0.1 and rate(node_disk_reads_completed_total[1m]) > 0) * on(instance) group_left + (nodename) node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host unusual disk read latency (instance {{ $labels.instance }}) + description: + "Disk latency is growing (read operations > 100ms)\n VALUE = {{ $value }}\n LABELS = + {{ $labels }}" - - alert: HostInodesWillFillIn24Hours - expr: '(node_filesystem_files_free{fstype!="msdosfs"} / node_filesystem_files{fstype!="msdosfs"} * 100 < 10 and predict_linear(node_filesystem_files_free{fstype!="msdosfs"}[1h], 24 * 3600) < 0 and ON (instance, device, mountpoint) node_filesystem_readonly{fstype!="msdosfs"} == 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host inodes will fill in 24 hours (instance {{ $labels.instance }}) - description: "Filesystem is predicted to run out of inodes within the next 24 hours at current write rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostUnusualDiskWriteLatency + expr: + '(rate(node_disk_write_time_seconds_total[1m]) / + rate(node_disk_writes_completed_total[1m]) > 0.1 and + rate(node_disk_writes_completed_total[1m]) > 0) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host unusual disk write latency (instance {{ $labels.instance }}) + description: + "Disk latency is growing (write operations > 100ms)\n VALUE = {{ $value }}\n LABELS = + {{ $labels }}" - - alert: HostUnusualDiskReadLatency - expr: '(rate(node_disk_read_time_seconds_total[1m]) / rate(node_disk_reads_completed_total[1m]) > 0.1 and rate(node_disk_reads_completed_total[1m]) > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host unusual disk read latency (instance {{ $labels.instance }}) - description: "Disk latency is growing (read operations > 100ms)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostHighCpuLoad + expr: + '(sum by (instance) (avg by (mode, instance) + (rate(node_cpu_seconds_total{mode!="idle"}[2m]))) > 0.8) * on(instance) group_left + (nodename) node_uname_info{nodename=~".+"}' + for: 10m + labels: + severity: warning + annotations: + summary: Host high CPU load (instance {{ $labels.instance }}) + description: "CPU load is > 80%\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostUnusualDiskWriteLatency - expr: '(rate(node_disk_write_time_seconds_total[1m]) / rate(node_disk_writes_completed_total[1m]) > 0.1 and rate(node_disk_writes_completed_total[1m]) > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host unusual disk write latency (instance {{ $labels.instance }}) - description: "Disk latency is growing (write operations > 100ms)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostCpuIsUnderutilized + expr: + '(100 - (rate(node_cpu_seconds_total{mode="idle"}[30m]) * 100) < 20) * on(instance) + group_left (nodename) node_uname_info{nodename=~".+"}' + for: 1w + labels: + severity: info + annotations: + summary: Host CPU is underutilized (instance {{ $labels.instance }}) + description: + "CPU load is < 20% for 1 week. Consider reducing the number of CPUs.\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - - alert: HostHighCpuLoad - expr: '(sum by (instance) (avg by (mode, instance) (rate(node_cpu_seconds_total{mode!="idle"}[2m]))) > 0.8) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 10m - labels: - severity: warning - annotations: - summary: Host high CPU load (instance {{ $labels.instance }}) - description: "CPU load is > 80%\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostCpuStealNoisyNeighbor + expr: + '(avg by(instance) (rate(node_cpu_seconds_total{mode="steal"}[5m])) * 100 > 10) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 0m + labels: + severity: warning + annotations: + summary: Host CPU steal noisy neighbor (instance {{ $labels.instance }}) + description: + "CPU steal is > 10%. A noisy neighbor is killing VM performances or a spot instance may + be out of credit.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostCpuIsUnderutilized - expr: '(100 - (rate(node_cpu_seconds_total{mode="idle"}[30m]) * 100) < 20) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 1w - labels: - severity: info - annotations: - summary: Host CPU is underutilized (instance {{ $labels.instance }}) - description: "CPU load is < 20% for 1 week. Consider reducing the number of CPUs.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostCpuHighIowait + expr: + '(avg by (instance) (rate(node_cpu_seconds_total{mode="iowait"}[5m])) * 100 > 10) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 0m + labels: + severity: warning + annotations: + summary: Host CPU high iowait (instance {{ $labels.instance }}) + description: + "CPU iowait > 10%. A high iowait means that you are disk or network bound.\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - - alert: HostCpuStealNoisyNeighbor - expr: '(avg by(instance) (rate(node_cpu_seconds_total{mode="steal"}[5m])) * 100 > 10) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 0m - labels: - severity: warning - annotations: - summary: Host CPU steal noisy neighbor (instance {{ $labels.instance }}) - description: "CPU steal is > 10%. A noisy neighbor is killing VM performances or a spot instance may be out of credit.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostUnusualDiskIo + expr: + '(rate(node_disk_io_time_seconds_total[1m]) > 0.5) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 5m + labels: + severity: warning + annotations: + summary: Host unusual disk IO (instance {{ $labels.instance }}) + description: + "Time spent in IO is too high on {{ $labels.instance }}. Check storage for + issues.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostCpuHighIowait - expr: '(avg by (instance) (rate(node_cpu_seconds_total{mode="iowait"}[5m])) * 100 > 10) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 0m - labels: - severity: warning - annotations: - summary: Host CPU high iowait (instance {{ $labels.instance }}) - description: "CPU iowait > 10%. A high iowait means that you are disk or network bound.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostContextSwitching + expr: + '((rate(node_context_switches_total[5m])) / (count without(cpu, mode) + (node_cpu_seconds_total{mode="idle"})) > 10000) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 0m + labels: + severity: warning + annotations: + summary: Host context switching (instance {{ $labels.instance }}) + description: + "Context switching is growing on the node (> 10000 / CPU / s)\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: HostUnusualDiskIo - expr: '(rate(node_disk_io_time_seconds_total[1m]) > 0.5) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 5m - labels: - severity: warning - annotations: - summary: Host unusual disk IO (instance {{ $labels.instance }}) - description: "Time spent in IO is too high on {{ $labels.instance }}. Check storage for issues.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostSwapIsFillingUp + expr: + '((1 - (node_memory_SwapFree_bytes / node_memory_SwapTotal_bytes)) * 100 > 80) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host swap is filling up (instance {{ $labels.instance }}) + description: "Swap is filling up (>80%)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostContextSwitching - expr: '((rate(node_context_switches_total[5m])) / (count without(cpu, mode) (node_cpu_seconds_total{mode="idle"})) > 10000) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 0m - labels: - severity: warning - annotations: - summary: Host context switching (instance {{ $labels.instance }}) - description: "Context switching is growing on the node (> 10000 / CPU / s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostSystemdServiceCrashed + expr: + '(node_systemd_unit_state{state="failed"} == 1) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 0m + labels: + severity: warning + annotations: + summary: Host systemd service crashed (instance {{ $labels.instance }}) + description: "systemd service crashed\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostSwapIsFillingUp - expr: '((1 - (node_memory_SwapFree_bytes / node_memory_SwapTotal_bytes)) * 100 > 80) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host swap is filling up (instance {{ $labels.instance }}) - description: "Swap is filling up (>80%)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostPhysicalComponentTooHot + expr: + '((node_hwmon_temp_celsius * ignoring(label) group_left(instance, job, node, sensor) + node_hwmon_sensor_label{label!="tctl"} > 75)) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 5m + labels: + severity: warning + annotations: + summary: Host physical component too hot (instance {{ $labels.instance }}) + description: + "Physical hardware component too hot\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostSystemdServiceCrashed - expr: '(node_systemd_unit_state{state="failed"} == 1) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 0m - labels: - severity: warning - annotations: - summary: Host systemd service crashed (instance {{ $labels.instance }}) - description: "systemd service crashed\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostNodeOvertemperatureAlarm + expr: + '(node_hwmon_temp_crit_alarm_celsius == 1) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 0m + labels: + severity: critical + annotations: + summary: Host node overtemperature alarm (instance {{ $labels.instance }}) + description: + "Physical node temperature alarm triggered\n VALUE = {{ $value }}\n LABELS = {{ + $labels }}" - - alert: HostPhysicalComponentTooHot - expr: '((node_hwmon_temp_celsius * ignoring(label) group_left(instance, job, node, sensor) node_hwmon_sensor_label{label!="tctl"} > 75)) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 5m - labels: - severity: warning - annotations: - summary: Host physical component too hot (instance {{ $labels.instance }}) - description: "Physical hardware component too hot\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostRaidArrayGotInactive + expr: + '(node_md_state{state="inactive"} > 0) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 0m + labels: + severity: critical + annotations: + summary: Host RAID array got inactive (instance {{ $labels.instance }}) + description: + "RAID array {{ $labels.device }} is in a degraded state due to one or more disk + failures. The number of spare drives is insufficient to fix the issue + automatically.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostNodeOvertemperatureAlarm - expr: '(node_hwmon_temp_crit_alarm_celsius == 1) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 0m - labels: - severity: critical - annotations: - summary: Host node overtemperature alarm (instance {{ $labels.instance }}) - description: "Physical node temperature alarm triggered\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostRaidDiskFailure + expr: + '(node_md_disks{state="failed"} > 0) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host RAID disk failure (instance {{ $labels.instance }}) + description: + "At least one device in RAID array on {{ $labels.instance }} failed. Array {{ + $labels.md_device }} needs attention and possibly a disk swap\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: HostRaidArrayGotInactive - expr: '(node_md_state{state="inactive"} > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 0m - labels: - severity: critical - annotations: - summary: Host RAID array got inactive (instance {{ $labels.instance }}) - description: "RAID array {{ $labels.device }} is in a degraded state due to one or more disk failures. The number of spare drives is insufficient to fix the issue automatically.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostKernelVersionDeviations + expr: + '(count(sum(label_replace(node_uname_info, "kernel", "$1", "release", + "([0-9]+.[0-9]+.[0-9]+).*")) by (kernel)) > 1) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 6h + labels: + severity: warning + annotations: + summary: Host kernel version deviations (instance {{ $labels.instance }}) + description: + "Different kernel versions are running\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostRaidDiskFailure - expr: '(node_md_disks{state="failed"} > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host RAID disk failure (instance {{ $labels.instance }}) - description: "At least one device in RAID array on {{ $labels.instance }} failed. Array {{ $labels.md_device }} needs attention and possibly a disk swap\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostOomKillDetected + expr: + '(increase(node_vmstat_oom_kill[1m]) > 0) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 0m + labels: + severity: warning + annotations: + summary: Host OOM kill detected (instance {{ $labels.instance }}) + description: "OOM kill detected\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostKernelVersionDeviations - expr: '(count(sum(label_replace(node_uname_info, "kernel", "$1", "release", "([0-9]+.[0-9]+.[0-9]+).*")) by (kernel)) > 1) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 6h - labels: - severity: warning - annotations: - summary: Host kernel version deviations (instance {{ $labels.instance }}) - description: "Different kernel versions are running\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostEdacCorrectableErrorsDetected + expr: + '(increase(node_edac_correctable_errors_total[1m]) > 0) * on(instance) group_left + (nodename) node_uname_info{nodename=~".+"}' + for: 0m + labels: + severity: info + annotations: + summary: Host EDAC Correctable Errors detected (instance {{ $labels.instance }}) + description: + "Host {{ $labels.instance }} has had {{ printf \"%.0f\" $value }} correctable memory + errors reported by EDAC in the last 5 minutes.\n VALUE = {{ $value }}\n LABELS = {{ + $labels }}" - - alert: HostOomKillDetected - expr: '(increase(node_vmstat_oom_kill[1m]) > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 0m - labels: - severity: warning - annotations: - summary: Host OOM kill detected (instance {{ $labels.instance }}) - description: "OOM kill detected\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostEdacUncorrectableErrorsDetected + expr: + '(node_edac_uncorrectable_errors_total > 0) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 0m + labels: + severity: warning + annotations: + summary: Host EDAC Uncorrectable Errors detected (instance {{ $labels.instance }}) + description: + "Host {{ $labels.instance }} has had {{ printf \"%.0f\" $value }} uncorrectable memory + errors reported by EDAC in the last 5 minutes.\n VALUE = {{ $value }}\n LABELS = {{ + $labels }}" - - alert: HostEdacCorrectableErrorsDetected - expr: '(increase(node_edac_correctable_errors_total[1m]) > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 0m - labels: - severity: info - annotations: - summary: Host EDAC Correctable Errors detected (instance {{ $labels.instance }}) - description: "Host {{ $labels.instance }} has had {{ printf \"%.0f\" $value }} correctable memory errors reported by EDAC in the last 5 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostNetworkReceiveErrors + expr: + '(rate(node_network_receive_errs_total[2m]) / rate(node_network_receive_packets_total[2m]) + > 0.01) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host Network Receive Errors (instance {{ $labels.instance }}) + description: + "Host {{ $labels.instance }} interface {{ $labels.device }} has encountered {{ printf + \"%.0f\" $value }} receive errors in the last two minutes.\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: HostEdacUncorrectableErrorsDetected - expr: '(node_edac_uncorrectable_errors_total > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 0m - labels: - severity: warning - annotations: - summary: Host EDAC Uncorrectable Errors detected (instance {{ $labels.instance }}) - description: "Host {{ $labels.instance }} has had {{ printf \"%.0f\" $value }} uncorrectable memory errors reported by EDAC in the last 5 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostNetworkTransmitErrors + expr: + '(rate(node_network_transmit_errs_total[2m]) / + rate(node_network_transmit_packets_total[2m]) > 0.01) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host Network Transmit Errors (instance {{ $labels.instance }}) + description: + "Host {{ $labels.instance }} interface {{ $labels.device }} has encountered {{ printf + \"%.0f\" $value }} transmit errors in the last two minutes.\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: HostNetworkReceiveErrors - expr: '(rate(node_network_receive_errs_total[2m]) / rate(node_network_receive_packets_total[2m]) > 0.01) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host Network Receive Errors (instance {{ $labels.instance }}) - description: "Host {{ $labels.instance }} interface {{ $labels.device }} has encountered {{ printf \"%.0f\" $value }} receive errors in the last two minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostNetworkInterfaceSaturated + expr: + '((rate(node_network_receive_bytes_total{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"}[1m]) + + rate(node_network_transmit_bytes_total{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"}[1m])) / + node_network_speed_bytes{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"} > 0.8 < 10000) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 1m + labels: + severity: warning + annotations: + summary: Host Network Interface Saturated (instance {{ $labels.instance }}) + description: + "The network interface \"{{ $labels.device }}\" on \"{{ $labels.instance }}\" is getting + overloaded.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostNetworkTransmitErrors - expr: '(rate(node_network_transmit_errs_total[2m]) / rate(node_network_transmit_packets_total[2m]) > 0.01) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host Network Transmit Errors (instance {{ $labels.instance }}) - description: "Host {{ $labels.instance }} interface {{ $labels.device }} has encountered {{ printf \"%.0f\" $value }} transmit errors in the last two minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostNetworkBondDegraded + expr: + '((node_bonding_active - node_bonding_slaves) != 0) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host Network Bond Degraded (instance {{ $labels.instance }}) + description: + "Bond \"{{ $labels.device }}\" degraded on \"{{ $labels.instance }}\".\n VALUE = {{ + $value }}\n LABELS = {{ $labels }}" - - alert: HostNetworkInterfaceSaturated - expr: '((rate(node_network_receive_bytes_total{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"}[1m]) + rate(node_network_transmit_bytes_total{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"}[1m])) / node_network_speed_bytes{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"} > 0.8 < 10000) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 1m - labels: - severity: warning - annotations: - summary: Host Network Interface Saturated (instance {{ $labels.instance }}) - description: "The network interface \"{{ $labels.device }}\" on \"{{ $labels.instance }}\" is getting overloaded.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostConntrackLimit + expr: + '(node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.8) * on(instance) + group_left (nodename) node_uname_info{nodename=~".+"}' + for: 5m + labels: + severity: warning + annotations: + summary: Host conntrack limit (instance {{ $labels.instance }}) + description: + "The number of conntrack is approaching limit\n VALUE = {{ $value }}\n LABELS = {{ + $labels }}" - - alert: HostNetworkBondDegraded - expr: '((node_bonding_active - node_bonding_slaves) != 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host Network Bond Degraded (instance {{ $labels.instance }}) - description: "Bond \"{{ $labels.device }}\" degraded on \"{{ $labels.instance }}\".\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostClockSkew + expr: + '((node_timex_offset_seconds > 0.05 and deriv(node_timex_offset_seconds[5m]) >= 0) or + (node_timex_offset_seconds < -0.05 and deriv(node_timex_offset_seconds[5m]) <= 0)) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 10m + labels: + severity: warning + annotations: + summary: Host clock skew (instance {{ $labels.instance }}) + description: + "Clock skew detected. Clock is out of sync. Ensure NTP is configured correctly on this + host.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - alert: HostConntrackLimit - expr: '(node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.8) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 5m - labels: - severity: warning - annotations: - summary: Host conntrack limit (instance {{ $labels.instance }}) - description: "The number of conntrack is approaching limit\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostClockNotSynchronising + expr: + '(min_over_time(node_timex_sync_status[1m]) == 0 and node_timex_maxerror_seconds >= 16) * + on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' + for: 2m + labels: + severity: warning + annotations: + summary: Host clock not synchronising (instance {{ $labels.instance }}) + description: + "Clock not synchronising. Ensure NTP is configured on this host.\n VALUE = {{ $value + }}\n LABELS = {{ $labels }}" - - alert: HostClockSkew - expr: '((node_timex_offset_seconds > 0.05 and deriv(node_timex_offset_seconds[5m]) >= 0) or (node_timex_offset_seconds < -0.05 and deriv(node_timex_offset_seconds[5m]) <= 0)) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 10m - labels: - severity: warning - annotations: - summary: Host clock skew (instance {{ $labels.instance }}) - description: "Clock skew detected. Clock is out of sync. Ensure NTP is configured correctly on this host.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - - alert: HostClockNotSynchronising - expr: '(min_over_time(node_timex_sync_status[1m]) == 0 and node_timex_maxerror_seconds >= 16) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 2m - labels: - severity: warning - annotations: - summary: Host clock not synchronising (instance {{ $labels.instance }}) - description: "Clock not synchronising. Ensure NTP is configured on this host.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" - - - alert: HostRequiresReboot - expr: '(node_reboot_required > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' - for: 4h - labels: - severity: info - annotations: - summary: Host requires reboot (instance {{ $labels.instance }}) - description: "{{ $labels.instance }} requires a reboot.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" + - alert: HostRequiresReboot + expr: + '(node_reboot_required > 0) * on(instance) group_left (nodename) + node_uname_info{nodename=~".+"}' + for: 4h + labels: + severity: info + annotations: + summary: Host requires reboot (instance {{ $labels.instance }}) + description: + "{{ $labels.instance }} requires a reboot.\n VALUE = {{ $value }}\n LABELS = {{ + $labels }}" diff --git a/hosts/k8s/README.md b/hosts/k8s/README.md index ca83f371..d798162c 100644 --- a/hosts/k8s/README.md +++ b/hosts/k8s/README.md @@ -4,7 +4,8 @@ I'm running two Kubernetes clusters, one for production and one for testing. -I prefer to use [k3s] as the Kubernetes distribution, because it's lightweight, easy to install, and full featured(see [what-have-k3s-removed-from-upstream-kubernetes] for details). +I prefer to use [k3s] as the Kubernetes distribution, because it's lightweight, easy to install, and +full featured(see [what-have-k3s-removed-from-upstream-kubernetes] for details). ## Hosts @@ -14,10 +15,10 @@ I prefer to use [k3s] as the Kubernetes distribution, because it's lightweight, 1. `k3s-prod-1-master-1` 1. `k3s-prod-1-master-2` 1. `k3s-prod-1-master-3` - 2. `k3s-prod-1-worker-1` - 2. `k3s-prod-1-worker-2` - 2. `k3s-prod-1-worker-3` -1. For testing:. + 1. `k3s-prod-1-worker-1` + 1. `k3s-prod-1-worker-2` + 1. `k3s-prod-1-worker-3` +1. For testing:. 1. `k3s-test-1-master-1` 2. `k3s-test-1-worker-1` 3. `k3s-test-1-worker-2` @@ -25,7 +26,9 @@ I prefer to use [k3s] as the Kubernetes distribution, because it's lightweight, ## Kubernetes Resources -Kubernetes resouces are deployed and managed separately through [nix-config/pulumi/k8s/](../../pulumi/k8s/). +Kubernetes resources are deployed and managed separately through +[nix-config/pulumi/k8s/](../../pulumi/k8s/). [k3s]: https://github.com/k3s-io/k3s/ -[what-have-k3s-removed-from-upstream-kubernetes]: https://github.com/k3s-io/k3s/?tab=readme-ov-file#what-have-you-removed-from-upstream-kubernetes +[what-have-k3s-removed-from-upstream-kubernetes]: + https://github.com/k3s-io/k3s/?tab=readme-ov-file#what-have-you-removed-from-upstream-kubernetes diff --git a/hosts/k8s/disko-config/README.md b/hosts/k8s/disko-config/README.md index 6defaa40..8fd2ce9e 100644 --- a/hosts/k8s/disko-config/README.md +++ b/hosts/k8s/disko-config/README.md @@ -29,5 +29,3 @@ K3S_TOKEN_FILE=./kubevirt-k3s-token USB_PATH=/run/media/ryan/NIXOS_K3S cp $K3S_TOKEN_FILE $USB_PATH ``` - - diff --git a/lib/README.md b/lib/README.md index 2df1902a..53e9d025 100644 --- a/lib/README.md +++ b/lib/README.md @@ -1,9 +1,13 @@ # Library -Some helper functions, used by `flake.nix` to reduce code duplication and make it easier to add new machines: +Some helper functions, used by `flake.nix` to reduce code duplication and make it easier to add new +machines: -1. `attrs.nix`: A set of functions to manupulate attribute sets. -1. `macosSystem.nix`: A function to generate config(attribute set) for macOS([nix-darwin](https://github.com/LnL7/nix-darwin)). +1. `attrs.nix`: A set of functions to manipulate attribute sets. +1. `macosSystem.nix`: A function to generate config(attribute set) for + macOS([nix-darwin](https://github.com/LnL7/nix-darwin)). 1. `nixosSystem.nix`: A function to generate config(attribute set) for NixOS. -1. `colmenaSystem.nix`: A function that generate config(another function) for remote deployment using [colmena](https://github.com/zhaofengli/colmena). -1. `default.nix`: import all the above functions, and some custom useful functions, and export them as a single attribute set. +1. `colmenaSystem.nix`: A function that generate config(another function) for remote deployment + using [colmena](https://github.com/zhaofengli/colmena). +1. `default.nix`: import all the above functions, and some custom useful functions, and export them + as a single attribute set. diff --git a/modules/README.md b/modules/README.md index e00a13c2..fc13a0b6 100644 --- a/modules/README.md +++ b/modules/README.md @@ -3,4 +3,3 @@ 1. `darwin`: macOS-specific configuration. 2. `nixos`: NixOS-specific configuration. 3. `base.nix`: Common configuration for both NixOS and Nix-Darwin. - diff --git a/modules/darwin/README.md b/modules/darwin/README.md index 3b8539f2..c2d823c6 100644 --- a/modules/darwin/README.md +++ b/modules/darwin/README.md @@ -2,4 +2,5 @@ This directory contains the modules for [Nix-Darwin](https://github.com/LnL7/nix-darwin). -See [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter) for a more detailed explanation. +See [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter) for a more +detailed explanation. diff --git a/modules/nixos/desktop/remote-desktop/README.md b/modules/nixos/desktop/remote-desktop/README.md index 2eef9997..e8330dd9 100644 --- a/modules/nixos/desktop/remote-desktop/README.md +++ b/modules/nixos/desktop/remote-desktop/README.md @@ -1,10 +1,13 @@ # Remote Desktop -1. **X11**: We have `xrdp` & `ssh -x` for remote desktop access, which works well for most use cases. +1. **X11**: We have `xrdp` & `ssh -x` for remote desktop access, which works well for most use + cases. 2. **Wayland**: (not tested) - 1. `waypipe`: similar to `ssh -X`, transfer wayland data over a ssh connection. - 2. [rustdesk](https://github.com/rustdesk/rustdesk): a remote desktop client/server written in rust. - 1. confirmed broken currently: - 3. [sunshine server](https://github.com/LizardByte/Sunshine) + [moonlight client](https://github.com/moonlight-stream): It's designed for game streaming, but it can be used for remote desktop as well. - 1. broken currently: - +3. `waypipe`: similar to `ssh -X`, transfer wayland data over a ssh connection. +4. [rustdesk](https://github.com/rustdesk/rustdesk): a remote desktop client/server written in rust. +5. confirmed broken currently: + +6. [sunshine server](https://github.com/LizardByte/Sunshine) + + [moonlight client](https://github.com/moonlight-stream): It's designed for game streaming, but it + can be used for remote desktop as well. +7. broken currently: diff --git a/nixos-installer/README.md b/nixos-installer/README.md index 717e4979..ab8bf69f 100644 --- a/nixos-installer/README.md +++ b/nixos-installer/README.md @@ -1,12 +1,16 @@ # Nix Environment Setup for Host: Idols - Ai -> :red_circle: **IMPORTANT**: **Once again, you should NOT deploy this flake directly on your machine! Please write your own configuration from scratch, and use my configuration and documentation for reference only.** +> :red_circle: **IMPORTANT**: **Once again, you should NOT deploy this flake directly on your +> machine! Please write your own configuration from scratch, and use my configuration and +> documentation for reference only.** -This flake prepares a Nix environment for setting my desktop [/hosts/idols_ai](/hosts/idols_ai/)(in main flake) up on a new machine. +This flake prepares a Nix environment for setting my desktop [/hosts/idols_ai](/hosts/idols_ai/)(in +main flake) up on a new machine. Other docs: -- README for [/hosts/12kingdoms_shoukei](/hosts/12kingdoms_shoukei): [./README.shoukei.md](./README.shoukei.md) +- README for [/hosts/12kingdoms_shoukei](/hosts/12kingdoms_shoukei): + [./README.shoukei.md](./README.shoukei.md) TODOs: @@ -14,11 +18,13 @@ TODOs: ## Why an extra flake is needed? -The configuration of the main flake, [/flake.nix](/flake.nix), is heavy, and it takes time to debug & deploy. -This simplified flake is tiny and can be deployed very quickly, it helps me to: +The configuration of the main flake, [/flake.nix](/flake.nix), is heavy, and it takes time to debug +& deploy. This simplified flake is tiny and can be deployed very quickly, it helps me to: -1. Adjust & verify my `hardware-configuration.nix` modification quickly before deploying the main flake. -2. Test some new filesystem related features on a NixOS virtual machine, such as impermanence, Secure Boot, TPM2, Encryption, etc. +1. Adjust & verify my `hardware-configuration.nix` modification quickly before deploying the main + flake. +2. Test some new filesystem related features on a NixOS virtual machine, such as impermanence, + Secure Boot, TPM2, Encryption, etc. ## Steps to Deploying this flake @@ -34,13 +40,14 @@ First, create a USB install medium from NixOS's official ISO image and boot from > [Frequently asked questions (FAQ) - cryptsetup](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions) -Securing a root file system is where dm-crypt excels, feature and performance-wise. -An encrypted root file system protects everything on the system, it make the system a black box to the attacker. +Securing a root file system is where dm-crypt excels, feature and performance-wise. An encrypted +root file system protects everything on the system, it make the system a black box to the attacker. 1. The EFI system partition(ESP) must be left unencrypted, and is mounted at `/boot` - 1. Since the UEFI firmware can only load boot loaders from unencrypted partitions. + 1. Since the UEFI firmware can only load boot loaders from unencrypted partitions. 2. Secure Boot is enabled, everything in ESP is signed. -3. The BTRFS file system with subvolumes is used for the root partition, and the swap area is a swapfile on a dedicated BTRFS subvolume, thus the swap area is also encrypted. +3. The BTRFS file system with subvolumes is used for the root partition, and the swap area is a + swapfile on a dedicated BTRFS subvolume, thus the swap area is also encrypted. And the boot flow is: @@ -68,7 +75,7 @@ parted /dev/nvme0n1 -- mkpart ESP fat32 2MB 629MB # part-1 parted /dev/nvme0n1 -- set 1 esp on # part-1 # Create the root partition using the rest of the disk -# Format: +# Format: # mkpart [part-type name fs-type] start end parted /dev/nvme0n1 -- mkpart primary 630MB 100% # part-1 @@ -80,7 +87,7 @@ Encrypting the root partition: ```bash lsblk -# show cryptsetup's compiled in defualts +# show cryptsetup's compiled in defaults cryptsetup --help # NOTE: `cat shoukei.md | grep luks > luks.sh` to generate this script @@ -91,7 +98,7 @@ cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --hash sha512 --iter cryptsetup luksDump /dev/nvme0n1p2 # open(unlock) the device with the passphrase you just set -cryptsetup luksOpen /dev/nvme0n1p2 crypted-nixos +cryptsetup luksOpen /dev/nvme0n1p2 encrypted-nixos # show disk status lsblk @@ -103,7 +110,7 @@ Formatting the root partition: # NOTE: `cat shoukei.md | grep create-btrfs > btrfs.sh` to generate this script mkfs.fat -F 32 -n ESP /dev/nvme0n1p1 # create-btrfs # format the root partition with btrfs and label it -mkfs.btrfs -L crypted-nixos /dev/mapper/crypted-nixos # create-btrfs +mkfs.btrfs -L encrypted-nixos /dev/mapper/crypted-nixos # create-btrfs # mount the root partition and create subvolumes mount /dev/mapper/crypted-nixos /mnt # create-btrfs @@ -117,7 +124,7 @@ umount /mnt # create-btrfs # NOTE: `cat shoukei.md | grep mount-1 > mount-1.sh` to generate this script # Remount the root partition with the subvolumes you just created -# +# # Enable zstd compression to: # 1. Reduce the read/write operations, which helps to: # 1. Extend the life of the SSD. @@ -152,10 +159,10 @@ Now, the disk status should be: ```bash # show disk status $ lsblk -nvme0n1 259:0 0 1.8T 0 disk +nvme0n1 259:0 0 1.8T 0 disk ├─nvme0n1p1 259:2 0 600M 0 part /mnt/boot -└─nvme0n1p2 259:3 0 1.8T 0 part - └─crypted-nixos 254:0 0 1.8T 0 crypt /mnt/swap +└─nvme0n1p2 259:3 0 1.8T 0 part + └─encrypted-nixos 254:0 0 1.8T 0 crypt /mnt/swap /mnt/persistent /mnt/snapshots /mnt/nix @@ -243,10 +250,10 @@ reboot And then reboot. - ## Deploying the main flake's NixOS configuration -After rebooting, we need to generate a new SSH key for the new machine, and add it to GitHub, so that the new machine can pull my private secrets repo: +After rebooting, we need to generate a new SSH key for the new machine, and add it to GitHub, so +that the new machine can pull my private secrets repo: ```bash # 1. Generate a new SSH key with a strong passphrase @@ -255,8 +262,9 @@ ssh-keygen -t ed25519 -a 256 -C "ryan@idols-ai" -f ~/.ssh/idols_ai ssh-add ~/.ssh/idols_ai ``` -Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets with the new host's system-level SSH key(`/etc/ssh/ssh_host_ed25519_key`), -so that agenix can decrypt them automatically on the new host when I deploy my NixOS configuration. +Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets +with the new host's system-level SSH key(`/etc/ssh/ssh_host_ed25519_key`), so that agenix can +decrypt them automatically on the new host when I deploy my NixOS configuration. After all these steps, we can finally deploy the main flake's NixOS configuration by: @@ -270,8 +278,10 @@ cd ~/nix-config just hypr ``` -Finally, to enable secure boot, follow the instructions in [lanzaboote - Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md) and [nix-config/ai/secure-boot.nix](https://github.com/ryan4yin/nix-config/blob/main/hosts/idols_ai/secureboot.nix) - +Finally, to enable secure boot, follow the instructions in +[lanzaboote - Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md) +and +[nix-config/ai/secure-boot.nix](https://github.com/ryan4yin/nix-config/blob/main/hosts/idols_ai/secureboot.nix) ## Change LUKS2's passphrase diff --git a/nixos-installer/README.shoukei.md b/nixos-installer/README.shoukei.md index 1ad64558..e2e7ba7a 100755 --- a/nixos-installer/README.shoukei.md +++ b/nixos-installer/README.shoukei.md @@ -1,16 +1,20 @@ # Nix Environment Setup for Host: 12Kingdoms - Shoukei -> :red_circle: **IMPORTANT**: **Once again, you should NOT deploy this flake directly on your machine! Please write your own configuration from scratch, and use my configuration and documentation for reference only.** +> :red_circle: **IMPORTANT**: **Once again, you should NOT deploy this flake directly on your +> machine! Please write your own configuration from scratch, and use my configuration and +> documentation for reference only.** > https://wiki.t2linux.org/distributions/nixos/installation/ > https://github.com/NixOS/nixos-hardware/tree/master/apple/t2 -This flake prepares a Nix environment for setting my desktop [/hosts/12kingdoms_shoukei](/hosts/12kingdoms_shoukei)(in main flake) up on a new machine. +This flake prepares a Nix environment for setting my desktop +[/hosts/12kingdoms_shoukei](/hosts/12kingdoms_shoukei)(in main flake) up on a new machine. ## Steps to Deploying -First, create a USB install medium from Apple T2's NixOS installer image: https://github.com/t2linux/nixos-t2-iso.git +First, create a USB install medium from Apple T2's NixOS installer image: +https://github.com/t2linux/nixos-t2-iso.git ### 2. Connecting to the Internet @@ -64,7 +68,7 @@ Now let's recreate the 4th partition via `fdisk`, and then encrypting the root p ```bash lsblk -# show cryptsetup's compiled in defualts +# show cryptsetup's compiled in defaults cryptsetup --help # NOTE: `cat shoukei.md | grep luks > format.sh` to generate this script @@ -75,7 +79,7 @@ cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --hash sha512 --iter cryptsetup luksDump /dev/nvme0n1p4 # open(unlock) the device with the passphrase you just set -cryptsetup luksOpen /dev/nvme0n1p4 crypted-nixos +cryptsetup luksOpen /dev/nvme0n1p4 encrypted-nixos # show disk status lsblk @@ -86,7 +90,7 @@ Formatting the root partition: ```bash # NOTE: `cat shoukei.md | egrep "create-btrfs" > create-btrfs.sh` to generate this script # format the root partition with btrfs and label it -mkfs.btrfs -L crypted-nixos /dev/mapper/crypted-nixos # create-btrfs +mkfs.btrfs -L encrypted-nixos /dev/mapper/crypted-nixos # create-btrfs # mount the root partition and create subvolumes mount /dev/mapper/crypted-nixos /mnt # create-btrfs btrfs subvolume create /mnt/@nix # create-btrfs @@ -135,7 +139,7 @@ $ lsblk nvme0n1 259:0 0 1.8T 0 disk ├─nvme0n1p1 259:2 0 600M 0 part /mnt/boot └─nvme0n1p4 259:3 0 1.8T 0 part - └─crypted-nixos 254:0 0 1.8T 0 crypt /mnt/swap + └─encrypted-nixos 254:0 0 1.8T 0 crypt /mnt/swap /mnt/persistent /mnt/snapshots /mnt/nix @@ -201,7 +205,7 @@ nixos-enter mv /etc/machine-id /persistent/etc/ mv /etc/ssh /persistent/etc/ -# delte the generated configuration after editing +# delete the generated configuration after editing rm -f /mnt/etc/nixos rm ~/nix-config/hosts/idols_ai/hardware-configuration-new.nix @@ -226,7 +230,8 @@ And then reboot. ## Deploying the main flake's NixOS configuration -After rebooting, we need to generate a new SSH key for the new machine, and add it to GitHub, so that the new machine can pull my private secrets repo: +After rebooting, we need to generate a new SSH key for the new machine, and add it to GitHub, so +that the new machine can pull my private secrets repo: ```bash # 1. Generate a new SSH key with a strong passphrase @@ -235,8 +240,9 @@ ssh-keygen -t ed25519 -a 256 -C "ryan@idols-ai" -f ~/.ssh/shoukei ssh-add ~/.ssh/shoukei ``` -Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets with the new host's system-level SSH key(`/etc/ssh/ssh_host_ed25519_key`), -so that agenix can decrypt them automatically on the new host when I deploy my NixOS configuration. +Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets +with the new host's system-level SSH key(`/etc/ssh/ssh_host_ed25519_key`), so that agenix can +decrypt them automatically on the new host when I deploy my NixOS configuration. After all these steps, we can finally deploy the main flake's NixOS configuration by: @@ -250,4 +256,7 @@ cd ~/nix-config just s-hypr ``` -Finally, to enable secure boot, follow the instructions in [lanzaboote - Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md) and [nix-config/ai/secure-boot.nix](https://github.com/ryan4yin/nix-config/blob/main/hosts/idols_ai/secureboot.nix) +Finally, to enable secure boot, follow the instructions in +[lanzaboote - Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md) +and +[nix-config/ai/secure-boot.nix](https://github.com/ryan4yin/nix-config/blob/main/hosts/idols_ai/secureboot.nix) diff --git a/outputs/README.md b/outputs/README.md index 21f1792f..d0012fba 100644 --- a/outputs/README.md +++ b/outputs/README.md @@ -7,18 +7,18 @@ There is no need to do this when you have a small number of machines. But when you have a large number of machines, it is necessary to manage them in a fine-grained way, otherwise, it will be difficult to manage and maintain them. -The number of my machines has grown to more than 20, -and the increase in scale has shown signs of getting out of control of complexity, -so it is a natural and reasonable choice to use this fine-grained architecture to manage. +The number of my machines has grown to more than 20, and the increase in scale has shown signs of +getting out of control of complexity, so it is a natural and reasonable choice to use this +fine-grained architecture to manage. ## Tests -Testing is not necessary when your configuration is not complex, -but with the increase in the number and configuration of your machines, testing becomes more and more important. +Testing is not necessary when your configuration is not complex, but with the increase in the number +and configuration of your machines, testing becomes more and more important. -We have two types of tests: eval tests and nixos tests, -both of which can help us detect many obscure errors early, -so as to avoid testing directly in the real world, and to avoid failures in personal computers and even corporate online environments. +We have two types of tests: eval tests and nixos tests, both of which can help us detect many +obscure errors early, so as to avoid testing directly in the real world, and to avoid failures in +personal computers and even corporate online environments. Related projects & docs: @@ -30,9 +30,9 @@ Related projects & docs: > TODO: More Tests! -Eval Tests evaluate the expressions and compare the results with the expected results. -It runs fast, but it doesn't build a real machine. -We use eval tests to ensure that some attributes are correctly set for each NixOS host(not Darwin). +Eval Tests evaluate the expressions and compare the results with the expected results. It runs fast, +but it doesn't build a real machine. We use eval tests to ensure that some attributes are correctly +set for each NixOS host(not Darwin). How to run all the eval tests: @@ -45,12 +45,15 @@ nix eval .#evalTests --show-trace --print-build-logs --verbose > WIP: not working yet NixOS Tests builds and starts virtual machines using our NixOS configuration and run tests on them. -Comparing to eval tests, it runs slow, but it builds a real machine, and we can test the whole system actually works as expected. +Comparing to eval tests, it runs slow, but it builds a real machine, and we can test the whole +system actually works as expected. Problems: -- [ ] We need a private cache server, so that our NixOS tests do not need to build some custom packages every time we run the tests. -- [ ] Cannot test the whole host, because my host relies on its unique ssh host key to decrypt its agenix secrets. +- [ ] We need a private cache server, so that our NixOS tests do not need to build some custom + packages every time we run the tests. +- [ ] Cannot test the whole host, because my host relies on its unique ssh host key to decrypt its + agenix secrets. - [ ] Maybe it's better to test every service separately, not the whole host? How to run NixOS tests for every host: diff --git a/outputs/default.nix b/outputs/default.nix index 79037de4..e2ac8c33 100644 --- a/outputs/default.nix +++ b/outputs/default.nix @@ -104,7 +104,7 @@ in { settings = { typos = { write = true; # Automatically fix typos - ignored-words = []; + configPath = "../.typos.toml"; }; prettier = { write = true; # Automatically format files diff --git a/overlays/README.md b/overlays/README.md index dec7ff7d..303f5150 100644 --- a/overlays/README.md +++ b/overlays/README.md @@ -2,8 +2,10 @@ Overlays for both NixOS and Nix-Darwin. -If you don't know much about overlays, it is recommended to learn the function and usage of overlays through [Overlays - NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/nixpkgs/overlays). - -1. `default.nix`: the entrypoint of overlays, it execute and import all overlay files in the current directory with the given args. -2. `fcitx5`: fcitx5's overlay, add my customized Chinese input method - [小鹤音形输入法](https://flypy.com/) +If you don't know much about overlays, it is recommended to learn the function and usage of overlays +through [Overlays - NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/nixpkgs/overlays). +1. `default.nix`: the entrypoint of overlays, it execute and import all overlay files in the current + directory with the given args. +2. `fcitx5`: fcitx5's overlay, add my customized Chinese input method - + [小鹤音形输入法](https://flypy.com/) diff --git a/overlays/fcitx5/README.md b/overlays/fcitx5/README.md index 7d099fbd..ff454927 100644 --- a/overlays/fcitx5/README.md +++ b/overlays/fcitx5/README.md @@ -4,18 +4,22 @@ Useful for Linux(fcitx5-rime) & macOS(squirrel). ## Linux(fcitx5-rime) -1. pay attention to the `rm -rf .local/share/fcitx5/rime/`, which may contains some auto generated rime config files, which may cause flypy not the default scheme for rime -2. manage `~/.config/fcitx5/profile` in ../home/hyprland/default.nix, which hardcode rime as the default input method, so you do not need to use fcitx-configtool to set rime as the default input method. -3. fcitx5-rime still cannot use on vscode & chrome now... need more time to figure out why and resolve it. - +1. pay attention to the `rm -rf .local/share/fcitx5/rime/`, which may contains some auto generated + rime config files, which may cause flypy not the default scheme for rime +2. manage `~/.config/fcitx5/profile` in ../home/hyprland/default.nix, which hardcode rime as the + default input method, so you do not need to use fcitx-configtool to set rime as the default input + method. +3. fcitx5-rime still cannot use on vscode & chrome now... need more time to figure out why and + resolve it. ## macOS(squirrel) -1. pay attention to the `rm -rf ~/Library/Rime/`, which may contains some auto generated rime config files. +1. pay attention to the `rm -rf ~/Library/Rime/`, which may contains some auto generated rime config + files. ## Docs about fcitx5 - [Fcitx5 - Arch Linux Wiki](https://wiki.archlinux.org/title/Fcitx5) - [Fcitx5 - Official Wiki](https://fcitx-im.org/wiki/Fcitx_5/zh-cn) -- [disscussion about using fcitx5 on hyprland](https://github.com/hyprwm/Hyprland/discussions/421) +- [discussion about using fcitx5 on hyprland](https://github.com/hyprwm/Hyprland/discussions/421) - [hyprland issue about fcitx5](https://github.com/hyprwm/Hyprland/discussions/421) diff --git a/overlays/fcitx5/rime-data-flypy/share/rime-data/default.custom.yaml b/overlays/fcitx5/rime-data-flypy/share/rime-data/default.custom.yaml index 0eb61d5f..44e23bd4 100644 --- a/overlays/fcitx5/rime-data-flypy/share/rime-data/default.custom.yaml +++ b/overlays/fcitx5/rime-data-flypy/share/rime-data/default.custom.yaml @@ -1,41 +1,38 @@ -customization: - distribution_code_name: Squirrel - distribution_version: 2019-06-23 - rime_version: 1.5.3 -patch: - schema_list: - - schema: flypy # 添加小鹤音形 - -# -# 可用的按键有 Caps_Lock, Shift_L, Shift_R, Control_L, control_R -# Mac 系统上的鼠须管不能区分左、右,因此只有对 Shift_L, Control_L 的设定起作用 -# -# 已输入编码时按切换键,可以进一步设定输入法中西文切换的形式 -# 可选的临时切换策略有三: -# inline_ascii 在输入法的临时西文编辑区内输入字母、数字、符号、空格等,回车上屏后自动复位到中文 -# commit_text 已输入的候选文字上屏并切换至西文输入模式 -# commit_code 已输入的编码字符上屏并切换至西文输入模式 -# 设为 noop, 屏蔽该切换键 -# -# 如果要把Caps Lock 设为只改变字母的大小写而不做中西文切换,可将 Caps_Lock 对应的切换方式设为 noop -# 如果要以Caps Lock 切换到西文模式,默认输出小写字母,请置 ascii_composer/good_old_caps_lock: false -# 如果要以Caps Lock 切换到西文模式,默认输出大写字母,请置 ascii_composer/good_old_caps_lock: true - - ascii_composer/good_old_caps_lock: true - ascii_composer/switch_key: - Caps_Lock: noop - Shift_L: commit_code - Shift_R: noop - Control_L: noop - Control_R: noop - - key_binder/bindings: - - when: paging - accept: bracketleft - send: Page_Up - - when: has_menu - accept: bracketright - send: Page_Down - - - +customization: + distribution_code_name: Squirrel + distribution_version: 2019-06-23 + rime_version: 1.5.3 +patch: + schema_list: + - schema: flypy # 添加小鹤音形 + + # + # 可用的按键有 Caps_Lock, Shift_L, Shift_R, Control_L, control_R + # Mac 系统上的鼠须管不能区分左、右,因此只有对 Shift_L, Control_L 的设定起作用 + # + # 已输入编码时按切换键,可以进一步设定输入法中西文切换的形式 + # 可选的临时切换策略有三: + # inline_ascii 在输入法的临时西文编辑区内输入字母、数字、符号、空格等,回车上屏后自动复位到中文 + # commit_text 已输入的候选文字上屏并切换至西文输入模式 + # commit_code 已输入的编码字符上屏并切换至西文输入模式 + # 设为 noop, 屏蔽该切换键 + # + # 如果要把Caps Lock 设为只改变字母的大小写而不做中西文切换,可将 Caps_Lock 对应的切换方式设为 noop + # 如果要以Caps Lock 切换到西文模式,默认输出小写字母,请置 ascii_composer/good_old_caps_lock: false + # 如果要以Caps Lock 切换到西文模式,默认输出大写字母,请置 ascii_composer/good_old_caps_lock: true + + ascii_composer/good_old_caps_lock: true + ascii_composer/switch_key: + Caps_Lock: noop + Shift_L: commit_code + Shift_R: noop + Control_L: noop + Control_R: noop + + key_binder/bindings: + - when: paging + accept: bracketleft + send: Page_Up + - when: has_menu + accept: bracketright + send: Page_Down diff --git a/overlays/fcitx5/rime-data-flypy/share/rime-data/default.yaml b/overlays/fcitx5/rime-data-flypy/share/rime-data/default.yaml index 72ba43a2..846bdeb3 100644 --- a/overlays/fcitx5/rime-data-flypy/share/rime-data/default.yaml +++ b/overlays/fcitx5/rime-data-flypy/share/rime-data/default.yaml @@ -24,74 +24,73 @@ menu: page_size: 5 punctuator: - full_shape: # replace full_shape with half_shape - ',' : { commit: , } - '.' : { commit: 。 } - '<' : [ 《, 〈, «, ‹ ] - '>' : [ 》, 〉, », › ] - '/' : { commit: 、 } - '?' : { commit: ? } - ';' : { commit: ; } - ':' : { commit: : } - '''' : { pair: [ '‘', '’' ] } - '"' : { pair: [ '“', '”' ] } - '\' : { commit: 、 } - '|' : '|' - '`' : '`' - '~' : { commit: ~ } - '!' : { commit: ! } - '@' : '@' - '#' : '#' - '%' : { commit: '%' } - '$' : { commit: "$" } - '^' : { commit: …… } - '&' : '&' - '*' : { commit: '*' } - '(' : ( - ')' : ) - '-' : '-' - '_' : —— - '+' : '+' - '=' : '=' - '[' : [ 「, 【, 〔, [ ] - ']' : [ 」, 】, 〕, ] ] - '{' : [ 『, 〖, { ] - '}' : [ 』, 〗, } ] - + full_shape: # replace full_shape with half_shape + ",": { commit: , } + ".": { commit: 。 } + "<": [《, 〈, «, ‹] + ">": [》, 〉, », ›] + "/": { commit: 、 } + "?": { commit: ? } + ";": { commit: ; } + ":": { commit: : } + "'": { pair: ["‘", "’"] } + '"': { pair: ["“", "”"] } + '\': { commit: 、 } + "|": "|" + "`": "`" + "~": { commit: ~ } + "!": { commit: ! } + "@": "@" + "#": "#" + "%": { commit: "%" } + "$": { commit: "$" } + "^": { commit: …… } + "&": "&" + "*": { commit: "*" } + "(": ( + ")": ) + "-": "-" + "_": —— + "+": "+" + "=": "=" + "[": [「, 【, 〔, [] + "]": [」, 】, 〕, ]] + "{": [『, 〖, {] + "}": [』, 〗, }] half_shape: - ',' : { commit: , } - '.' : { commit: 。 } - '<' : [ 《, 〈, «, ‹ ] - '>' : [ 》, 〉, », › ] - '/' : { commit: 、 } - '?' : { commit: ? } - ';' : { commit: ; } - ':' : { commit: : } - '''' : { pair: [ '‘', '’' ] } - '"' : { pair: [ '“', '”' ] } - '\' : { commit: 、 } - '|' : '|' - '`' : '`' - '~' : { commit: ~ } - '!' : { commit: ! } - '@' : '@' - '#' : '#' - '%' : { commit: '%' } - '$' : { commit: "$" } - '^' : { commit: …… } - '&' : '&' - '*' : { commit: '*' } - '(' : ( - ')' : ) - '-' : '-' - '_' : —— - '+' : '+' - '=' : '=' - '[' : [ 「, 【, 〔, [ ] - ']' : [ 」, 】, 〕, ] ] - '{' : [ 『, 〖, { ] - '}' : [ 』, 〗, } ] + ",": { commit: , } + ".": { commit: 。 } + "<": [《, 〈, «, ‹] + ">": [》, 〉, », ›] + "/": { commit: 、 } + "?": { commit: ? } + ";": { commit: ; } + ":": { commit: : } + "'": { pair: ["‘", "’"] } + '"': { pair: ["“", "”"] } + '\': { commit: 、 } + "|": "|" + "`": "`" + "~": { commit: ~ } + "!": { commit: ! } + "@": "@" + "#": "#" + "%": { commit: "%" } + "$": { commit: "$" } + "^": { commit: …… } + "&": "&" + "*": { commit: "*" } + "(": ( + ")": ) + "-": "-" + "_": —— + "+": "+" + "=": "=" + "[": [「, 【, 〔, [] + "]": [」, 】, 〕, ]] + "{": [『, 〖, {] + "}": [』, 〗, }] key_binder: bindings: diff --git a/overlays/fcitx5/rime-data-flypy/share/rime-data/flypy.schema.yaml b/overlays/fcitx5/rime-data-flypy/share/rime-data/flypy.schema.yaml index e8d65da5..c1356679 100644 --- a/overlays/fcitx5/rime-data-flypy/share/rime-data/flypy.schema.yaml +++ b/overlays/fcitx5/rime-data-flypy/share/rime-data/flypy.schema.yaml @@ -16,14 +16,14 @@ punctuator: switches: - name: ascii_mode reset: 0 - # states: [ 中文, 英文 ] + # states: [ 中文, 英文 ] - name: full_shape - # states: [ 半角, 全角 ] + # states: [ 半角, 全角 ] - name: simplification - # states: [ 简, 繁 ] + # states: [ 简, 繁 ] reset: 0 - name: ascii_punct - # states: [ 。,, ., ] + # states: [ 。,, ., ] reset: 0 engine: @@ -61,11 +61,11 @@ engine: speller: alphabet: "abcdefghijklmnopqrstuvwxyz;'" - initials: ';abcdefghijklmnopqrstuvwxyz' + initials: ";abcdefghijklmnopqrstuvwxyz" finals: "'" #delimiter: " '" max_code_length: 4 - auto_select: true #顶字上屏 + auto_select: true #顶字上屏 auto_select_pattern: ^;.$|^\w{4}$ auto_clear: max_length #manual|auto|max_length 空码按下一键确认清屏|空码自动清|达到最长码时后码顶上清屏 @@ -77,13 +77,12 @@ translator: enable_user_dict: false disable_user_dict_for_patterns: - "^z.*$" - history: - input: ;f - size: 1 #重复前几次上屏 - initial_quality: 1 #首选 - + input: ;f + size: 1 #重复前几次上屏 + initial_quality: 1 #首选 + simplification: opencc_config: s2tw.json option_name: simplification @@ -96,7 +95,7 @@ custom_phraseVD: enable_sentence: false enable_completion: false initial_quality: 0 #用户词和系统词重码 置顶 - + custom_phraseXT: dictionary: "" user_dict: flypy_sys @@ -112,7 +111,7 @@ custom_phraseYH: enable_sentence: false enable_completion: false initial_quality: -1 #用户词和系统词重码居后 - + custom_phraseQMZ: dictionary: "" user_dict: flypy_full @@ -124,27 +123,26 @@ custom_phraseQMZ: reverse_lookup: dictionary: flypydz comment_format: - # - xform/^/〔/ - # - xform/$/〕/ + # - xform/^/〔/ + # - xform/$/〕/ - xform/ / / - key_binder: import_preset: default #方案切换相关 bindings: - - {accept: bracketleft, send: Page_Up, when: paging} # [上翻页 - - {accept: bracketright, send: Page_Down, when: has_menu} # ]下翻页 - - {accept: comma, send: comma, when: paging} #注销逗号翻页 - - {accept: period, send: period, when: has_menu} #注销句号翻页 - - {accept: semicolon, send: 2, when: has_menu} #分号次选 - # - {accept: Release+semicolon, send: semicolon, when: has_menu} #如启用此行,则分号引导符号功能无效 - - {accept: Release+period, send: period, when: composing} #句号顶屏 - - {accept: Release+comma, send: comma, when: composing} #逗号顶屏 - - {accept: "Tab", send: Escape, when: composing} - - {accept: "Shift_R", send: Escape, when: composing} - - {accept: "Shift+space", toggle: full_shape, when: always} #切换全半角 - - {accept: "Control+period", toggle: ascii_punct, when: always} #切换中英标点 - - {accept: "Control+j", toggle: simplification, when: always} #切换简繁 + - { accept: bracketleft, send: Page_Up, when: paging } # [上翻页 + - { accept: bracketright, send: Page_Down, when: has_menu } # ]下翻页 + - { accept: comma, send: comma, when: paging } #注销逗号翻页 + - { accept: period, send: period, when: has_menu } #注销句号翻页 + - { accept: semicolon, send: 2, when: has_menu } #分号次选 + # - {accept: Release+semicolon, send: semicolon, when: has_menu} #如启用此行,则分号引导符号功能无效 + - { accept: Release+period, send: period, when: composing } #句号顶屏 + - { accept: Release+comma, send: comma, when: composing } #逗号顶屏 + - { accept: "Tab", send: Escape, when: composing } + - { accept: "Shift_R", send: Escape, when: composing } + - { accept: "Shift+space", toggle: full_shape, when: always } #切换全半角 + - { accept: "Control+period", toggle: ascii_punct, when: always } #切换中英标点 + - { accept: "Control+j", toggle: simplification, when: always } #切换简繁 recognizer: import_preset: default @@ -157,7 +155,6 @@ recognizer: menu: page_size: 5 #候选项数 - + style: horizontal: true #竖排为false - \ No newline at end of file diff --git a/overlays/fcitx5/rime-data-flypy/share/rime-data/squirrel.custom.yaml b/overlays/fcitx5/rime-data-flypy/share/rime-data/squirrel.custom.yaml index 21f0412d..3deac1ee 100644 --- a/overlays/fcitx5/rime-data-flypy/share/rime-data/squirrel.custom.yaml +++ b/overlays/fcitx5/rime-data-flypy/share/rime-data/squirrel.custom.yaml @@ -1,39 +1,38 @@ -customization: - distribution_code_name: squirrel - distribution_version: 0.14.0 - generator: "squirrel::UIStyleSettings" - modified_time: "2019-06-23" - rime_version: 1.5.3 -patch: - "preset_color_schemes/metro": - author: "flypy.com" - back_color: 0xffffff # 候选条背景色 - border_color_width: 1 - #border_color: 0xe89f00 # 边框色 - #preedit_back_color: 0xf0403516 #新增,未知其意 - border_height: 8 # 窗口边界高度,大于圆角半径才生效 - border_width: 8 # 窗口边界宽度,大于圆角半径才生效 - candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。 - corner_radius: 6 # 窗口圆角半径 - #hilited_corner_radius: 6 # 高亮圆角 - hilited_text_color: 0x000000 # 编码高亮 - hilited_back_color: 0xffffff # 编码背景高亮 - hilited_candidate_label_color: 0xeeeeee # 首选编号色 - hilited_candidate_text_color: 0xffffff # 首选文字色 - hilited_candidate_back_color: 0xe89f00 # 首选背景色 - hilited_comment_text_color: 0xcccccc # 首选提示字母色 - label_color: 0x555555 # 次选编号色 - candidate_text_color: 0x000000 # 次选文字色 - candidate_back_color: 0xffffff # 次选背景色 - comment_text_color: 0x555555 # 次选提示字母色 - horizontal: true # 候选窗横向显示 - font_point: 18 # 候选窗文字字号 - label_font_point: 14 # 候选窗编号字号 - inline_preedit: true # 开启嵌入编码 - name: "metro" - text_color: 0x333333 # 编码行文字颜色,24位色值,16进制,BGR顺序 - "style/line_spacing": 12 # 候选词的行间距 - "style/color_scheme": metro - "style/display_tray_icon": false - "style/text_orientation": horizontal # horizontal | vertical - \ No newline at end of file +customization: + distribution_code_name: squirrel + distribution_version: 0.14.0 + generator: "squirrel::UIStyleSettings" + modified_time: "2019-06-23" + rime_version: 1.5.3 +patch: + "preset_color_schemes/metro": + author: "flypy.com" + back_color: 0xffffff # 候选条背景色 + border_color_width: 1 + #border_color: 0xe89f00 # 边框色 + #preedit_back_color: 0xf0403516 #新增,未知其意 + border_height: 8 # 窗口边界高度,大于圆角半径才生效 + border_width: 8 # 窗口边界宽度,大于圆角半径才生效 + candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。 + corner_radius: 6 # 窗口圆角半径 + #hilited_corner_radius: 6 # 高亮圆角 + hilited_text_color: 0x000000 # 编码高亮 + hilited_back_color: 0xffffff # 编码背景高亮 + hilited_candidate_label_color: 0xeeeeee # 首选编号色 + hilited_candidate_text_color: 0xffffff # 首选文字色 + hilited_candidate_back_color: 0xe89f00 # 首选背景色 + hilited_comment_text_color: 0xcccccc # 首选提示字母色 + label_color: 0x555555 # 次选编号色 + candidate_text_color: 0x000000 # 次选文字色 + candidate_back_color: 0xffffff # 次选背景色 + comment_text_color: 0x555555 # 次选提示字母色 + horizontal: true # 候选窗横向显示 + font_point: 18 # 候选窗文字字号 + label_font_point: 14 # 候选窗编号字号 + inline_preedit: true # 开启嵌入编码 + name: "metro" + text_color: 0x333333 # 编码行文字颜色,24位色值,16进制,BGR顺序 + "style/line_spacing": 12 # 候选词的行间距 + "style/color_scheme": metro + "style/display_tray_icon": false + "style/text_orientation": horizontal # horizontal | vertical diff --git a/overlays/fcitx5/rime-data-flypy/share/rime-data/squirrel.yaml b/overlays/fcitx5/rime-data-flypy/share/rime-data/squirrel.yaml index 5e3a2fc8..28d3b79e 100644 --- a/overlays/fcitx5/rime-data-flypy/share/rime-data/squirrel.yaml +++ b/overlays/fcitx5/rime-data-flypy/share/rime-data/squirrel.yaml @@ -1,12 +1,12 @@ # Squirrel settings # encoding: utf-8 -config_version: '0.37' +config_version: "0.37" us_keyboard_layout: true # for veteran chord-typist -chord_duration: 0.1 # seconds +chord_duration: 0.1 # seconds # options: always | never | appropriate show_notifications_when: appropriate @@ -22,7 +22,7 @@ style: # NOTE: do not set a default value for `candidate_list_layout`, in order to # keep the deprecated `horizontal` option working for existing users. #candidate_list_layout: stacked # stacked | linear - text_orientation: horizontal # horizontal | vertical + text_orientation: horizontal # horizontal | vertical inline_preedit: true corner_radius: 10 @@ -38,7 +38,7 @@ style: # adjust the base line of vertical text #base_offset: 6 - font_face: 'Lucida Grande' + font_face: "Lucida Grande" font_point: 21 #label_font_face: 'Lucida Grande' label_font_point: 18 @@ -117,7 +117,7 @@ preset_color_schemes: hilited_text_color: 0xffcf9a hilited_back_color: 0x222222 hilited_candidate_text_color: 0x92f6da - hilited_candidate_back_color: 0x10000000 # 0x333333 + hilited_candidate_back_color: 0x10000000 # 0x333333 comment_text_color: 0x606cff psionics: @@ -203,7 +203,7 @@ preset_color_schemes: name: 简约白/Clean White author: Chongyu Zhu , based on 搜狗「简约白」 horizontal: true - candidate_format: '%c %@' + candidate_format: "%c %@" corner_radius: 6 border_height: 6 border_width: 6 @@ -222,72 +222,72 @@ preset_color_schemes: apathy: name: 冷漠/Apathy author: LIANG Hai - horizontal: true # 水平排列 + horizontal: true # 水平排列 inline_preedit: true #单行显示,false双行显示 - candidate_format: "%c\u2005%@\u2005" # 编号 %c 和候选词 %@ 前后的空间 - corner_radius: 5 #候选条圆角 + candidate_format: "%c\u2005%@\u2005" # 编号 %c 和候选词 %@ 前后的空间 + corner_radius: 5 #候选条圆角 border_height: 0 border_width: 0 - back_color: 0xFFFFFF #候选条背景色 - font_face: "PingFangSC-Regular,HanaMinB" #候选词字体 - font_point: 16 #候选字词大小 - text_color: 0x424242 #高亮选中词颜色 - label_font_face: "STHeitiSC-Light" #候选词编号字体 - label_font_point: 12 #候选编号大小 - hilited_candidate_text_color: 0xEE6E00 #候选文字颜色 - hilited_candidate_back_color: 0xFFF0E4 #候选文字背景色 - comment_text_color: 0x999999 #拼音等提示文字颜色 + back_color: 0xFFFFFF #候选条背景色 + font_face: "PingFangSC-Regular,HanaMinB" #候选词字体 + font_point: 16 #候选字词大小 + text_color: 0x424242 #高亮选中词颜色 + label_font_face: "STHeitiSC-Light" #候选词编号字体 + label_font_point: 12 #候选编号大小 + hilited_candidate_text_color: 0xEE6E00 #候选文字颜色 + hilited_candidate_back_color: 0xFFF0E4 #候选文字背景色 + comment_text_color: 0x999999 #拼音等提示文字颜色 dust: name: 浮尘/Dust author: Superoutman - horizontal: true # 水平排列 + horizontal: true # 水平排列 inline_preedit: true #单行显示,false双行显示 - candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。 - corner_radius: 2 #候选条圆角 - border_height: 3 # 窗口边界高度,大于圆角半径才生效 - border_width: 8 # 窗口边界宽度,大于圆角半径才生效 - back_color: 0xeeffffff #候选条背景色 - border_color: 0xE0B693 # 边框色 - font_face: "HYQiHei-55S Book,HanaMinA Regular" #候选词字体 - font_point: 14 #候选字词大小 - label_font_face: "SimHei" #候选词编号字体 - label_font_point: 10 #候选编号大小 - label_color: 0xcbcbcb # 预选栏编号颜色 - candidate_text_color: 0x555555 # 预选项文字颜色 - text_color: 0x424242 # 拼音行文字颜色,24位色值,16进制,BGR顺序 - comment_text_color: 0x999999 # 拼音等提示文字颜色 - hilited_text_color: 0x9e9e9e # 高亮拼音 (需要开启内嵌编码) - hilited_candidate_text_color: 0x000000 # 第一候选项文字颜色 - hilited_candidate_back_color: 0xfff0e4 # 第一候选项背景背景色 - hilited_candidate_label_color: 0x555555 # 第一候选项编号颜色 - hilited_comment_text_color: 0x9e9e9e # 注解文字高亮 + candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。 + corner_radius: 2 #候选条圆角 + border_height: 3 # 窗口边界高度,大于圆角半径才生效 + border_width: 8 # 窗口边界宽度,大于圆角半径才生效 + back_color: 0xeeffffff #候选条背景色 + border_color: 0xE0B693 # 边框色 + font_face: "HYQiHei-55S Book,HanaMinA Regular" #候选词字体 + font_point: 14 #候选字词大小 + label_font_face: "SimHei" #候选词编号字体 + label_font_point: 10 #候选编号大小 + label_color: 0xcbcbcb # 预选栏编号颜色 + candidate_text_color: 0x555555 # 预选项文字颜色 + text_color: 0x424242 # 拼音行文字颜色,24位色值,16进制,BGR顺序 + comment_text_color: 0x999999 # 拼音等提示文字颜色 + hilited_text_color: 0x9e9e9e # 高亮拼音 (需要开启内嵌编码) + hilited_candidate_text_color: 0x000000 # 第一候选项文字颜色 + hilited_candidate_back_color: 0xfff0e4 # 第一候选项背景背景色 + hilited_candidate_label_color: 0x555555 # 第一候选项编号颜色 + hilited_comment_text_color: 0x9e9e9e # 注解文字高亮 mojave_dark: name: 沙漠夜/Mojave Dark author: xiehuc - horizontal: true # 水平排列 - inline_preedit: true # 单行显示,false双行显示 - candidate_format: "%c\u2005%@" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。 - corner_radius: 5 # 候选条圆角 - hilited_corner_radius: 3 # 高亮圆角 - border_height: 6 # 窗口边界高度,大于圆角半径才生效 - border_width: 6 # 窗口边界宽度,大于圆角半径才生效 - font_face: "PingFangSC" # 候选词字体 - font_point: 16 # 候选字词大小 - label_font_point: 14 # 候选编号大小 + horizontal: true # 水平排列 + inline_preedit: true # 单行显示,false双行显示 + candidate_format: "%c\u2005%@" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。 + corner_radius: 5 # 候选条圆角 + hilited_corner_radius: 3 # 高亮圆角 + border_height: 6 # 窗口边界高度,大于圆角半径才生效 + border_width: 6 # 窗口边界宽度,大于圆角半径才生效 + font_face: "PingFangSC" # 候选词字体 + font_point: 16 # 候选字词大小 + label_font_point: 14 # 候选编号大小 - text_color: 0xdedddd # 拼音行文字颜色,24位色值,16进制,BGR顺序 - back_color: 0x252320 # 候选条背景色 - label_color: 0x888785 # 预选栏编号颜色 - border_color: 0x020202 # 边框色 - candidate_text_color: 0xdedddd # 预选项文字颜色 - hilited_text_color: 0xdedddd # 高亮拼音 (需要开启内嵌编码) - hilited_back_color: 0x252320 # 高亮拼音 (需要开启内嵌编码) - hilited_candidate_text_color: 0xffffff # 第一候选项文字颜色 - hilited_candidate_back_color: 0xcb5d00 # 第一候选项背景背景色 + text_color: 0xdedddd # 拼音行文字颜色,24位色值,16进制,BGR顺序 + back_color: 0x252320 # 候选条背景色 + label_color: 0x888785 # 预选栏编号颜色 + border_color: 0x020202 # 边框色 + candidate_text_color: 0xdedddd # 预选项文字颜色 + hilited_text_color: 0xdedddd # 高亮拼音 (需要开启内嵌编码) + hilited_back_color: 0x252320 # 高亮拼音 (需要开启内嵌编码) + hilited_candidate_text_color: 0xffffff # 第一候选项文字颜色 + hilited_candidate_back_color: 0xcb5d00 # 第一候选项背景背景色 hilited_candidate_label_color: 0xffffff # 第一候选项编号颜色 - comment_text_color: 0xdedddd # 拼音等提示文字颜色 + comment_text_color: 0xdedddd # 拼音等提示文字颜色 #hilited_comment_text_color: 0xdedddd # 注解文字高亮 solarized_light: @@ -342,9 +342,9 @@ app_options: ascii_mode: true no_inline: true org.vim.MacVim: - ascii_mode: true # 初始爲西文模式 - no_inline: true # 不使用行內編輯 - vim_mode: true # 退出VIM插入模式自動切換輸入法狀態 + ascii_mode: true # 初始爲西文模式 + no_inline: true # 不使用行內編輯 + vim_mode: true # 退出VIM插入模式自動切換輸入法狀態 com.apple.dt.Xcode: ascii_mode: true com.barebones.textwrangler: @@ -369,4 +369,4 @@ app_options: inline: true ru.keepcoder.Telegram: # 規避 https://github.com/rime/squirrel/issues/475 - inline: true \ No newline at end of file + inline: true diff --git a/secrets/README.md b/secrets/README.md index 59374a14..20f735da 100644 --- a/secrets/README.md +++ b/secrets/README.md @@ -1,24 +1,31 @@ # Secrets Management -> For Website/App's passwords, see [/home/base/desktop/password-store](/home/base/desktop/password-store/README.md) for more details. +> For Website/App's passwords, see +> [/home/base/desktop/password-store](/home/base/desktop/password-store/README.md) for more details. -All my secrets are safely encrypted via agenix, and stored in a separate private GitHub repository and referenced as a flake input in this flake. +All my secrets are safely encrypted via agenix, and stored in a separate private GitHub repository +and referenced as a flake input in this flake. -The encryption is done by using all my host's public keys(`/etc/ssh/ssh_host_ed25519_key`), so that they can only be decrypted on any of my configured hosts. -The host keys are generated locally on each host by openssh without passphrase, and are only readable by `root`, and will never leave the host. +The encryption is done by using all my host's public keys(`/etc/ssh/ssh_host_ed25519_key`), so that +they can only be decrypted on any of my configured hosts. The host keys are generated locally on +each host by openssh without passphrase, and are only readable by `root`, and will never leave the +host. -In this way, all secrets is still encrypted when transmitted over the network and written to `/nix/store`, -they are decrypted only when they are finally used. +In this way, all secrets is still encrypted when transmitted over the network and written to +`/nix/store`, they are decrypted only when they are finally used. -In addition, we further improve the security of secrets files by storing them in a separate private repository. +In addition, we further improve the security of secrets files by storing them in a separate private +repository. -This directory contains this README.md, and a `nixos.nix`/`darwin.nix` that used to decrypt all my secrets via agenix, and then I can use them in this flake. +This directory contains this README.md, and a `nixos.nix`/`darwin.nix` that used to decrypt all my +secrets via agenix, and then I can use them in this flake. ## Adding or Updating Secrets > All the operations in this section should be performed in my private repository: `nix-secrets`. -This task is accomplished using the [agenix](https://github.com/ryantm/agenix) CLI tool with the `./secrets.nix` file, so you need to have it installed first: +This task is accomplished using the [agenix](https://github.com/ryantm/agenix) CLI tool with the +`./secrets.nix` file, so you need to have it installed first: To use agenix temporarily, run: @@ -29,7 +36,8 @@ nix shell nixpkgs#agenix Suppose you want to add a new secret file `xxx.age`. Follow these steps: 1. Navigate to your private `nix-secrets` repository. -2. Edit `secrets.nix` and add a new entry for `xxx.age`, defining the encryption keys and the secret file path, for example: +2. Edit `secrets.nix` and add a new entry for `xxx.age`, defining the encryption keys and the secret + file path, for example: ```nix # This file is not imported into your NixOS configuration. It is only used for the agenix CLI. @@ -72,14 +80,15 @@ Alternatively, you can encrypt an existing file to `xxx.age` using the following cat xxx | sudo agenix -e ./xxx.age -i /etc/ssh/ssh_host_ed25519_key ``` -`agenix` will encrypt the file with all the public keys we defined in `secrets.nix`, -so all the users and systems defined in `secrets.nix` can decrypt it with their private keys. +`agenix` will encrypt the file with all the public keys we defined in `secrets.nix`, so all the +users and systems defined in `secrets.nix` can decrypt it with their private keys. ## Deploying Secrets > All the operations in this section should be performed in this repository. -First, add your own private `nix-secrets` repository and `agenix` as a flake input, and pass them to sub modules via `specialArgs`: +First, add your own private `nix-secrets` repository and `agenix` as a flake input, and pass them to +sub modules via `specialArgs`: ```nix { @@ -145,22 +154,25 @@ Then, create `./secrets/default.nix` with the following content: } ``` -From now on, every time you run `nixos-rebuild switch`, it will decrypt the secrets using the private keys defined in `age.identityPaths`. -It will then symlink the secrets to the path defined by the `age.secrets..path` argument, which defaults to `/etc/secrets`. - +From now on, every time you run `nixos-rebuild switch`, it will decrypt the secrets using the +private keys defined in `age.identityPaths`. It will then symlink the secrets to the path defined by +the `age.secrets..path` argument, which defaults to `/etc/secrets`. ## Adding a new host -1. `cat` the sytem-level public key(`/etc/ssh/ssh_host_ed25519_key.pub`) of the new host, and send it to an old host which has already been configured. +1. `cat` the system-level public key(`/etc/ssh/ssh_host_ed25519_key.pub`) of the new host, and send + it to an old host which has already been configured. 2. On the old host: - 1. Add the public key to `secrets.nix`, and rekey all the secrets via `sudo agenix -r -i /etc/ssh/ssh_host_ed25519_key`. + 1. Add the public key to `secrets.nix`, and rekey all the secrets via + `sudo agenix -r -i /etc/ssh/ssh_host_ed25519_key`. 2. Commit and push the changes to `nix-secrets`. 3. On the new host: - 1. Clone this repo and run `nixos-rebuild switch` to deploy it, all the secrets will be decrypted automatically via the host private key. - + 1. Clone this repo and run `nixos-rebuild switch` to deploy it, all the secrets will be decrypted + automatically via the host private key. ## Other Replacements - [ragenix](https://github.com/yaxitech/ragenix): A Rust reimplementation of agenix. - - agenix is mainly written in bash, and it's error message is quite obscure, a little typo may cause some errors no one can understand. + - agenix is mainly written in bash, and it's error message is quite obscure, a little typo may + cause some errors no one can understand. - with a type-safe language like Rust, we can get a better error message and less bugs. diff --git a/secrets/nixos.nix b/secrets/nixos.nix index 2bf285fc..84bada05 100644 --- a/secrets/nixos.nix +++ b/secrets/nixos.nix @@ -35,7 +35,7 @@ in { server.operation.enable = mkEnableOption "NixOS Secrets for Operation Servers(Backup, Monitoring, etc)"; server.kubernetes.enable = mkEnableOption "NixOS Secrets for Kubernetes"; - impermanence.enable = mkEnableOption "Wether use impermanence and ephemeral root file system"; + impermanence.enable = mkEnableOption "whether use impermanence and ephemeral root file system"; }; config = diff --git a/vars/README.md b/vars/README.md index 83e1ec43..96ef3d92 100644 --- a/vars/README.md +++ b/vars/README.md @@ -1,5 +1,3 @@ # Variables Some common variables that I use in my NixOS configuration. - -