diff --git a/m/hut/monitoring.nix b/m/hut/monitoring.nix index db5f49fb..0c1cb78a 100644 --- a/m/hut/monitoring.nix +++ b/m/hut/monitoring.nix @@ -6,7 +6,7 @@ ../module/meteocat-exporter.nix ../module/upc-qaire-exporter.nix ./gpfs-probe.nix - ./nix-daemon-exporter.nix + ../module/nix-daemon-exporter.nix ]; age.secrets.grafanaJungleRobotPassword = { diff --git a/m/hut/nix-daemon-builds.sh b/m/module/nix-daemon-builds.sh similarity index 100% rename from m/hut/nix-daemon-builds.sh rename to m/module/nix-daemon-builds.sh diff --git a/m/hut/nix-daemon-exporter.nix b/m/module/nix-daemon-exporter.nix similarity index 100% rename from m/hut/nix-daemon-exporter.nix rename to m/module/nix-daemon-exporter.nix diff --git a/m/module/p.nix b/m/module/p.nix new file mode 100644 index 00000000..2005eb87 --- /dev/null +++ b/m/module/p.nix @@ -0,0 +1,68 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.p; +in +{ + options = { + services.p = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to enable the p service."; + }; + path = lib.mkOption { + type = lib.types.str; + default = "/var/lib/p"; + description = "Where to save the pasted files on disk."; + }; + url = lib.mkOption { + type = lib.types.str; + default = "https://jungle.bsc.es/p"; + description = "URL prefix for the printed file."; + }; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = let + p = pkgs.writeShellScriptBin "p" '' + set -e + pastedir="${cfg.path}/$USER" + cd "$pastedir" + + ext="txt" + if [ -n "$1" ]; then + ext="$1" + fi + + out=$(mktemp "XXXXXXXX.$ext") + cat > "$out" + chmod go+r "$out" + echo "${cfg.url}/$USER/$out" + ''; + in [ p ]; + + systemd.services.p = let + # Take only normal users + users = lib.filterAttrs (_: v: v.isNormalUser) config.users.users; + # Create a directory for each user + commands = lib.concatLists (lib.mapAttrsToList (_: user: [ + "install -d -o ${user.name} -g ${user.group} -m 0755 ${cfg.path}/${user.name}" + ]) users); + in { + description = "P service setup"; + requires = [ "network-online.target" ]; + #wants = [ "remote-fs.target" ]; + #after = [ "remote-fs.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = pkgs.writeShellScript "p-init.sh" ('' + + install -d -o root -g root -m 0755 ${cfg.path} + + '' + (lib.concatLines commands)); + }; + }; + }; +} diff --git a/m/tent/blackbox.yml b/m/tent/blackbox.yml new file mode 100644 index 00000000..ccd701e8 --- /dev/null +++ b/m/tent/blackbox.yml @@ -0,0 +1,14 @@ +modules: + http_2xx: + prober: http + timeout: 5s + http: + preferred_ip_protocol: "ip4" + follow_redirects: true + valid_status_codes: [] # Defaults to 2xx + method: GET + icmp: + prober: icmp + timeout: 5s + icmp: + preferred_ip_protocol: "ip4" diff --git a/m/tent/configuration.nix b/m/tent/configuration.nix index 07b92449..956a191c 100644 --- a/m/tent/configuration.nix +++ b/m/tent/configuration.nix @@ -6,6 +6,14 @@ ../module/emulation.nix ../module/debuginfod.nix ../module/ssh-hut-extern.nix + ./monitoring.nix + ./nginx.nix + ./nix-serve.nix + ./gitlab-runner.nix + ./gitea.nix + ../hut/public-inbox.nix + ../hut/msmtp.nix + ../module/p.nix ]; # Select the this using the ID to avoid mismatches @@ -22,13 +30,11 @@ # Only BSC DNSs seem to be reachable from the office VLAN nameservers = [ "84.88.52.35" "84.88.52.36" ]; + search = [ "bsc.es" ]; defaultGateway = "10.0.44.1"; }; - nix.settings = { - extra-substituters = [ "https://jungle.bsc.es/cache" ]; - extra-trusted-public-keys = [ "jungle.bsc.es:pEc7MlAT0HEwLQYPtpkPLwRsGf80ZI26aj29zMw/HH0=" ]; - }; + services.p.enable = true; services.prometheus.exporters.node = { enable = true; diff --git a/m/tent/gitea.nix b/m/tent/gitea.nix new file mode 100644 index 00000000..546ac5f3 --- /dev/null +++ b/m/tent/gitea.nix @@ -0,0 +1,30 @@ +{ config, lib, ... }: +{ + services.gitea = { + enable = true; + appName = "Gitea in the jungle"; + + settings = { + server = { + ROOT_URL = "https://jungle.bsc.es/git/"; + LOCAL_ROOT_URL = "https://jungle.bsc.es/git/"; + LANDING_PAGE = "explore"; + }; + metrics.ENABLED = true; + service = { + DISABLE_REGISTRATION = true; + REGISTER_MANUAL_CONFIRM = true; + ENABLE_NOTIFY_MAIL = true; + }; + log.LEVEL = "Warn"; + + mailer = { + ENABLED = true; + FROM = "jungle-robot@bsc.es"; + PROTOCOL = "sendmail"; + SENDMAIL_PATH = "/run/wrappers/bin/sendmail"; + SENDMAIL_ARGS = "--"; + }; + }; + }; +} diff --git a/m/tent/gitlab-runner.nix b/m/tent/gitlab-runner.nix new file mode 100644 index 00000000..166b8ca5 --- /dev/null +++ b/m/tent/gitlab-runner.nix @@ -0,0 +1,93 @@ +{ pkgs, lib, config, ... }: + +{ + age.secrets.tent-gitlab-runner-pm-shell.file = ../../secrets/tent-gitlab-runner-pm-shell-token.age; + age.secrets.tent-gitlab-runner-pm-docker.file = ../../secrets/tent-gitlab-runner-pm-docker-token.age; + age.secrets.tent-gitlab-runner-bsc-docker.file = ../../secrets/tent-gitlab-runner-bsc-docker-token.age; + + services.gitlab-runner = let sec = config.age.secrets; in { + enable = true; + settings.concurrent = 5; + services = { + # For gitlab.pm.bsc.es + gitlab-pm-shell = { + executor = "shell"; + environmentVariables = { + SHELL = "${pkgs.bash}/bin/bash"; + }; + authenticationTokenConfigFile = sec.tent-gitlab-runner-pm-shell.path; + preGetSourcesScript = pkgs.writeScript "setup" '' + echo "This is the preGetSources script running, brace for impact" + env + ''; + }; + gitlab-pm-docker = { + authenticationTokenConfigFile = sec.tent-gitlab-runner-pm-docker.path; + executor = "docker"; + dockerImage = "debian:stable"; + }; + + # For gitlab.bsc.es + gitlab-bsc-docker = { + # gitlab.bsc.es still uses the old token mechanism + registrationConfigFile = sec.tent-gitlab-runner-bsc-docker.path; + tagList = [ "docker" "tent" "nix" ]; + executor = "docker"; + dockerImage = "alpine"; + dockerVolumes = [ + "/nix/store:/nix/store:ro" + "/nix/var/nix/db:/nix/var/nix/db:ro" + "/nix/var/nix/daemon-socket:/nix/var/nix/daemon-socket:ro" + ]; + dockerDisableCache = true; + registrationFlags = [ + # Increase build log length to 64 MiB + "--output-limit 65536" + ]; + preBuildScript = pkgs.writeScript "setup-container" '' + mkdir -p -m 0755 /nix/var/log/nix/drvs + mkdir -p -m 0755 /nix/var/nix/gcroots + mkdir -p -m 0755 /nix/var/nix/profiles + mkdir -p -m 0755 /nix/var/nix/temproots + mkdir -p -m 0755 /nix/var/nix/userpool + mkdir -p -m 1777 /nix/var/nix/gcroots/per-user + mkdir -p -m 1777 /nix/var/nix/profiles/per-user + mkdir -p -m 0755 /nix/var/nix/profiles/per-user/root + mkdir -p -m 0700 "$HOME/.nix-defexpr" + mkdir -p -m 0700 "$HOME/.ssh" + cat >> "$HOME/.ssh/known_hosts" << EOF + bscpm04.bsc.es ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPx4mC0etyyjYUT2Ztc/bs4ZXSbVMrogs1ZTP924PDgT + gitlab-internal.bsc.es ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF9arsAOSRB06hdy71oTvJHG2Mg8zfebADxpvc37lZo3 + EOF + . ${pkgs.nix}/etc/profile.d/nix-daemon.sh + # Required to load SSL certificate paths + . ${pkgs.cacert}/nix-support/setup-hook + ''; + environmentVariables = { + ENV = "/etc/profile"; + USER = "root"; + NIX_REMOTE = "daemon"; + PATH = "${config.system.path}/bin:/bin:/sbin:/usr/bin:/usr/sbin"; + }; + }; + }; + }; + + systemd.services.gitlab-runner.serviceConfig = { + DynamicUser = lib.mkForce false; + User = "gitlab-runner"; + Group = "gitlab-runner"; + ExecStart = lib.mkForce + ''${pkgs.gitlab-runner}/bin/gitlab-runner run --config ''${HOME}/.gitlab-runner/config.toml --listen-address "127.0.0.1:9252" --working-directory ''${HOME}''; + }; + + users.users.gitlab-runner = { + uid = config.ids.uids.gitlab-runner; + home = "/var/lib/gitlab-runner"; + description = "Gitlab Runner"; + group = "gitlab-runner"; + extraGroups = [ "docker" ]; + createHome = true; + }; + users.groups.gitlab-runner.gid = config.ids.gids.gitlab-runner; +} diff --git a/m/tent/monitoring.nix b/m/tent/monitoring.nix new file mode 100644 index 00000000..2d1bdc58 --- /dev/null +++ b/m/tent/monitoring.nix @@ -0,0 +1,205 @@ +{ config, lib, pkgs, ... }: + +{ + imports = [ + ../module/meteocat-exporter.nix + ../module/upc-qaire-exporter.nix + ../module/nix-daemon-exporter.nix + ]; + + age.secrets.grafanaJungleRobotPassword = { + file = ../../secrets/jungle-robot-password.age; + owner = "grafana"; + mode = "400"; + }; + + services.grafana = { + enable = true; + settings = { + server = { + domain = "jungle.bsc.es"; + root_url = "%(protocol)s://%(domain)s/grafana"; + serve_from_sub_path = true; + http_port = 2342; + http_addr = "127.0.0.1"; + }; + smtp = { + enabled = true; + from_address = "jungle-robot@bsc.es"; + user = "jungle-robot"; + # Read the password from a file, which is only readable by grafana user + # https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#file-provider + password = "$__file{${config.age.secrets.grafanaJungleRobotPassword.path}}"; + host = "mail.bsc.es:465"; + startTLS_policy = "NoStartTLS"; + }; + feature_toggles.publicDashboards = true; + "auth.anonymous".enabled = true; + log.level = "warn"; + }; + }; + + services.prometheus = { + enable = true; + port = 9001; + retentionTime = "5y"; + listenAddress = "127.0.0.1"; + }; + + # We need access to the devices to monitor the disk space + systemd.services.prometheus-node-exporter.serviceConfig.PrivateDevices = lib.mkForce false; + systemd.services.prometheus-node-exporter.serviceConfig.ProtectHome = lib.mkForce "read-only"; + + # Credentials for IPMI exporter + age.secrets.ipmiYml = { + file = ../../secrets/ipmi.yml.age; + owner = "ipmi-exporter"; + }; + + # Create an IPMI group and assign the ipmi0 device + users.groups.ipmi = {}; + services.udev.extraRules = '' + SUBSYSTEM=="ipmi", KERNEL=="ipmi0", GROUP="ipmi", MODE="0660" + ''; + + # Add a new ipmi-exporter user that can read the ipmi0 device + users.users.ipmi-exporter = { + isSystemUser = true; + group = "ipmi"; + }; + + # Disable dynamic user so we have the ipmi-exporter user available for the credentials + systemd.services.prometheus-ipmi-exporter.serviceConfig = { + DynamicUser = lib.mkForce false; + PrivateDevices = lib.mkForce false; + User = lib.mkForce "ipmi-exporter"; + Group = lib.mkForce "ipmi"; + RestrictNamespaces = lib.mkForce false; + # Fake uid to 0 so it shuts up + ExecStart = let + cfg = config.services.prometheus.exporters.ipmi; + in lib.mkForce (lib.concatStringsSep " " ([ + "${pkgs.util-linux}/bin/unshare --map-user 0" + "${pkgs.prometheus-ipmi-exporter}/bin/ipmi_exporter" + "--web.listen-address ${cfg.listenAddress}:${toString cfg.port}" + "--config.file ${lib.escapeShellArg cfg.configFile}" + ] ++ cfg.extraFlags)); + }; + + services.prometheus = { + exporters = { + ipmi = { + enable = true; + configFile = config.age.secrets.ipmiYml.path; + #extraFlags = [ "--log.level=debug" ]; + listenAddress = "127.0.0.1"; + }; + node = { + enable = true; + enabledCollectors = [ "logind" ]; + port = 9002; + listenAddress = "127.0.0.1"; + }; + blackbox = { + enable = true; + listenAddress = "127.0.0.1"; + configFile = ./blackbox.yml; + }; + }; + + scrapeConfigs = [ + { + job_name = "local"; + static_configs = [{ + targets = [ + "127.0.0.1:9002" # Node exporter + #"127.0.0.1:9115" # Blackbox exporter + "127.0.0.1:9290" # IPMI exporter for local node + "127.0.0.1:9928" # UPC Qaire custom exporter + "127.0.0.1:9929" # Meteocat custom exporter + "127.0.0.1:9999" # Nix-daemon custom exporter + ]; + }]; + } + { + job_name = "blackbox-http"; + metrics_path = "/probe"; + params = { module = [ "http_2xx" ]; }; + static_configs = [{ + targets = [ + "https://www.google.com/robots.txt" + "https://pm.bsc.es/" + "https://pm.bsc.es/gitlab/" + "https://jungle.bsc.es/" + "https://gitlab.bsc.es/" + ]; + }]; + relabel_configs = [ + { + # Takes the address and sets it in the "target=" URL parameter + source_labels = [ "__address__" ]; + target_label = "__param_target"; + } + { + # Sets the "instance" label with the remote host we are querying + source_labels = [ "__param_target" ]; + target_label = "instance"; + } + { + # Shows the host target address instead of the blackbox address + target_label = "__address__"; + replacement = "127.0.0.1:9115"; + } + ]; + } + { + job_name = "blackbox-icmp"; + metrics_path = "/probe"; + params = { module = [ "icmp" ]; }; + static_configs = [{ + targets = [ + "1.1.1.1" + "8.8.8.8" + "ssfhead" + "raccoon" + "anella-bsc.cesca.cat" + "upc-anella.cesca.cat" + "fox.ac.upc.edu" + "arenys5.ac.upc.edu" + "arenys0-2.ac.upc.edu" + "epi01.bsc.es" + "axle.bsc.es" + ]; + }]; + relabel_configs = [ + { + # Takes the address and sets it in the "target=" URL parameter + source_labels = [ "__address__" ]; + target_label = "__param_target"; + } + { + # Sets the "instance" label with the remote host we are querying + source_labels = [ "__param_target" ]; + target_label = "instance"; + } + { + # Shows the host target address instead of the blackbox address + target_label = "__address__"; + replacement = "127.0.0.1:9115"; + } + ]; + } + { + job_name = "ipmi-raccoon"; + metrics_path = "/ipmi"; + static_configs = [ + { targets = [ "127.0.0.1:9290" ]; } + ]; + params = { + target = [ "raccoon-ipmi" ]; + module = [ "raccoon" ]; + }; + } + ]; + }; +} diff --git a/m/tent/nginx.nix b/m/tent/nginx.nix new file mode 100644 index 00000000..de9214e7 --- /dev/null +++ b/m/tent/nginx.nix @@ -0,0 +1,73 @@ +{ theFlake, pkgs, ... }: +let + website = pkgs.stdenv.mkDerivation { + name = "jungle-web"; + src = theFlake; + buildInputs = [ pkgs.hugo ]; + buildPhase = '' + cd web + rm -rf public/ + hugo + ''; + installPhase = '' + cp -r public $out + ''; + # Don't mess doc/ + dontFixup = true; + }; +in +{ + networking.firewall.allowedTCPPorts = [ 80 ]; + services.nginx = { + enable = true; + virtualHosts."jungle.bsc.es" = { + root = "${website}"; + listen = [ + { + addr = "0.0.0.0"; + port = 80; + } + ]; + extraConfig = '' + set_real_ip_from 127.0.0.1; + set_real_ip_from 84.88.52.107; + real_ip_recursive on; + real_ip_header X-Forwarded-For; + + location /git { + rewrite ^/git$ / break; + rewrite ^/git/(.*) /$1 break; + proxy_pass http://127.0.0.1:3000; + proxy_redirect http:// $scheme://; + } + location /cache { + rewrite ^/cache/(.*) /$1 break; + proxy_pass http://127.0.0.1:5000; + proxy_redirect http:// $scheme://; + } + location /lists { + proxy_pass http://127.0.0.1:8081; + proxy_redirect http:// $scheme://; + } + location /grafana { + proxy_pass http://127.0.0.1:2342; + proxy_redirect http:// $scheme://; + proxy_set_header Host $host; + # Websockets + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + location ~ ^/~(.+?)(/.*)?$ { + alias /vault/home/$1/public_html$2; + index index.html index.htm; + autoindex on; + absolute_redirect off; + } + location /p/ { + alias /var/lib/p/; + } + ''; + }; + }; +} diff --git a/m/tent/nix-serve.nix b/m/tent/nix-serve.nix new file mode 100644 index 00000000..35ccd728 --- /dev/null +++ b/m/tent/nix-serve.nix @@ -0,0 +1,16 @@ +{ config, ... }: + +{ + age.secrets.nixServe.file = ../../secrets/nix-serve.age; + + services.nix-serve = { + enable = true; + # Only listen locally, as we serve it via ssh + bindAddress = "127.0.0.1"; + port = 5000; + + secretKeyFile = config.age.secrets.nixServe.path; + # Public key: + # jungle.bsc.es:pEc7MlAT0HEwLQYPtpkPLwRsGf80ZI26aj29zMw/HH0= + }; +} diff --git a/secrets/ipmi.yml.age b/secrets/ipmi.yml.age index e445aaed..02d12187 100644 Binary files a/secrets/ipmi.yml.age and b/secrets/ipmi.yml.age differ diff --git a/secrets/jungle-robot-password.age b/secrets/jungle-robot-password.age index af68a1b2..a25102e9 100644 Binary files a/secrets/jungle-robot-password.age and b/secrets/jungle-robot-password.age differ diff --git a/secrets/nix-serve.age b/secrets/nix-serve.age index 9ba631a9..2d142fbd 100644 --- a/secrets/nix-serve.age +++ b/secrets/nix-serve.age @@ -1,11 +1,13 @@ age-encryption.org/v1 --> ssh-ed25519 HY2yRg PJVi+uAtVYX0QDMUG5/Ip9OrvpUacDhmqWc/n3gLW30 -EkAFsA6KxxO6bAavRSyJ/faFTQnXqcI/+R1ZAujvmGQ --> ssh-ed25519 CAWG4Q 0JqMbIWUuT0kc/5hdUd4i4Qp41W1LpaiLS5Qz3qlVU8 -uTw5Xjr24vZ1uWeMjy/OVF5SR2EsTgREBF0L1sFEjR8 --> ssh-ed25519 xA739A Ssbmf6ra+Ov4YC9L0ygizkmwOg1GLztxfDQtNY/Y4G8 -rbGwoyinV9phgBqaOgMJeqFKyAFB1fb0hLWhf4mviGE --> ssh-ed25519 MSF3dg KcJlZUVuZaIAnnWxuXZmxZZ9v0whgVe9D3lqpR2GmEI -JND6nt2RWGT53gQp/rot2bXOpm3c4n/WPP4l5KJ/wFo ---- /C3CrTiYseZVwp0N4tMSOiAu49Mp/J6yUn3RUpfmqoc -ݙ0c^bX .7bǜ]CfYB;d∭3%?߭r2-՞'z]$[Sf%̜ŏ 0NM_d|bR~puԝ Aji{6ÊW+o \ No newline at end of file +-> ssh-ed25519 HY2yRg T/Qom1qxE0M+FuvsXD/KZ6Usfp6v3Xwx043kDgxbCz4 +6GRg0QjuHd2+d6lJfZqqPMPMjS91HEcJ/W0KRV6Et50 +-> ssh-ed25519 G5LX5w pzg0wK+Q6KZP67CkyZNYbNcahlq9SIuFN18H85ARykU +aDSrO49tg/a3GOAJR96lh803bXoZqp/G6VMiSvf91vw +-> ssh-ed25519 CAWG4Q X+F/6LF8VUUoV72iCLzKKpYGRDoUHuBy1E+yr29RKEo +c779vpt/fiN7n0kGAc5jA9fWkzCPrthlNZdN4p6csrk +-> ssh-ed25519 xA739A sbg087VKj/gcycV9JrBNCoCfB4kRMDSVo3EtfpRVDyg +Lv5ges1KmxGwvz4UPZCD0v4YN2ms2Q3wmrJ14XCKYsQ +-> ssh-ed25519 MSF3dg pCLeyeWYbnNWQwwlGcsKz0KZ4BaaYKCGjo0XOPpo+no +IsNxFoB2nTxyThJxtAxSA6gauXHGQJnVefs/K2MZ+DM +--- tgB3F+k1/PQt+r5Cz+FqH31hCZFvr0Y8uZVKkdA80yo +60.(s?68QIdgb`Az ssh-ed25519 G5LX5w V9bHLoGuY4stRwbzVS9Qa0L9yoY+UoCoXc+dJJQW/Ag +2ut9GfdJ3KBCqZRaloZCQsl8MLfaZAZxqj6JtPJzu2k +-> ssh-ed25519 CAWG4Q OAqnIfMECpKglZ7aF9tv/PQinG1Ou2+IEZ+nf4dtQjg +dANdMLe4iI0d6Xd/dIMpZK+mgw2+VmJFQScHaIxD7WI +-> ssh-ed25519 xA739A nVNF4Y6VSa5PP6FFBJpVmoFYYseoFx5F2wJU+Pwk+Xk +A5CiuTSNlX9Y76qhYgblBdJl3zPhtjWho2oL5/sIKu0 +-> ssh-ed25519 MSF3dg /WMsGnBGzquIMyw06gHKpSS4OUxheulT59kxi+/pxxU +ppwcv7RLzUbQUM7j0Tb9rRVT9XyPMhqYr2fr4S0nTJY +--- zOe0Ko0oxArbmxePMPDVAT0pDju7IeOAih7sNrDcoVs +ikA +hODVw! E݈+`C5LAtM^ E<HI_nno?j- +AnԔί>ZzdTb"(@{_ځC \ No newline at end of file diff --git a/web/content/paste/_index.md b/web/content/paste/_index.md index e4ebd61d..1022a31d 100644 --- a/web/content/paste/_index.md +++ b/web/content/paste/_index.md @@ -5,13 +5,13 @@ author: "Rodrigo Arias Mallo" date: 2024-09-20 --- -The hut machine provides a paste service using the program `p` (as in paste). +The tent machine provides a paste service using the program `p` (as in paste). -You can use it directly from the hut machine or remotely if you have [SSH -access](/access) to hut using the following alias: +You can use it directly from the tent machine or remotely if you have [SSH +access](/access) to tent using the following alias: ``` -alias p="ssh hut p" +alias p="ssh tent p" ``` You can add it to bashrc or zshrc for persistent installation. @@ -19,7 +19,7 @@ You can add it to bashrc or zshrc for persistent installation. ## Usage The `p` command reads from the standard input, uploads the content to a file -in the ceph filesystem and prints the URL to access it. It only accepts an +in the local filesystem and prints the URL to access it. It only accepts an optional argument, which is the extension of the file that will be stored on disk (without the dot). By default it uses the `txt` extension, so plain text can be read in the browser directly. @@ -28,21 +28,21 @@ can be read in the browser directly. p [extension] ``` -To remove files, go to `/ceph/p/$USER` and remove them manually. +To remove files, go to `/var/lib/p/$USER` and remove them manually. ## Examples Share a text file, in this case the source of p itself: ``` -hut% p < m/hut/p.nix +tent% p < m/tent/p.nix https://jungle.bsc.es/p/rarias/okbtG130.txt ``` Paste the last dmesg lines directly from a pipe: ``` -hut% dmesg | tail -5 | p +tent% dmesg | tail -5 | p https://jungle.bsc.es/p/rarias/luX4STm9.txt ```