Torero – Boots on the Ground Framework for Automation Sharing

Background

One of the many useful things I came away with from AutoCon1 in Amsterdam was a "to-do" to investigate torero.

Launched by Itential at NAF's AutoCon1 as a community based product and presented to the AutoCon community by Peter Sprygada in Amsterdam, one has to take notice and I did.

You can see Mr. Sprygada's session for yourself here.

What is torero?

Simply put torero_image is a CLI based framework to facilitate sharing automation (specifically, code repositories). In fact, it is a binary executable you can install on any Linux system (including MAC ARM) which today supports sharing of:

  • Ansible Playbooks (Peter Sprygada, remember?),
  • straight up Python, and
  • OpenTofu (open source Terraform)

I've been able to run the "Getting started" repository (with some minor adjustments documented in the sidebar below) on WLS version 2 using Ubuntu 22.04 so there may be an option for Windows users with Windows Subsystem for Linux although that is not specifically called out in the documentation.

What problem is torero_image trying to solve?

Creating localized automation (here is my script and I am running it on my laptop) is fairly commonplace by now but the real power is being able to share it and execute it consistently. That is the only way to start realizing the promise of "network automation" and "sharing it" is very much a barrier to entry.

In his talk, Peter Sprygada mentions that the inspiration came, at least partially, from discussions around this very topic at AutoCon0.

So back to the problem.

How do you share your automation?

I'll summarize my own experience.

My first issue was that I developed on a Mac (Intel back then) and at the time 100% of my team was using Windows. Eventually some of my team mates actually moved to a Mac (least we miss out on installing many of the modules we used on a new M1) but at the end of the day we are always bound by what our clients make available to us either physically or via a VM or Virtual Desktop and that is most often Windows based (and without Admin privileges).

Windows Executable

So at first I tried various modules which created executable (.exe) versions of my scripts. That was clumsy at best and failed miserably without Admin privileges on Windows systems.

Docker Container

Next I tried Docker containers with "everything you need". I loved this solution as it took out the local installation issues. Unfortunately, this solution ran into similar issues when working in environments without Windows Admin privileges along with issues with the Docker Windows software itself.

Local Virtual Environments

Nothing for it, next was to build out the virtual environments for each engineer. But it was much more than that, first everyone had to learn at least enough about Git to be able to clone a repository and keep it updated (ever grateful for GitHub Desktop). No small feat when revision control is as foreign as Cappadocian Greek to many network engineers. If anything required Admin privileges, we hit a brick wall. (Think of all the ping modules!)

Purpose built custom application servers with GUI or Workflow Frameworks

Over time we've moved to centralized servers when possible using either HTTPS/GUI based in house developed applications/repositories and or frameworks like Prefect and AWX. This allows us to build execution environments in one spot rather than distributed ones. BUT sometimes those are needed.

How can we easily allow network engineers to execute automation from a repository without all the heavy lifting (clone, build env, etc.) AND with some centralized authentication (that is not built in manually) and reporting?

A new option with torero

torero_image is designed to distribute our code by:

  1. instantiating a service for our code which already lives in a repository,
  2. adding centralized authentication if needed,
  3. adding some centralization for reporting and management, and
  4. providing a way to build the required virtual environments on demand.
    These ephemeral virtual environments are built locally on demand as part of running your automation. In that way, they are always current as they are created and destroyed per run.

torero_image can operate in two modes, local and client/server.

What it isn't (so far anyway)

torero_image is not inherently an orchestration or workflow automation tool. If you have built out your playbooks or scripts with embedded orchestration then you are all set but today there are no specific features for orchestration as you will find in those frameworks.

torero_image has no GUI or REST API. Either as a server, client, or standalone/local instance, it is a CLI based tool.

Remember that this was just announced so we are essentially looking at Version 1

Where does it fit?

torero_image is in a very unique space that could help bridge that "how to deploy" or "how to share" gap. The centralized but local model is not one I've encountered before and I have to say I am intrigued.

If you need local execution but want to make it easy to run your automation without putting your team through Git and Python training, this could really help. If you want to overlay authentication, it provides an easy way to do that without a massive uplift.

I do think some features are needed before we can throw torero_image into our toolbox.

  • Better "secret" and credential handling
  • GUI
  • REST API
  • Inventory and variable options or clearer documentation that we should be leveraging other frameworks and solutions for those functions
  • Better reporting and logging
  • Execution progress monitoring
  • Improved Documentation
  • Broader Community Support

Conclusion

In general this space is both maturing and getting quite a bit of attention and torero_image is both and example of that as well as a unique offering within it.

I am excited to see it and will be watching. It needs to mature a bit more but again, this is Version 1.

Once it does, I think it could really help those who have automation scripts in their repositories and are looking for an easy way to get it into the hands of an extended team with some additional features like authentication.

For teams just getting started (Gemini Maturity Model for those who made it through my session at AutoCon1), it is absolutely worth a look so you can try to avoid my sorry saga of "sharing scripts".

Now, let's take torero_image for a test drive!


Installation

Installation (untarring really... remember its a binary) was uneventful on a Linux VM as well as on an Apple M1.

claudia@Claudias-Mac-mini-m1 torero % curl https://download.torero.dev/torero-1.0.0_darwin_arm64.tar.gz --output torero-1.0.0_darwin_arm64.tar.gz
claudia@Claudias-Mac-mini-m1 torero % tar -zxvf torero-1.0.0_darwin_arm64.tar.gz
x torero
claudia@Claudias-Mac-mini-m1 torero % ./torero
the logging directory at /Users/claudia/.torero.d does not exist. Creating the directory now
Please read the license at: https://torero.dev/licenses/eula
Do you agree to the EULA? (yes/no): yes
License accepted. Thank You!
Welcome to torero
Application Mode: local

Usage:
  torero [command]

Resource Commands:
  create       Create a resource
  delete       Delete a resource
  describe     Display all details about a resource
  get          Display information about all resources of a certain type

Runner Commands:
  run          Run an automation service

Other Commands:
  completion   Generate shell completion scripts for [bash|zsh|fish]
  export       Export resources/services to a service file
  hostkeys     Manage remote system ssh host keys
  import       Import resources/services from a service file
  version      Shows the current version of torero

Flags:
      --config       Path to the configuration file
  -h, --help         help for torero
      --raw          Displays the result of the command in its raw format
      --verbose      Enable verbose output

Use "torero [command] --help" for more information about a command.

Find more information at: https://torero.dev/
claudia@Claudias-Mac-mini-m1 torero %

On a Windows 10 system using WSL there was just one installation hiccup with the python venv installation which is documented in the WSL sidebar below.

Its important to note that a .torero.d directory will be created in your home directory. This is a good place for the torero configuration file should you need one. You will need one to move to client/server mode.

By default, this is what you will see in your ~/.torero.d directory.

claudia@Claudias-Mac-mini-m1 torero % ls -al ~/.torero.d
total 264
drwxr-xr-x   5 claudia  staff     160 Jul 14 15:27 .
drwxr-x---+ 44 claudia  staff    1408 Jul 14 15:27 ..
-rw-r--r--   1 claudia  staff       0 Jul 14 15:27 .license-accepted
-rw-------   1 claudia  staff  131072 Jul 14 15:27 torero.db
-rw-r--r--   1 claudia  staff      53 Jul 14 15:27 torero.log
claudia@Claudias-Mac-mini-m1 torero %

To view the default configuration:

claudia@awx:~/.torero.d$ torero version --show-config

Setup

Local Mode

By default, the base installation is in 'local' mode. If thats all you need, you are all set. In this introduction we will focus on local mode.

Client/Server Mode

Check out this post for a quick example of torero in client/server mode.

Execution

Local Mode

I started with a fairly basic existing repository. I wanted to see how easy it would be to just overlay torero on an existing GitHub repository. I ran into a few issues. Some were around the repo itself and how I built the scripts and some I'm still trying to debug. I wound up having to simplify the scripts.

It was a great learning experience in debugging. Debugging is not well covered in the documentation so I've noted options in the resources section below. Got great and almost immediate community support.

The workflow follows three basic steps.

  1. Register the repository

  2. Create a service out of one of the scripts in the repository

  3. Execute or run the service

Tip:
After setting up torero in client/server mode and logging in, you can continue working in torero as though you were in local mode so the steps above apply.

Register your repository

In this case I am using the simplest form, a public GitHub repository. For a private repository you will need to set up Git Hub access and that is covered in the current documentation.

./torero create repository client-discovery-repo  --description "Client Discovery Simplified GitHub Repository" --url https://github.com/cldeluna/client_discovery_simple.git --reference main
claudia@DESKTOP-S41OCM2:~/WSL/torero$ ./torero create repository client-discovery-repo  --description "Client Discovery GitHub Repository" --url https://github.com/cldeluna/client_discovery.git --reference main
Successfully created the repository

Name:             client-discovery-repo
Description:      Client Discovery GitHub Repository
Url:              https://github.com/cldeluna/client_discovery.git
Reference:        main
Tags:
Private Key Name:

claudia@DESKTOP-S41OCM2:~/WSL/torero$ ./torero get repositories
NAME                    DESCRIPTION                          URL                                                REFERENCE   TAGS    PRIVATE KEY NAME
client-discovery-repo   Client Discovery GitHub Repository   https://github.com/cldeluna/client_discovery.git   main    
example-scripts-repo    Simple repository for quick start    https://github.com/torerodev/example-scripts.git   main    

claudia@DESKTOP-S41OCM2:~/WSL/torero$

Tip:

To remove the repository:

claudia@DESKTOP-S41OCM2:~/WSL/torero$ ./torero delete repository client-discovery-repo
Successfully deleted the repository 'client-discovery-repo' 

To check repositories:

claudia@Claudias-Mac-mini-m1 torero % ./torero get repositories
NAME                    DESCRIPTION                                     URL                                                  REFERENCE   TAGS    PRIVATE KEY NAME
client-discovery-repo   Client Discovery Simplified GitHub Repository   https://github.com/cldeluna/client_discovery_simp…   main

Create a service

./torero create python-script seed_devlist --repository client-discovery-repo --filename seed_devlist.py  --description "Create inventory from seed device"  --verbose
./torero create python-script get-show-commands --repository client-discovery-repo --filename get_showcmds.py --description "Get show commands from one or more devices"  --verbose

Tip:
The --working-dir argument is used to tell torero where in the repo to find your script if you want to point to it directly. It is not the directory to execute from.

Example on Windows with WSL:

claudia@DESKTOP-S41OCM2:~/WSL/torero$ ./torero create python-script seed_devlist --repository client-discovery-repo --filename seed_devlist.py  --description "Create inventory from seed device"  --verbose
2024-07-14T20:14:54Z INF no configuration file found
2024-07-14T20:14:54Z INF using local connection
Successfully created the Python script

Name:        seed_devlist
Repo Name:   client-discovery-repo
Working Dir:
File Name:   seed_devlist
Decorator:
Description: Create inventory from seed device
Tags: 

Example on MAC:

claudia@Claudias-Mac-mini-m1 torero % ./torero create python-script get-show-commands --repository client-discovery-repo --filename get_showcmds.py --description "Get show commands from one or more devices"  --verbose
2024-07-15T19:06:52Z INF no configuration file found
2024-07-15T19:06:53Z INF using local connection
2024-07-15T19:06:53Z DBG Getting store's value for key 'services/v1/python-script/get-show-commands'
2024-07-15T19:06:53Z DBG Putting value in store for key 'services/v1/python-script/get-show-commands'
Successfully created the Python script

Name:        get-show-commands
Repo Name:   client-discovery-repo
Working Dir:
File Name:   get_showcmds.py
Decorator:
Description: Get show commands from one or more devices
Tags:

Tip:

To remove the service

claudia@Claudias-Mac-mini-m1 torero % ./torero delete python-script seed_devlist

To check services:

claudia@Claudias-Mac-mini-m1 torero % ./torero get services
claudia@Claudias-Mac-mini-m1 torero % ./torero get python-scripts

Steps 1 and 2 were straightforward and basically effortless.

claudia@Claudias-Mac-mini-m1 torero % ./torero get repositories
NAME                    DESCRIPTION                                     URL                                                  REFERENCE   TAGS    PRIVATE KEY NAME
client-discovery-repo   Client Discovery Simplified GitHub Repository   https://github.com/cldeluna/client_discovery_simp…   main

claudia@Claudias-Mac-mini-m1 torero % ./torero get services
NAME                TYPE            CREATED
get-show-commands   python-script   2024-07-15T19:06:53Z

claudia@Claudias-Mac-mini-m1 torero % ./torero get python-scripts
NAME                REPO NAME               WORKING DIR   FILE NAME         DESCRIPTION                                  TAGS
get-show-commands   client-discovery-repo                 get_showcmds.py   Get show commands from one or more devices

claudia@Claudias-Mac-mini-m1 torero %

Execution (Run the Service)

Note that the first time you run the service it will take a few minutes to set everything up. After that, if hashes remain unchanged (your repository is unchanged), it will run noticeably faster.

./torero run python-script get-show-commands --verbose

My first attempt at the execution step was problematic and understanding where to go for community support took some digging and reaching out but support is certainly there and you can find out more information in the Resources section.

The simplified version of the repo executed flawlessly but I have some re-structuring to do. In its native form, I set paths in environment variables but the paths in torero are ephemeral so I need to re-think that. I also save the output either in a local directory or in a path provided via a command line argument. Passing arguments require that they be exposed via decorators so its a bit more complex and I tend to offer lots of arguments so I'll need to re-think that as well.

Saving in the local directory is a bad idea as it goes away after the run so all my saved show command output was deleted.

Here is the complete output (with logging set to DEBUG via an environment variable). Pretty impressive as you see all the steps you normally do manually zip by.

I was able to run my "get show commands" service from the simplified repository on my Mac, a Linux VM, and Windows with WSL!

claudia@Claudias-Mac-mini-m1 torero % ./torero run python-script get-show-commands --verbose
2024-07-15T19:08:51Z INF no configuration file found
2024-07-15T19:08:51Z INF using local connection
2024-07-15T19:08:51Z DBG Getting store's value for key 'services/v1/python-script/get-show-commands'
2024-07-15T19:08:51Z DBG Getting store's value for key 'repository/v1/repository/client-discovery-repo'
2024-07-15T19:08:51Z DBG source repository url is https://github.com/cldeluna/client_discovery_simple.git
2024-07-15T19:08:51Z DBG source reference is main
2024-07-15T19:08:51Z DBG uri schema is https
2024-07-15T19:08:51Z DBG setting environment variable UserKnownHostsFile to /Users/claudia/.torero.d/known_hosts
2024-07-15T19:08:51Z DBG running command 'ssh-keyscan github.com'
2024-07-15T19:08:52Z DBG command exit status: 0, execution time: 945.800084ms
2024-07-15T19:08:52Z DBG host key for host 'github.com' and key type 'ssh-rsa' with a matching fingerprint already exists in known_hosts. Skipping...
2024-07-15T19:08:52Z DBG host key for host 'github.com' and key type 'ecdsa-sha2-nistp256' with a matching fingerprint already exists in known_hosts. Skipping...
2024-07-15T19:08:52Z DBG host key for host 'github.com' and key type 'ssh-ed25519' with a matching fingerprint already exists in known_hosts. Skipping...
2024-07-15T19:08:53Z DBG clone repository completed successfully to /var/folders/85/_v894yd15475q6j70pb173800000gn/T/tmp1138342025
2024-07-15T19:08:53Z DBG target is /var/folders/85/_v894yd15475q6j70pb173800000gn/T/tmp1138342025
2024-07-15T19:08:53Z DBG attempting to find python interpreter
2024-07-15T19:08:53Z DBG found python interpreter /usr/bin/python3
2024-07-15T19:08:53Z DBG no virtual environment for these requirements exists yet. Installing virtual environment at '/Users/claudia/.torero.d/venv/abbae2cd86c12e6ec2c99d355e45ea6abd996897'
2024-07-15T19:08:53Z DBG running command '/usr/bin/python3 -m venv /Users/claudia/.torero.d/venv/abbae2cd86c12e6ec2c99d355e45ea6abd996897'
2024-07-15T19:08:55Z DBG command exit status: 0, execution time: 2.490702125s
2024-07-15T19:08:55Z DBG venv creation succeeded.
Stdout:

Stderr:

2024-07-15T19:08:55Z DBG running command '/usr/bin/python3 --version'
2024-07-15T19:08:55Z DBG command exit status: 0, execution time: 10.342167ms
2024-07-15T19:08:55Z DBG running command '/Users/claudia/.torero.d/venv/abbae2cd86c12e6ec2c99d355e45ea6abd996897/bin/pip3 install -r /Users/claudia/.torero.d/venv/abbae2cd86c12e6ec2c99d355e45ea6abd996897/requirements.txt'
2024-07-15T19:09:00Z DBG command exit status: 0, execution time: 4.984422084s
2024-07-15T19:09:00Z DBG pip dependency install succeeded.
Stdout:
Collecting netmiko==4.4.0
  Using cached netmiko-4.4.0-py3-none-any.whl (232 kB)
Collecting numpy==2.0.0
  Using cached numpy-2.0.0-cp39-cp39-macosx_11_0_arm64.whl (13.3 MB)
Collecting python-dotenv==1.0.1
  Using cached python_dotenv-1.0.1-py3-none-any.whl (19 kB)
Collecting PyYAML==6.0.1
  Using cached PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl (174 kB)
Collecting pyserial>=3.3
  Using cached pyserial-3.5-py2.py3-none-any.whl (90 kB)
Collecting scp>=0.13.6
  Using cached scp-0.15.0-py2.py3-none-any.whl (8.8 kB)
Collecting ntc-templates>=3.1.0
  Using cached ntc_templates-5.1.0-py3-none-any.whl (450 kB)
Collecting cffi>=1.17.0rc1
  Using cached cffi-1.17.0rc1-cp39-cp39-macosx_11_0_arm64.whl (178 kB)
Collecting paramiko>=2.9.5
  Using cached paramiko-3.4.0-py3-none-any.whl (225 kB)
Collecting textfsm>=1.1.3
  Using cached textfsm-1.1.3-py2.py3-none-any.whl (44 kB)
Collecting setuptools>=65.0.0
  Using cached setuptools-70.3.0-py3-none-any.whl (931 kB)
Collecting pycparser
  Using cached pycparser-2.22-py3-none-any.whl (117 kB)
Collecting cryptography>=3.3
  Using cached cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl (5.9 MB)
Collecting bcrypt>=3.2
  Using cached bcrypt-4.1.3-cp39-abi3-macosx_10_12_universal2.whl (506 kB)
Collecting pynacl>=1.5
  Using cached PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl (349 kB)
Collecting six
  Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting future
  Using cached future-1.0.0-py3-none-any.whl (491 kB)
Installing collected packages: pycparser, cffi, six, pynacl, future, cryptography, bcrypt, textfsm, paramiko, setuptools, scp, PyYAML, pyserial, ntc-templates, python-dotenv, numpy, netmiko
  Attempting uninstall: setuptools
    Found existing installation: setuptools 58.0.4
    Uninstalling setuptools-58.0.4:
      Successfully uninstalled setuptools-58.0.4
Successfully installed PyYAML-6.0.1 bcrypt-4.1.3 cffi-1.17.0rc1 cryptography-42.0.8 future-1.0.0 netmiko-4.4.0 ntc-templates-5.1.0 numpy-2.0.0 paramiko-3.4.0 pycparser-2.22 pynacl-1.5.0 pyserial-3.5 python-dotenv-1.0.1 scp-0.15.0 setuptools-70.3.0 six-1.16.0 textfsm-1.1.3

Stderr:
WARNING: You are using pip version 21.2.4; however, version 24.1.2 is available.
You should consider upgrading via the '/Users/claudia/.torero.d/venv/abbae2cd86c12e6ec2c99d355e45ea6abd996897/bin/python3 -m pip install --upgrade pip' command.

2024-07-15T19:09:00Z DBG virtual environment path is '/Users/claudia/.torero.d/venv/abbae2cd86c12e6ec2c99d355e45ea6abd996897'
2024-07-15T19:09:00Z DBG running command '/Users/claudia/.torero.d/venv/abbae2cd86c12e6ec2c99d355e45ea6abd996897/bin/python /var/folders/85/_v894yd15475q6j70pb173800000gn/T/tmp1138342025/get_showcmds.py'
2024-07-15T19:09:06Z DBG command exit status: 0, execution time: 5.638709958s
Start Time:   2024-07-15T19:08:51Z
End Time:     2024-07-15T19:09:06Z
Elapsed Time: 14.782267s
Return Code:  0
Stdout:
===== Date is 2024-07-15 ====
Directory  local  Created

===============  Device 10.1.10.66 ===============
--- Show Command: term len 0
--- Show Command: show run
--- Show Command: show version
--- Show Command: show inventory
--- Show Command: show cdp nei
--- Show Command: show cd nei det
--- Show Command: show vlan
--- Show Command: show spanning-tree
--- Show Command: show spanning-tree root priority system-id
--- Show Command: show int
--- Show Command: show int status
--- Show Command: show int trunk
--- Show Command: show ip int br
--- Show Command: show ip arp
--- Show Command: show mac address-table
--- Show Command: show etherchannel sum
--- Show Command: show vrf
--- Show Command: show ip route
--- Show Command: show swi
--- Show Command: dir
--- Show Command: show boot system

Saving show command output to /private/var/folders/85/_v894yd15475q6j70pb173800000gn/T/tmp1138342025/local/10.1.10.66_2024-07-15.txt

Stderr:

claudia@Claudias-Mac-mini-m1 torero % ls /private/var/folders/85/_v894yd15475q6j70pb173800000gn/T/tmp1138342025/local
ls: /private/var/folders/85/_v894yd15475q6j70pb173800000gn/T/tmp1138342025/local: No such file or directory
claudia@Claudias-Mac-mini-m1 torero %

Minor code change to set the output directory to a directory under the users home (~) directory did the trick.

claudia@Claudias-Mac-mini-m1 torero % ./torero run python-script get-show-commands --verbose
Start Time:   2024-07-15T19:50:44Z
End Time:     2024-07-15T19:50:51Z
Elapsed Time: 6.180845s
Return Code:  0
Stdout:
===== Date is 2024-07-15 ====
Directory  /Users/claudia/show_output  Created

===============  Device 10.1.10.66 ===============
--- Show Command: term len 0
--- Show Command: show run
--- Show Command: show version
--- Show Command: show inventory
--- Show Command: show cdp nei
--- Show Command: show cd nei det
--- Show Command: show vlan
--- Show Command: show spanning-tree
--- Show Command: show spanning-tree root priority system-id
--- Show Command: show int
--- Show Command: show int status
--- Show Command: show int trunk
--- Show Command: show ip int br
--- Show Command: show ip arp
--- Show Command: show mac address-table
--- Show Command: show etherchannel sum
--- Show Command: show vrf
--- Show Command: show ip route
--- Show Command: show swi
--- Show Command: dir
--- Show Command: show boot system

Saving show command output to /Users/claudia/show_output/10.1.10.66_2024-07-15.txt

Stderr:

claudia@Claudias-Mac-mini-m1 torero % ls ~/show_output
10.1.10.66_2024-07-15.txt
claudia@Claudias-Mac-mini-m1 torero %

Debugging Levels

You can increase the logging level to get more details. Easiest way to do that is to set the environment variable TORERO_LOG_LEVEL to the logging level you want (DEBUG in my case).

Supported logging levels include:

  • TRACE
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL
  • DISABLED

Tips:

To set your log level:

claudia@Claudias-Mac-mini-m1 torero % export TORERO_LOG_LEVEL=DEBUG

To check your log level:

claudia@Claudias-Mac-mini-m1 torero % echo $TORERO_LOG_LEVEL

To clear out your virtual environments (assuming the default installation location):

claudia@Claudias-Mac-mini-m1 torero % rm -rf ~/.torero.d/venv

Resources

The best resource so far, apart from the torero site itself, is the LinkedIn page which has links to some basic YouTube videos.

For more interactive community support go to the NAF (Network Automation Forum) slack channel at hashtag#tools-torero.

If you are reading this then you are clearly interested in automating your network infrastructure so you should join the NAF community immediately if not sooner!

If you are interested in checking out torero in client/server mode please see La Corrida de Torero - torero in client/server mode.


Windows Subsystem for Linux (WSL) Sidebar

Had a few issues completing the installation and successful execution on WSL. Specifically, meeting the python venv module requirement (also true on my Linux VM )

Encountered this error on both a Linux VM running Ubuntu 22.04 and WSL.

On the Linux VM, no problem.

However on WSL, the sudo apt install python3.10-venv command errored out. The commands below allowed me to complete the installation and run the script.

# The following three commands executed in the WSL Ubuntu 22.04 shell on my Windows system worked
sudo apt-get update
sudo apt install python3-dev
sudo apt install python3-venv

Complete log of WSL commands

Enviornment: WSL Version 2 running Ubuntu 22.04 image

    4  mkdir WSL
    5  cd WSL/
    6  ls
    7  mkdir torero
    8  cd torero
    9  curl https://download.torero.dev/torero-1.0.0_linux_amd64.tar.gz --output torero-1.0.0_linux_amd64.tar.gz
   10  ls
   15  tar -zxvf torero-1.0.0_linux_amd64.tar.gz
   16  ls
   17  ./torero
   18  ls
   21  ./torero version
   22  ./torero create repository example-scripts-repo --description "Simple repository for quick start" --url https://github.com/torerodev/example-scripts.git --reference main
   23  ./torero get repositories
   24  ./torero describe repository example-scripts-repo
   25  ./torero create python-script hello-torero --repository example-scripts-repo --filename hello-torero.py  --description "Quick Start Example"
   26  ./torero run python-script hello-torero
   27  sudo apt install python3.10-venv # Did not WORK! The ./torero run command failed because python3.10-venv was needed
   29  python3 -V
   30  # The following three commands executed in the WSL Ubuntu 22.04 shell on my Windows system worked
   32  sudo apt-get update
   33  sudo apt install python3-dev
   34  sudo apt install python3-venv
   35  ./torero run python-script hello-torero # NOW this executed succesfully