breakout to iTerm2 script (#21)

Add a script to generate iTerm2 configurations from the breakout tool console connections.
This commit is contained in:
sgherdao
2022-05-11 21:14:44 +01:00
committed by GitHub
parent b636b84985
commit c991ec19e4
12 changed files with 465 additions and 0 deletions

13
scripts/brk2iterm/Pipfile Normal file
View File

@@ -0,0 +1,13 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
pyyaml = "*"
jinja2 = "*"
[dev-packages]
[requires]
python_version = "3.9"

114
scripts/brk2iterm/Pipfile.lock generated Normal file
View File

@@ -0,0 +1,114 @@
{
"_meta": {
"hash": {
"sha256": "5dfb741c036307722614d300d5752d8d9989e8c1fc77ca77e7c2dd4ae9fbd0ce"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.9"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"jinja2": {
"hashes": [
"sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
"sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
],
"index": "pypi",
"version": "==3.1.2"
},
"markupsafe": {
"hashes": [
"sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003",
"sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88",
"sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5",
"sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7",
"sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a",
"sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603",
"sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1",
"sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135",
"sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247",
"sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6",
"sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601",
"sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77",
"sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02",
"sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e",
"sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63",
"sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f",
"sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980",
"sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b",
"sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812",
"sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff",
"sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96",
"sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1",
"sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925",
"sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a",
"sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6",
"sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e",
"sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f",
"sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4",
"sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f",
"sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3",
"sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c",
"sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a",
"sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417",
"sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a",
"sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a",
"sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37",
"sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452",
"sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933",
"sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a",
"sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"
],
"markers": "python_version >= '3.7'",
"version": "==2.1.1"
},
"pyyaml": {
"hashes": [
"sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
"sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
"sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
"sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b",
"sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4",
"sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07",
"sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba",
"sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9",
"sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
"sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
"sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
"sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
"sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
"sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
"sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
"sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
"sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
"sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
"sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
"sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
"sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
"sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
"sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
"sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
"sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
"sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
"sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
"sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
"sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
"sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
"sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
"sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
"sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
],
"index": "pypi",
"version": "==6.0"
}
},
"develop": {}
}

157
scripts/brk2iterm/README.md Normal file
View File

@@ -0,0 +1,157 @@
## CML breakout to iTerm2
This script reads a CML breakout `labs.yaml` and generates a python script for each lab using Jinja2.
Each python script contains the code to start one of your CML lab, using the iTerm2's [Python API](https://iterm2.com/python-api/).
When launched from iTerm2, a script will open a new window, start the breakout tool and telnet to each nodes for one of your lab.
![showcase](showcase.png)
<p align="right">(<a href="#top">back to top</a>)</p>
## Getting Started
### Prerequisites
- Install iTerm2 if not done already, for example:
```
brew install iterm2
```
- Install the iTerm2's Python Runtime:
From iTerm2's menu, go to `Scripts -> Manage -> Install Python Runtime`
![py-runtime01](install_py_runtime01.png)
This will download and install the iTerm2's Python Runtime:
![py-runtime02](install_py_runtime02.png)
- Get the breakout tool
Download the breakout tool from your CML controller see [Installing the Breakout Tool](https://developer.cisco.com/docs/modeling-labs/#!installing-breakout-tool)
Once the binary obtained, make it executable:
```
chmod u+x breakout-macos-x86_amd64
```
Then, move the binary somewhere in your `$PATH` for example `/usr/local/bin/`, use `breakout` as the destination filename:
```
mv breakout-macos-x86_amd64 /usr/local/bin/breakout
```
Alternatively, create a symlink:
```
ln -s /path/to/breakout-macos-x86_amd64 /usr/local/bin/breakout
```
_Note: The Python script expects the Breakout binary to be named `breakout`; If this is not wanted, rename all occurrences of `breakout` to your preferred name in the code_
### Installation
Clone the repository, cd in the directory and install the requirements:
- pipenv
```
pipenv install
```
- pip
```
python3 -m venv /path/to/directory
pip install -r requirements
```
Note: the only dependences are `pyyaml` and `jinja2`.
## Usage
The following options are available:
```
python3 brk2iterm.py -h
usage: brk2iterm.py [-h] [-d BRK_DIR] [-f YAML_FILE] [-l LISTEN_ADDR] [-s SLEEP]
[-j JINJA2_TEMPLATE]
reads a CML breakout labs.yaml generates iterm python scripts
optional arguments:
-h, --help show this help message and exit
-d BRK_DIR, --brk-dir BRK_DIR
path to dir containing the breakout labs YAML files (default:
current directory)
-f YAML_FILE, --yaml-file YAML_FILE
name of the 'labs' YAML file, (default: labs.yaml)
-l LISTEN_ADDR, --listen_addr LISTEN_ADDR
specify the listen address (default: ::1)
-s SLEEP, --sleep SLEEP
sleep time (in seconds) before initiating telnet session (default:
3)
-j JINJA2_TEMPLATE, --jinja2-template JINJA2_TEMPLATE
full path to the iterm_script.j2 Jinja2 template (default:
./iterm_script.j2)
```
### Generate your CML breakout labs's configurations:
Use `breakout init` or `breakout ui` to fetch the labs and nodes from the controller and generate the `labs.yaml` file:
```
breakout init
get simplified node definitions from controller...
get active console keys from controller...
get active VNC keys from controller...
get all the labs from controller...
get all the nodes for the labs from controller...
get nodes for lab L2L IKEv2 from controller...
get nodes for lab cisco_isis_sr_101_v1 from controller...
config written.
ls -l
.rwxrwxrwx 746 sgherdao 11 Mar 21:04 config.yaml
.rwxrwxrwx 1.3k sgherdao 3 May 21:50 labs.yaml
```
_Note: check your `labs.yaml` file and ensure that `enabled` is set to true for all the desired labs_
### Launch brk2iterm.py
```
python3 brk2iterm.py --brk-dir ~/CML/
ls -l
.rw-r--r-- 659 sgherdao 10 May 19:03 1eaf2c3b-9207-4524-9e7c-3eeaada67886.py <<
.rw-r--r-- 3.0k sgherdao 10 May 18:13 brk2iterm.py
.rw-r--r-- 2.0k sgherdao 10 May 19:03 d231681f-a88c-4004-884a-4c9639ad8b07.py <<
.rw-r--r--@ 1.0M sgherdao 10 May 18:29 install_py_runtime01.png
.rw-r--r--@ 172k sgherdao 10 May 18:31 install_py_runtime02.png
.rw-r--r-- 769 sgherdao 10 May 18:15 iterm_script.j2
.rw-r--r-- 164 sgherdao 10 May 18:09 Pipfile
.rw-r--r-- 7.7k sgherdao 10 May 18:09 Pipfile.lock
.rw-r--r-- 3.7k sgherdao 10 May 18:37 README.md
```
Feel free to give the python iTerm2 scripts less machine friendly names and move
the files to the iTerm2 Scripts directory, the folder should be located there
`~/Library/Application\ Support/iTerm2/Scripts`:
```
mv 1eaf2c3b-9207-4524-9e7c-3eeaada67886.py ~/Library/Application\ Support/iTerm2/Scripts/l2l.py
```
### Launch the lab's script from iTerm2's menu:
![launch_script01](launch_script01.png)
### Happy labbing!
![launch_script02](launch_script02.png)
<p align="right">(<a href="#top">back to top</a>)</p>

View File

@@ -0,0 +1,123 @@
#!/usr/bin/env python3
import argparse
import shutil
import sys
import jinja2
import yaml
def main() -> int:
"""
reads a CML breakout labs.yaml file and returns a list of dict ready to be
translated into multiple JSON or YAML tmuxp session files.
By default, each telnet session will have its own window but if the `-p` or
`--panes` flag is set, then each telnet session will be in a pane in one
(and only one) window.
VNC sessions are ignored.
"""
parser = argparse.ArgumentParser(
description="reads a CML breakout labs.yaml generates iterm python scripts"
)
parser.add_argument(
"-d",
"--brk-dir",
type=str,
default=".",
help="path to dir containing the breakout labs YAML files (default: current directory)",
)
parser.add_argument(
"-f",
"--yaml-file",
type=str,
default="labs.yaml",
help="name of the 'labs' YAML file, (default: labs.yaml)",
)
parser.add_argument(
"-l",
"--listen_addr",
default="::1",
help="specify the listen address (default: ::1)",
)
parser.add_argument(
"-s",
"--sleep",
type=float,
default="3",
help="sleep time (in seconds) before initiating telnet session (default: 3)",
)
parser.add_argument(
"-j",
"--jinja2-template",
type=str,
default="./iterm_script.j2",
help="full path to the iterm_script.j2 Jinja2 template (default: ./iterm_script.j2)",
)
args = parser.parse_args()
# load labs yaml file
brk_dir = args.brk_dir
yaml_file = args.yaml_file
jinja2_template = args.jinja2_template
with open(f"{brk_dir}/{yaml_file}") as f:
labs = yaml.safe_load(f)
listen_addr = args.listen_addr
sleep = args.sleep
iterm_scripts = {}
for uuid, lab in labs.items():
iterm_scripts[uuid] = brk2tabs(
lab=lab,
brk_dir=brk_dir,
listen_addr=listen_addr,
)
with open(jinja2_template) as f:
iterm_template = jinja2.Template(f.read())
for uuid, it_script in iterm_scripts.items():
with open(f"{uuid}.py", "w") as f:
f.write(iterm_template.render(brk_lab=it_script, sleep=sleep))
def brk2tabs(lab: dict, brk_dir: str, listen_addr: str) -> dict:
"""
Extract CML lab relevant info (port, lab title...)
return a dict with iterm tab data
"""
lab_title = lab["lab_title"]
breakout_path = shutil.which("breakout")
conf = {
"session_name": lab_title,
"tabs": [
{
"tab_title": "breakout",
"shell_command": f"cd {brk_dir} && {breakout_path} run '{lab_title}'",
}
],
}
telnet_path = shutil.which("telnet")
for _, node in lab["nodes"].items():
node_label = node["label"]
conf["tabs"].extend(
[
{
"tab_title": f"{node_label}/{n['name'][-1]}",
"shell_command": f"{telnet_path} {listen_addr} {n['listen_port']}",
}
for n in node["devices"]
if n["enabled"] and n["name"] != "vnc"
]
)
return conf
if __name__ == "__main__":
sys.exit(main())

Binary file not shown.

After

Width:  |  Height:  |  Size: 1000 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env python3.7
import iterm2
import time
async def main(connection):
app = await iterm2.async_get_app(connection)
window = await app.current_window.async_create(connection)
{% for brk_tab in brk_lab["tabs"][:1] %}
tab = window.current_tab
await tab.async_set_title("{{ brk_tab["tab_title"] }}")
session = tab.current_session
await session.async_send_text("{{ brk_tab['shell_command'] }}\n")
{% endfor %}
time.sleep({{ sleep }})
{% for brk_tab in brk_lab["tabs"][1:] %}
tab = await window.async_create_tab(
)
await tab.async_set_title("{{ brk_tab["tab_title"] }}")
session = tab.current_session
await session.async_send_text("{{ brk_tab['shell_command'] }}\n")
{% endfor %}
iterm2.run_until_complete(main)

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

View File

@@ -0,0 +1,11 @@
#
# These requirements were autogenerated by pipenv
# To regenerate from the project's Pipfile, run:
#
# pipenv lock --requirements
#
-i https://pypi.org/simple
jinja2
markupsafe
pyyaml

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@@ -45,6 +45,30 @@ brew install tmuxp
apt install tmuxp
```
- Get the breakout tool
Download the breakout tool from your CML controller see [Installing the Breakout Tool](https://developer.cisco.com/docs/modeling-labs/#!installing-breakout-tool)
Once the binary obtained, make it executable:
```
chmod u+x breakout-macos-x86_amd64
```
Then, move the binary somewhere in your `$PATH` for example `/usr/local/bin/`, use `breakout` as the destination filename:
```
mv breakout-macos-x86_amd64 /usr/local/bin/breakout
```
Alternatively, create a symlink:
```
ln -s /path/to/breakout-macos-x86_amd64 /usr/local/bin/breakout
```
_Note: The Python script expects the Breakout binary to be named `breakout` and be in your `PATH`; If this is not wanted, rename relevant occurrences of `breakout` to your preferred name in the code_
### Installation
Clone the repository, cd in the directory and install the requirements: