diff --git a/dev/tramp-sample-project/Dockerfile b/dev/tramp-sample-project/Dockerfile deleted file mode 100644 index 7d87b18cd..000000000 --- a/dev/tramp-sample-project/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM clojure:temurin-17-lein-bullseye -ENV DEBIAN_FRONTEND=noninteractive -ENV NREPL_PORT=7888 - -RUN apt-get update \ - && apt-get install -y openssh-server locales \ - && mkdir /var/run/sshd - -RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ - locale-gen -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -RUN locale-gen en_US.UTF-8 -RUN locale-gen en en_US en_US.UTF-8 -RUN dpkg-reconfigure locales - -RUN echo 'root:cider' | chpasswd - -RUN sed -i 's/^#* *PasswordAuthentication .*/PasswordAuthentication yes/' /etc/ssh/sshd_config -RUN sed -i 's/^#* *PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config -RUN sed -i 's/^#* *ChallengeResponseAuthentication .*/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config - -# SSH login fix. Otherwise user is kicked off after login -RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd - -EXPOSE 22 - -CMD ["/usr/sbin/sshd", "-D"] - -WORKDIR /usr/src/app - -COPY . /usr/src/app - -RUN lein deps - -RUN echo "export JAVA_HOME=${JAVA_HOME}" >> /root/.bashrc -RUN echo "export JAVA_CMD=${JAVA_HOME}/bin/java" >> /root/.bashrc -RUN echo "export LEIN_HOME=${LEIN_HOME}" >> /root/.bashrc -RUN echo "export LEIN_JAVA_CMD=${LEIN_JAVA_CMD}" >> /root/.bashrc -RUN echo "export LEIN_JVM_OPTS=${LEIN_JVM_OPTS}" >> /root/.bashrc -RUN echo "export LEIN_ROOT=${LEIN_ROOT}" >> /root/.bashrc -RUN echo "export NREPL_PORT=${NREPL_PORT}" >> /root/.bashrc -RUN echo "export PATH=${PATH}" >> /root/.bashrc diff --git a/dev/tramp-sample-project/Dockerfile.template b/dev/tramp-sample-project/Dockerfile.template new file mode 100644 index 000000000..1094dbbad --- /dev/null +++ b/dev/tramp-sample-project/Dockerfile.template @@ -0,0 +1,43 @@ +# Use an official Clojure image as parent +FROM {{container/parent}} + +# PATH "hardening" +# +# Upstream does not install the jdk via apt, but (1) copies it to /opt and +# (2) adds it to PATH in an ENV directive. These are available when using docker +# commands like run or exec, but will not propagate through ssh. +# +# Moreover, when executing a shell-command via tramp, it won't lookup the user-specific +# PATH by default. Instead, it searches for the executable in conventional directories +# like /usr/bin and the remotes initial `getconf PATH`. +# +# Lastly, in the case of running a login shell, PATH will be overwritten by /etc/profile +# with a hardcoded value. +# +# To circumvent these and other potential issues, we ensure that java +# is symlinked to the expected places. +RUN ln -sv $JAVA_HOME/bin/* /usr/bin/ + +# Persisting upstreams other envars to /etc/environment ensures that they are available +# from *everywhere* unless overwritten. +RUN echo JAVA_HOME=$JAVA_HOME >> /etc/environment && \ + echo CLOJURE_VERSION=$CLOJURE_VERSION >> /etc/environment + +# SSH server setup +RUN apt-get update && apt-get install -y \ + openssh-server && \ + # Start as a service once, to init necessary runtime state + service ssh start && \ + # ! Allow remote root access ! + # ! password: cider ! + sed -i 's/^#* *PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config && \ + echo 'root:cider' | chpasswd +EXPOSE 22 + +# Project folder initialization +COPY . /usr/src/app +WORKDIR /usr/src/app +RUN {{project/init-cmd}} + +# Run the ssh server. [-D]on't be a daemon. Log to std[-e]rr. +ENTRYPOINT ["/usr/sbin/sshd","-De"] diff --git a/dev/tramp-sample-project/Makefile b/dev/tramp-sample-project/Makefile deleted file mode 100644 index d2487db65..000000000 --- a/dev/tramp-sample-project/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -build: - DOCKER_BUILDKIT=0 docker build --no-cache -t cider-tramp-dev . - -run: build - docker run -p 7888:7888 -p 8022:22 cider-tramp-dev - -ssh: - ssh-keygen -R "[localhost]:8022" - echo "Password is: cider" - ssh root@localhost -p 8022 diff --git a/dev/tramp-sample-project/Makefile.template b/dev/tramp-sample-project/Makefile.template new file mode 100644 index 000000000..2d7f50f99 --- /dev/null +++ b/dev/tramp-sample-project/Makefile.template @@ -0,0 +1,18 @@ +build: remove-from-known-hosts + docker build -t {{container/name}} . + +run: build + docker run -p {{container/ssh-port}}:22 {{container/name}} + +remove-from-known-hosts: + ssh-keygen -R '[localhost]:{{container/ssh-port}}' + +ssh-login: + echo "Password is: cider" + ssh root@localhost -p {{container/ssh-port}} + +stop: + docker stop `(docker ps --quiet --filter ancestor={{container/name}})` || exit 0 + +cleanup: stop + docker remove `(docker ps --all --quiet --filter ancestor={{container/name}})` diff --git a/dev/tramp-sample-project/README.md b/dev/tramp-sample-project/README.md index b913ea37c..18df5789f 100644 --- a/dev/tramp-sample-project/README.md +++ b/dev/tramp-sample-project/README.md @@ -6,13 +6,17 @@ This way, for development purposes, we can SSH into it with TRAMP and exercise C ## Some ways to get started: -### `cider-jack-in` from a tramp buffer -* `M-:` `(async-shell-command "make run")` to run the Docker image -* `M-:` `(find-file "/sshx:root@localhost#8022:/usr/src/app/src/foo.clj")` -* `M-x` `cider-jack-in` -* Enter password: `cider` +### Using babashka + +* Use `bb run lein` or `bb run tools-deps` to start a container +* Follow the on screen instructions +* Stop the container[s] with `bb stop lein`, `bb stop tools-deps` +* Remove them with `bb clean lein`, `bb clean tools-deps` +* See `bb.edn` for all commands and how this is wired up + ### Manually create a remote repl and connect to it +* cd to `./lein` * In one terminal tab, run `make run` to run the Docker image * Once it's ready, from another tab, run `make ssh` and start a repl manually from there * The password is `cider` @@ -24,3 +28,4 @@ Now, from emacs you can `cider-connect` to localhost. * `M-x cider-connect` (choose `localhost`, `7888`) NOTE: Do not visit `foo.clj` directly - do it from dired instead. + diff --git a/dev/tramp-sample-project/bb.edn b/dev/tramp-sample-project/bb.edn new file mode 100644 index 000000000..7f48ce2e9 --- /dev/null +++ b/dev/tramp-sample-project/bb.edn @@ -0,0 +1,55 @@ +;; TODO Troubleshooting and explainers: +;; - provide a better fix for the ssh-key problem +;; - ! (nrepl-use-ssh-fallback-for-remote-hosts t) has to be t +;; - vterm will fail with /usr/bin/bash, there's only /bin/bash +;; - explain unsafe autosafe names +;; - ! message how to connect +;; - ! password? and fingerprint? +;; - check if already running and stop it + +{:paths ["."] + :tasks + {build {:depends [-dockerfile] + :task (bash "docker build -t {{container/name}} ./{{project/dir}}")} + start {:depends [build] + :task + (do (echo "\n--------------------------------------------------------------------------------\n" + "Get started:\n" + " (1) M-x find-file \"ssh:/root@localhost#{{container/ssh-port}}:/usr/src/app/src/foo.clj\"" + " (2) Accept the host key [on xfirst run only]" + " (3) Enter password: \"cider\"" + " (4) M-x cider-jack-in-clj" + "\n--------------------------------------------------------------------------------\n") + (bash "docker run -p {{container/ssh-port}}:22 {{container/name}}"))} + stop (bash "docker stop $(docker ps --quiet --filter ancestor={{container/name}}) || exit 0") + cleanup {:depends [stop -remove-from-known-hosts] + :task (bash "docker remove `(docker ps --all --quiet --filter ancestor={{container/name}})`")} + list (bash "docker ps --filter ancestor={{container/name}}") + + -remove-from-known-hosts (bash "ssh-keygen -R \"[localhost]:{{container/ssh-port}}\"") + ;; TODO stop if already running + + -dockerfile (spit (str (:project/dir target) "Dockerfile") (selmer/render-file "Dockerfile.template" target)) + -makefile (spit (str (:project/dir target) "Makefile") (selmer/render-file "Makefile.template" target)) + + :init + (do (def config + {:lein {:project/dir "lein-app/" + :project/init-cmd "lein deps" + :container/ssh-port "8022" + :container/name "cider-tramp-dev-lein" + :container/parent "clojure:temurin-17-lein-bullseye"} + :tools-deps {:project/dir "tools-deps-app/" + :project/init-cmd "clojure -P" + :container/ssh-port "9022" + :container/name "cider-tramp-dev-tools-deps" + :container/parent "clojure:temurin-17-tools-deps-bullseye"}}) + + (def target (config (or (keyword (first *command-line-args*)) :tools-deps))) + (defn bash [s] (shell (str "bash -c '" (selmer/render s target) "'"))) + (defn echo [& lines] (println (selmer/render (str/join "\n" lines) target))) + ;; Print the shell-command that's executed. From https://clojurians.slack.com/archives/CLX41ASCS/p1693517240805539?thread_ts=1693515381.686759&cid=CLX41ASCS + (alter-var-root (var babashka.process/*defaults*) assoc :pre-start-fn (fn [m] (apply println ">" (:cmd m))))) + :leave (println "Finished task:" (:name (current-task))) + :requires ([selmer.parser :as selmer] + [clojure.string :as str])}} diff --git a/dev/tramp-sample-project/lein-app/Dockerfile b/dev/tramp-sample-project/lein-app/Dockerfile new file mode 100644 index 000000000..624111922 --- /dev/null +++ b/dev/tramp-sample-project/lein-app/Dockerfile @@ -0,0 +1,43 @@ +# Use an official Clojure image as parent +FROM clojure:temurin-17-lein-bullseye + +# PATH "hardening" +# +# Upstream does not install the jdk via apt, but (1) copies it to /opt and +# (2) adds it to PATH in an ENV directive. These are available when using docker +# commands like run or exec, but will not propagate through ssh. +# +# Moreover, when executing a shell-command via tramp, it won't lookup the user-specific +# PATH by default. Instead, it searches for the executable in conventional directories +# like /usr/bin and the remotes initial `getconf PATH`. +# +# Lastly, in the case of running a login shell, PATH will be overwritten by /etc/profile +# with a hardcoded value. +# +# To circumvent these and other potential issues, we ensure that java +# is symlinked to the expected places. +RUN ln -sv $JAVA_HOME/bin/* /usr/bin/ + +# Persisting upstreams other envars to /etc/environment ensures that they are available +# from *everywhere* unless overwritten. +RUN echo JAVA_HOME=$JAVA_HOME >> /etc/environment && \ + echo CLOJURE_VERSION=$CLOJURE_VERSION >> /etc/environment + +# SSH server setup +RUN apt-get update && apt-get install -y \ + openssh-server && \ + # Start as a service once, to init necessary runtime state + service ssh start && \ + # ! Allow remote root access ! + # ! password: cider ! + sed -i 's/^#* *PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config && \ + echo 'root:cider' | chpasswd +EXPOSE 22 + +# Project folder initialization +COPY . /usr/src/app +WORKDIR /usr/src/app +RUN lein deps + +# Run the ssh server. [-D]on't be a daemon. Log to std[-e]rr. +ENTRYPOINT ["/usr/sbin/sshd","-De"] diff --git a/dev/tramp-sample-project/lein-app/Makefile b/dev/tramp-sample-project/lein-app/Makefile new file mode 100644 index 000000000..95366d111 --- /dev/null +++ b/dev/tramp-sample-project/lein-app/Makefile @@ -0,0 +1,18 @@ +build: remove-from-known-hosts + docker build -t cider-tramp-dev-lein . + +run: build + docker run -p 8022:22 cider-tramp-dev-lein + +remove-from-known-hosts: + ssh-keygen -R '[localhost]:8022' + +ssh-login: + echo "Password is: cider" + ssh root@localhost -p 8022 + +stop: + docker stop `(docker ps --quiet --filter ancestor=cider-tramp-dev-lein)` || exit 0 + +cleanup: stop + docker remove `(docker ps --all --quiet --filter ancestor=cider-tramp-dev-lein)` diff --git a/dev/tramp-sample-project/project.clj b/dev/tramp-sample-project/lein-app/project.clj similarity index 100% rename from dev/tramp-sample-project/project.clj rename to dev/tramp-sample-project/lein-app/project.clj diff --git a/dev/tramp-sample-project/lein-app/src/foo.clj b/dev/tramp-sample-project/lein-app/src/foo.clj new file mode 100644 index 000000000..6240f3a3a --- /dev/null +++ b/dev/tramp-sample-project/lein-app/src/foo.clj @@ -0,0 +1,7 @@ +(ns foo + (:require + [clj-http.client :as client])) + +(def home (client/get "http://www.clojure.org")) + +(sort-by second > (frequencies (:body home))) diff --git a/dev/tramp-sample-project/src/foo.clj b/dev/tramp-sample-project/src/foo.clj deleted file mode 100644 index e5a730e66..000000000 --- a/dev/tramp-sample-project/src/foo.clj +++ /dev/null @@ -1,3 +0,0 @@ -(ns foo - (:require - [clj-http.client :as client])) diff --git a/dev/tramp-sample-project/tools-deps-app/Dockerfile b/dev/tramp-sample-project/tools-deps-app/Dockerfile new file mode 100644 index 000000000..e8341e339 --- /dev/null +++ b/dev/tramp-sample-project/tools-deps-app/Dockerfile @@ -0,0 +1,43 @@ +# Use an official Clojure image as parent +FROM clojure:temurin-17-tools-deps-bullseye + +# PATH "hardening" +# +# Upstream does not install the jdk via apt, but (1) copies it to /opt and +# (2) adds it to PATH in an ENV directive. These are available when using docker +# commands like run or exec, but will not propagate through ssh. +# +# Moreover, when executing a shell-command via tramp, it won't lookup the user-specific +# PATH by default. Instead, it searches for the executable in conventional directories +# like /usr/bin and the remotes initial `getconf PATH`. +# +# Lastly, in the case of running a login shell, PATH will be overwritten by /etc/profile +# with a hardcoded value. +# +# To circumvent these and other potential issues, we ensure that java +# is symlinked to the expected places. +RUN ln -sv $JAVA_HOME/bin/* /usr/bin/ + +# Persisting upstreams other envars to /etc/environment ensures that they are available +# from *everywhere* unless overwritten. +RUN echo JAVA_HOME=$JAVA_HOME >> /etc/environment && \ + echo CLOJURE_VERSION=$CLOJURE_VERSION >> /etc/environment + +# SSH server setup +RUN apt-get update && apt-get install -y \ + openssh-server && \ + # Start as a service once, to init necessary runtime state + service ssh start && \ + # ! Allow remote root access ! + # ! password: cider ! + sed -i 's/^#* *PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config && \ + echo 'root:cider' | chpasswd +EXPOSE 22 + +# Project folder initialization +COPY . /usr/src/app +WORKDIR /usr/src/app +RUN clojure -P + +# Run the ssh server. [-D]on't be a daemon. Log to std[-e]rr. +ENTRYPOINT ["/usr/sbin/sshd","-De"] diff --git a/dev/tramp-sample-project/tools-deps-app/Makefile b/dev/tramp-sample-project/tools-deps-app/Makefile new file mode 100644 index 000000000..302ef371b --- /dev/null +++ b/dev/tramp-sample-project/tools-deps-app/Makefile @@ -0,0 +1,18 @@ +build: remove-from-known-hosts + docker build -t cider-tramp-dev-tools-deps . + +run: build + docker run -p 9022:22 cider-tramp-dev-tools-deps + +remove-from-known-hosts: + ssh-keygen -R '[localhost]:9022' + +ssh-login: + echo "Password is: cider" + ssh root@localhost -p 9022 + +stop: + docker stop `(docker ps --quiet --filter ancestor=cider-tramp-dev-tools-deps)` || exit 0 + +cleanup: stop + docker remove `(docker ps --all --quiet --filter ancestor=cider-tramp-dev-tools-deps)` diff --git a/dev/tramp-sample-project/tools-deps-app/deps.edn b/dev/tramp-sample-project/tools-deps-app/deps.edn new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/dev/tramp-sample-project/tools-deps-app/deps.edn @@ -0,0 +1 @@ +{} diff --git a/dev/tramp-sample-project/tools-deps-app/src/foo.clj b/dev/tramp-sample-project/tools-deps-app/src/foo.clj new file mode 100644 index 000000000..6240f3a3a --- /dev/null +++ b/dev/tramp-sample-project/tools-deps-app/src/foo.clj @@ -0,0 +1,7 @@ +(ns foo + (:require + [clj-http.client :as client])) + +(def home (client/get "http://www.clojure.org")) + +(sort-by second > (frequencies (:body home)))