Spire How To
Connect to multiple hosts in parallel
Pass a vector or sequence of host descriptors to ssh-group
. Host descriptors can be a host string or a host config hashmap.
(ssh-group ["root@host-1" "root@host-2"]
;; commands here
)
or
(ssh-group [{:username "root" :hostname "host-1"}
{:username "root" :hostname "host-2"]]
;; commands here
)
Connect to a single host
Use the ssh
macro. This can take a host string, or a host config hashmap.
(ssh "root@localhost"
;; commands here
)
or
(ssh {:username "root" :hostname "localhost"}
;; commands here
)
or
(ssh {:host-string "root@localhost"}
;; commands here
)
Connect to an SSH server on a non-standard port
Append the port number to the host string:
(ssh "root@localhost:2200"
;; commands here
)
or specify the :port
key in a host config hashmap
(ssh {:username "root" :hostname "localhost" :port 2200}
;; commands here
)
Connect to an SSH server using a password stored in the program
If key authentication is not being used spire
will try to use password authentication. If this is allowed by the server but not provided by the program, the program will prompt the user via the terminal to enter a password:
$ spire -e '(ssh "localhost" ...)'
Enter Password for user@locahost: ...type in password here...
To provide a password inside the program to be used, use the :password
host config key
(ssh {:username "root"
:hostname "localhost"
:password "my-super-secret-password"}
;; commands here
)
Connect to an SSH server with a specific key located in a local file
Pass the key's file location into the :identity
of a host config:
(ssh {:host-string "root@localhost"
:identity "/home/user/.ssh/id_rsa"}
;; commands here
)
$ spire my-script.clj
Enter Passphrase for /home/user/.ssh/id_rsa: ...type in key passphrase here...
Connect to an SSH server with a specific key contained in a var
You can provide the key content to be used to authenticate with :private-key
:
(ssh {:host-string "root@localhost"
:private-key (slurp "/home/user/.ssh/id_rsa")}
;; commands here
)
$ spire my-script.clj
Enter Passphrase for inline key for root@localhost: ...type in key passphrase here...
Connect to an SSH server with an encrypted private key in a file
If you specify an encrypted identity and no passphrase, spire will ask for your passphrase via the terminal. You can manually pass in both the key and the key's :passphrase
(ssh {:host-string "root@localhost"
:identity "/home/user/.ssh/id_rsa"
:passphrase "this is my super secret key passphrase"}
;; commands here
)
Connect to an SSH server with an encrypted private key from a var
If you specify an encrypted identity and no passphrase, spire will ask for your passphrase via the terminal. You can manually pass in both the key and the key's :passphrase
(ssh {:host-string "root@localhost"
:private-key (slurp "/home/user/.ssh/id_rsa")
:passphrase "this is my super secret key passphrase"}
;; commands here
)
Dangerously connect to an SSH server without checking the host key
Pass in :strict-host-key-check
with a value of false
to the host configuration:
(ssh {:host-string "root@localhost"
:strict-host-key-checking false}
;; commands here
)
Note: This parameter will both allow you to connect to a new host with an unknown key, and connect to an existing host with a key that differs from the one stored locally in the host key storage.
Note: Connecting to a machine with this value set to false, stores the key in the known_hosts file.
Automatically accept the provided host certificate and store it
Pass in :accept-host-key
with a value of true
and your blueprint will automatically answer yes for that host if it is asked whether to accept a new host-key:
(ssh {:username "root"
:hostname "localhost"
:accept-host-key true}
;; commands here
)
Note: This will not allow you to connect to the host if the host key has changed. You will need to remove your old host key with ssh -R "username@hostname"
so the new key can be accepted and stored.
Only automatically accept a new host key if the signature matches a known signature.
Pass in the known signature as the value of :host-key-accept
:
(ssh {:username "root"
:hostname "localhost"
:accept-host-key "e4:d6:ce:f8:c4:4f:b4:60:1a:47:fc:f0:27:c8:da:c7"}
;; commands here
)
Activate authentication agent forwarding to the remote machine
Set :agent-forwarding
to true
in the host config
(ssh {:username "root"
:hostname "remote-host"
:agent-forwarding true}
(shell {:cmd "ssh -T git@github.com"}))
Accessing the present host config definition when running in parallel
The function (get-host-config)
will return the present executing host config hash-map:
(ssh-group ["root@host-1" "root@host-2"]
(let [config (get-host-config)]
;; config will reference host-1 or host-2, whichever we are running inside
(hostname (:hostname config))
))
You can get a specific element of the host config by supplying a value lookup path to it:
(ssh-group ["root@host-1" "root@host-2"]
(hostname (get-host-config [:hostname])))
Get the facts describing the target system
You can get all facts for the target system by calling (get-fact)
(ssh-group ["root@host-1" "root@host-2"]
(get-fact))
You can pass a key path to lookup into get-fact
:
(ssh-group ["root@host-1" "root@host-2"]
(get-fact [:system]))
Get the facts describing a different system to your present target.
You can look up another system's facts with a few methods:
...TODO explain ...
Provide a custom host key for parallel execution result sets
ssh-group
returns the result set as a hashmap. This hashmap by default is keyed with the host string.
(ssh-group ["root@host-1" "root@host-2"]
(get-fact [:system :os]))
$ spire example.clj
{"root@host-1" {...}
"root@host-2" {...}}
You can provide your own key to refer to this machine by with the :key
host config argument:
(ssh-group [{:username "root"
:hostname "host-1"
:key :host-1}
{:username "root"
:hostname "host-2"
:key :host-2}]
(get-fact [:system :os]))
$ spire example.clj
{:host-1 {...}
:host-2 {...}}
Run some modules on only one type of operating system
Use the on-os
macro:
(ssh-group all-hosts
(on-os
:linux (apt :update)
:freebsd (pkg :update)))
Run some modules on only a specific linux distribution
Use the on-distro
macro:
(ssh-group all-hosts
(on-distro
:ubuntu (apt :update)
:centos (yum :update)))
Create a standalone script
Use a shebang line on your file
#!/usr/bin/env spire
;; clojure code here
Set the executable bit and launch it.
$ chmod a+x my-file.clj
$ ./my-file.clj
Read the launch arguments
Use the *command-line-args*
var.
(let [target (second *command-line-args*)]
(ssh target
(get-fact)))
$ spire my-file.clj root@localhost
Read a local environment variable
The System
namespace is available. Use its getenv
function:
(when (= "dev" (System/getenv "SPIRE_ENV"))
;; some special rules for dev
)
Run a shell command on the remote machines
The shell
module provides all you need
(ssh "root@localhost"
(shell {:cmd "ps aux"}))
Debug a blueprint by printing a result and then continuing
Use debug
to probe the return values of a module and print them on the output.
(ssh "root@localhost"
(debug (shell {:cmd "ps aux"})))
Run modules as root under passwordless sudo
Use the sudo
macro to enclose some modules
(ssh "user@localhost"
(sudo
(shell {:cmd "whoami"})))
Run the modules as another user using sudo
Using the sudo-user
macro allows you to specify the user and password
(ssh "user@localhost"
(sudo-user {:username "root"
:password "my-sudo-password"}
(shell {:cmd "whoami"})))