Skip to content

Commit

Permalink
Added targeting of multiple groups and devices through a new 'keyword'
Browse files Browse the repository at this point in the history
Through a new sorting method, all cool and logically formatted.
  • Loading branch information
DaanSelen authored Feb 13, 2025
2 parents ad220e8 + 4f75969 commit 0368397
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 40 deletions.
54 changes: 28 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,41 @@ To install, follow the following commands:<br>

### Linux setup:

```shell
```bash
git clone https://github.com/daanselen/meshbook
cd ./meshbook
python3 -m venv ./venv
source ./venv/bin/activate
pip3 install -r ./requirements.txt
cp ./templates/meshcentral.conf.template ./meshcentral.conf
```

### Windows setup:
### Windows setup (PowerShell, not cmd):

```shell
git clone https://github.com/daanselen/meshbook
cd ./meshbook
python3 -m venv ./venv
python -m venv ./venv # or python3 when done through the Microsoft Store.
.\venv\Scripts\activate # Make sure to check the terminal prefix.
pip3 install -r ./requirements.txt
cp .\templates\meshcentral.conf.template .\meshcentral.conf
```

Now copy the configuration template from ./templates and fill it in with the correct details. The url should start with `wss://`.<br>
Now copy the configuration template from ./templates and fill it in with the correct details (remove .template from the file) this is shown in the last step of the setup(s).<br>
The url should start with `wss://`.<br>
You can check pre-made examples in the examples directory, make sure the values are set to your situation.<br>
After this you can use meshbook, for example:

### Linux run:

```shell
```bash
python3 .\meshbook.py -pb .\examples\echo.yaml
```

### Windows run:

```shell
.\venv\Scripts\python.exe .\meshbook.py -pb .\examples\echo.yaml
.\venv\Scripts\python.exe .\meshbook.py -pb .\examples\echo_example.yaml
```

### How to check if everything is okay?
Expand Down Expand Up @@ -80,6 +84,7 @@ So to target for example a mesh/group in MeshCentral called: "Nerthus" do:
---
name: example configuration
group: "Nerthus"
#target_os: "Linux" # <--- according to os_categories.json
variables:
- name: var1
value: "This is the first variable"
Expand Down Expand Up @@ -118,6 +123,7 @@ You can expand the command chain as follows:<br>
---
name: Echo a string to the terminal through the meshbook example.
group: "Dev"
#target_os: "Linux" # <--- according to os_categories.json
variables:
- name: file
value: "/etc/os-release"
Expand All @@ -129,34 +135,30 @@ tasks:
The following response it received when executing the first yaml of the above files (without the `-s` parameters, which just outputs the below JSON).

```shell
python3 meshbook.py -pb examples/echo_example.yaml
~/meshbook$ python3 meshbook.py -pb examples/echo_example.yaml
----------------------------------------
Playbook: examples/echo_example.yaml
Operating System Categorisation file: ./os_categories.json
Congiguration file: ./meshcentral.conf
Target group: Development
Grace: True
Silent: False
----------------------------------------
Trying to load the MeshCentral account credential file...
Trying to load the Playbook yaml file and compile it into something workable...
Trying to load the Operating System categorisation JSON file...
Connecting to MeshCentral and establish a session using variables from previous credential file.
Generating group list with nodes and reference the targets from that.
----------------------------------------
Executing playbook on the targets.
Executing playbook on the target(s): Development.
Initiating grace-period...
1...
2...
3...
----------------------------------------
1. Running: Echo!
----------------------------------------
{
"Task 1": [
{
"complete": true,
"result": "PRETTY_NAME=\"Debian GNU/Linux 12 (bookworm)\" NAME=\"Debian GNU/Linux\" VERSION_ID=\"12\" VERSION=\"12 (bookworm)\" VERSION_CODENAME=bookworm ID=debian HOME_URL=\"https://www.debian.org/\" SUPPORT_URL=\"https://www.debian.org/support\" BUG_REPORT_URL=\"https://bugs.debian.org/\"\n",
"command": "echo $(cat /etc/os-release)",
"device_id": "<Node-Unique>",
"device_name": "raspberrypi5"
},
{
"complete": true,
"result": "PRETTY_NAME=\"Debian GNU/Linux 12 (bookworm)\" NAME=\"Debian GNU/Linux\" VERSION_ID=\"12\" VERSION=\"12 (bookworm)\" VERSION_CODENAME=bookworm ID=debian HOME_URL=\"https://www.debian.org/\" SUPPORT_URL=\"https://www.debian.org/support\" BUG_REPORT_URL=\"https://bugs.debian.org/\"\n",
"command": "echo $(cat /etc/os-release)",
"device_id": "<Node-Unique>",
"device_name": "Cubic"
}
]
}
{"Task 1": "ALL THE DATA"} # Not sharing due to PID
```
The above without `-s` is quite verbose. use `--help` to read about parameters and getting a minimal response for example.

Expand Down
Binary file removed assets/meshbook_yaml_os.png
Binary file not shown.
Binary file removed assets/meshcentral_os.png
Binary file not shown.
3 changes: 2 additions & 1 deletion examples/apt_update_example.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: Refresh the apt cache
device: Cubic
device: "<Device-Name>"
#target_os: "Linux"
variables:
- name: package_manager
value: "apt"
Expand Down
1 change: 1 addition & 0 deletions examples/apt_upgrade_example.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: Refresh the apt cache
group: "Dev"
#target_os: "Linux"
variables:
- name: package_manager
value: "apt"
Expand Down
4 changes: 2 additions & 2 deletions examples/echo_example.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: Echo a string to the terminal through the meshbook example.
group: "Dev"
target_os: Debian GnU/Linux 12 (bookworm)
group: "Development"
target_os: "Linux"
variables:
- name: file
value: "/etc/os-release"
Expand Down
1 change: 1 addition & 0 deletions examples/variable_usage_example.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: Ping Multiple Points
group: "Kubernetes"
#target_os: "Debian"
variables:
- name: host1
value: "1.1.1.1"
Expand Down
67 changes: 56 additions & 11 deletions meshbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,21 +141,53 @@ async def gather_targets(playbook: dict, group_list: dict[str, list[dict]], os_c
target_list = []
target_os = playbook.get("target_os")

if "device" in playbook:
pseudo_target = playbook["device"]
async def process_device_or_group(pseudo_target, group_list, os_categories, target_os) -> list[str]:
"""Helper function to process devices or groups."""

matched_devices = []
for group in group_list:
for device in group_list[group]:
if device["device_name"] == pseudo_target:
matched_devices = await filter_targets([device], os_categories, target_os)
matched_devices.append(device)

if matched_devices:
return await filter_targets(matched_devices, os_categories, target_os)
return []

match playbook:
case {"device": pseudo_target}: # Single device target
if isinstance(pseudo_target, str):
matched_devices = await process_device_or_group(pseudo_target, group_list, os_categories, target_os)
target_list.extend(matched_devices)

else:
console("\033[91mPlease use devices (Notice the 'S') for multiple devices.\x1B[0m", True)

case {"devices": pseudo_target}: # List of devices
if isinstance(pseudo_target, list):
for sub_pseudo_device in pseudo_target:
matched_devices = await process_device_or_group(sub_pseudo_device, group_list, os_categories, target_os)
target_list.extend(matched_devices)

elif "group" in playbook:
pseudo_target = playbook["group"]
else:
console("\033[91mThe 'devices' method is being used, but only one string is given. Did you mean 'device'?\x1B[0m", True)

case {"group": pseudo_target}: # Single group target
if isinstance(pseudo_target, str) and pseudo_target in group_list:
matched_devices = await filter_targets(group_list[pseudo_target], os_categories, target_os)
target_list.extend(matched_devices)

else:
console("\033[91mPlease use groups (Notice the 'S') for multiple groups.\x1B[0m", True)

if pseudo_target in group_list:
matched_devices = await filter_targets(group_list[pseudo_target], os_categories, target_os)
target_list.extend(matched_devices)
case {"groups": pseudo_target}: # List of groups
if isinstance(pseudo_target, list):
for sub_pseudo_target in pseudo_target:
if sub_pseudo_target in group_list:
matched_devices = await filter_targets(group_list[sub_pseudo_target], os_categories, target_os)
target_list.extend(matched_devices)
else:
console("\033[91mThe 'groups' method is being used, but only one string is given. Did you mean 'group'?\x1B[0m", True)

return target_list

Expand Down Expand Up @@ -220,10 +252,10 @@ async def main():
console("Operating System Categorisation file: " + args.oscategories)
console("Congiguration file: " + args.conf)
if "device" in playbook:
console("Target device: " + playbook["device"])
console("Target device: " + str(playbook["device"]))

elif "group" in playbook:
console("Target group: " + playbook["group"])
console("Target group: " + str(playbook["group"]))

console("Grace: " + str((not args.nograce))) # Negation of bool for correct explanation
console("Silent: False") # Can be pre-defined because if silent flag was passed then none of this would be printed.
Expand All @@ -249,7 +281,20 @@ async def main():

else:
console(("-" * 40))
target_name = playbook["group"] if "group" in playbook else playbook["device"] # Quickly get the name.

match playbook:
case {"group": candidate_target_name}:
target_name = candidate_target_name

case {"groups": candidate_target_name}:
target_name = str(candidate_target_name)

case {"device": candidate_target_name}:
target_name = candidate_target_name

case {"devices": candidate_target_name}:
target_name = str(candidate_target_name)

console(("\033[91mExecuting playbook on the target(s): " + target_name + ".\x1B[0m"))

if not args.nograce:
Expand Down

0 comments on commit 0368397

Please sign in to comment.