Generating SSH oJobs
oJobs are not only restricted to OpenAF’s javascript or shell script. They can actually handle multiple languages. One of the bundled languages is ssh.
The ssh oJob’s job language allows you to define jobs that execute shell scripts in other hosts acesssible through SSH. Given the oJob features of being able to run jobs in parallel, declaring dependencies between them, modularity, etc… allows you to build, on a simple YAML oJob definition, complex multi-target actions. For example:
- being able to execute a shell script template in multiple hosts at the same time
- gathering the results of running multiple commands in multiple hosts
Getting started
To get started quickly simple execute:
$ ojob ojob.io/ojob/templates/ssh num=3 > example.yaml
This will generate an example.yaml ready for you change and execute commands in three hosts.
You can change the number of hosts at any time, read the hosts from another file or even implement dynamic logic (using an API, for example) to determine the current list of hosts
Changing the generated oJob
On the begining of the file you have a fix list to get started. You can use YAML’s achors, as generated, to make it easier and faster to build these lists. Basically each list entry needs:
Entry | Comment |
---|---|
name | Just an unique name to identify the target for easier identification on logs. |
host | The hostname or IP address of the target. |
port | The SSH port (e.g. usually 22). |
login | The SSH login to use. |
pass | The SSH password to use or the private SSH identification certificate password (can be in encrypted form). |
id | The file path to a private SSH identifcation certificate password. |
timeout | The connection timeout in ms. |
# The password will be asked and set for all. To disable and provide no password or a specific password
# for each: (1) uncomment "pass:"; (2) comment "Ask pass" in the todo section;
#
list: &LIST
- ssh:
name : Host A
host : 1.2.3.4
port : &PORT 22
login : &LOGIN aLogin
#pass : &PASS theLoginOrKeyPasswordEncrypted
id : &ID /path/to/private_key.id
timeout: &TIMEOUT 2500
- ssh:
name : Host B
host : 1.2.3.5
port : *PORT
login : *LOGIN
#pass : *PASS
id : *ID
timeout: *TIMEOUT
# [...]
Asking for the password
If a password is not defined it will be interactively asked through the “Ask pass” job:
todo:
- Ask pass
- Run commands
Connectivity check
Included in the template there is a specific job, “Check connectivity”, to use the host and port to understand if the target is network reachable:
# ------------------------
- name: Check connectivity
exec: |
ow.loadNet()
var _r = ow.net.testPort(args.ssh.host, args.ssh.port)
if (!_r) throw templify("Cannot connect to : ()!", args)
The commands to execute
Finally, the commands to execute in each host in the “Run commands” job. Since the args is a list of entries the job will automatically run in parallel. The typeArgs.shellPrefix determines what will be used to identify the logs lines for each target execution:
# ----------------------
- name : Run commands
from :
- Set pass
- Check connectivity
lang : ssh
typeArgs:
shellPrefix: ssh.name
args : *LIST
exec : |
# write here any sh commands you need like it was a shell script
#
id
To avoid running in parallel simply add typeArgs.single to true.
▷ [Ask pass] | 77496 | STARTED ─────────────────────────────────────────────────────── 2023-06-03 12:05:07.626
✓ Password: [---]
✓ [Ask pass] | 77496 | SUCCESS ═══════════════════════════════════════════════════════ 2023-06-03 12:05:10.178
▷ [Run commands] | 77496 | STARTED ─────────────────────────────────────────────────── 2023-06-03 12:05:10.196
[Host B] Darwin b.host 22.5.0 Darwin Kernel Version 22.5.0: Mon Apr 24 20:51:50 PDT 2023; root:xnu-8796.121.2~5/RELEASE_X86_64 x86_64
[Host C] Linux c.host 4.19.0-23-amd64 #1 SMP Debian 4.19.269-1 (2022-12-20) x86_64 GNU/Linux
[Host A] Linux a.host 5.4.0-74-generic #83-Ubuntu SMP Sat May 8 02:35:39 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
✓ [Run commands] | 77496 | SUCCESS ═══════════════════════════════════════════════════ 2023-06-03 12:05:11.842