From 415d1536fbbd9dd4e868319f0c0f62c8745265c4 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 23 Jun 2025 09:39:45 -0700 Subject: [PATCH] init commit --- README.md | 3 + defaults/main.yaml | 44 ++++++++++++++ files/lldp-api.py | 47 +++++++++++++++ files/lldp-scan.py | 34 +++++++++++ tasks/lldp.yaml | 105 ++++++++++++++++++++++++++++++++++ tasks/main.yaml | 37 ++++++++++++ tasks/onboard.yaml | 28 +++++++++ tasks/purge-defaults.yaml | 15 +++++ templates/project_template.j2 | 5 ++ templates/service_template.j2 | 15 +++++ 10 files changed, 333 insertions(+) create mode 100644 README.md create mode 100644 defaults/main.yaml create mode 100644 files/lldp-api.py create mode 100644 files/lldp-scan.py create mode 100644 tasks/lldp.yaml create mode 100644 tasks/main.yaml create mode 100644 tasks/onboard.yaml create mode 100644 tasks/purge-defaults.yaml create mode 100644 templates/project_template.j2 create mode 100644 templates/service_template.j2 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7ca099b --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +Playbooks for the Pi-Top + +Right now there's just the LLDP Scanner diff --git a/defaults/main.yaml b/defaults/main.yaml new file mode 100644 index 0000000..034d379 --- /dev/null +++ b/defaults/main.yaml @@ -0,0 +1,44 @@ +--- + +lldp_packages: + - lldpd + - ethtool + - dbus-user-session + - curl + +default_projects: + - "electronics" + - "pi_top_4" + - "robotics" + +project_path: "/usr/lib/python3/dist-packages/pt_miniscreen/demo_projects" + +archive_path: "/opt/pi-top/archive/projects" + +api_working_dir: "/var/lib/lldp-api" + +lldp_project_working_dir: "/home/{{ admin_username }}/Desktop/Projects/lldp-scan" + +admin_username: pi + +pi_default_password: "pi-top" + +kde_full: false + +rename_host: false + +install_packages: false + +config_smb: true + +save_pi_user: true + +public_deploy: true + +update_grub_timeout: false + +gather_only: false + +deb_base: false + +... \ No newline at end of file diff --git a/files/lldp-api.py b/files/lldp-api.py new file mode 100644 index 0000000..8182095 --- /dev/null +++ b/files/lldp-api.py @@ -0,0 +1,47 @@ +import requests +import subprocess +from lxml import html +from flask import Flask, request, jsonify +import json +from datetime import datetime + +app = Flask(__name__) + +@app.route('/test', methods=['GET']) +def test(): + return {"message": "Hello There"} + +@app.route('/data', methods=['GET']) +def get_data(): + return get_lldp_data() + +def get_lldp_data(): + # Set commands here + commands = { + "switch_name": "lldpcli show neighbors | grep SysName | cut -d ':' -f 2 | tr -d ' '", + "port_name": "lldpcli show neighbors | grep PortDes | cut -d ':' -f 2 | tr -d ' '", + "port_speed": "ethtool eth0 | grep Speed | cut -d ':' -f 2 | tr -d ' '", + "vlan_id": "lldpcli show neighbors details | grep VLAN | cut -d ':' -f 2 | cut -d ',' -f 1 | tr -d ' '" + } + + # Create an empty dictionary to store the results + results = {} + # Loop through the commands, run them, and store the output in the results dictionary + for key, command in commands.items(): + try: + # Run the command and capture the output + result = subprocess.run(command, shell=True, capture_output=True, text=True) + + # Store the output in the dictionary, removing any trailing newlines + results[key] = result.stdout.strip() + except Exception as e: + # Handle any errors by storing the error message in the results + results[key] = f"Error: {str(e)}" + results['timestamp'] = datetime.now().strftime("%H:%M:%S") + # Convert the results dictionary to a JSON string + # json_output = + return json.dumps(results, indent=4) + +if __name__ == '__main__': + app.run(debug=True, host='127.0.0.1', port=5000) + \ No newline at end of file diff --git a/files/lldp-scan.py b/files/lldp-scan.py new file mode 100644 index 0000000..5df0d28 --- /dev/null +++ b/files/lldp-scan.py @@ -0,0 +1,34 @@ +import requests +import json +from time import sleep +from pitop import Pitop + +pitop = Pitop() +miniscreen = pitop.miniscreen +miniscreen.display_multiline_text("Welcome to LLDP Scanner", font_size=14) +sleep (1) + +while not miniscreen.cancel_button.is_pressed: + # Query LLDP API + api_response = requests.get("http://127.0.0.1:5000/data") + api_data = api_response.json() + port_name = api_data['port_name'] + port_speed = api_data['port_speed'] + switch_name = api_data['switch_name'] + vlan_id = api_data['vlan_id'] + lldp_timestamp = api_data['timestamp'] + + # Display LLDP data + miniscreen.display_multiline_text(f"LLDP Scan Taken {lldp_timestamp}", font_size=14) + sleep(4) + miniscreen.display_multiline_text(f"Port Name: {port_name}", font_size=12) + sleep(4) + miniscreen.display_multiline_text(f"Port Speed: {port_speed}", font_size=12) + sleep(4) + miniscreen.display_multiline_text(f"Switch Name: {switch_name}", font_size=12) + sleep(4) + miniscreen.display_multiline_text(f"VLAN ID: {vlan_id}", font_size=12) + sleep(4) + +miniscreen.display_multiline_text("Ending Application", font_size=14) +sleep(2) \ No newline at end of file diff --git a/tasks/lldp.yaml b/tasks/lldp.yaml new file mode 100644 index 0000000..c745146 --- /dev/null +++ b/tasks/lldp.yaml @@ -0,0 +1,105 @@ +--- + +# Install Packages +- name: prereqs - install apt packages + apt: + name: "{{ item }}" + state: present + loop: "{{ lldp_packages }}" + +############################################### +# LLDP Python api +############################################### + +- name: LLDP API + block: + + # Create API Folder + - name: lldp - api - create api folder + file: + path: "{{ api_working_dir }}" + state: directory + mode: '0755' + + # Copy API Code + - name: lldp - api - copy api code + copy: + src: lldp-api.py + dest: "{{ api_working_dir }}/app.py" + mode: 0644 + + # Create lldp-api python service + - name: lldp - api - create service file + vars: + exec_start: "python3 {{ api_working_dir }}/app.py" + svc_desc: "LLDP API" + working_dir: "{{ api_working_dir }}" + template: + src: service_template.j2 + dest: /etc/systemd/system/lldp_api.service + mode: 0644 + + # enable and start lldp service + - name: lldp - Restart LLDP service + service: + name: lldpd + state: restarted + enabled: yes + + # daemon reload + - name: lldp - api - daemon reload + systemd: + daemon_reload: yes + + # Enable and start + - name: lldp - api - enable and start api + systemd: + name: lldp_api.service + state: started + enabled: yes + + # Test + - name: lldp - api - test + shell: "curl -S 'http://127.0.0.1:5000/data'" + register: api_test + + # Show test results + - name: lldp - api - show result + debug: + msg: "{{ api_test.stdout }}" + +############################################### +# LLDP Project +############################################### + + # Create working dir + - name: LLDP Project - Create Working Directory + file: + path: "{{ lldp_project_working_dir }}" + state: directory + owner: "{{ admin_username }}" + group: "{{ admin_username }}" + mode: '0755' + + # Copy python code + - name: LLDP Project - copy app code + copy: + src: lldp-scan.py + dest: "{{ lldp_project_working_dir }}/app.py" + owner: "{{ admin_username }}" + group: "{{ admin_username }}" + mode: 0644 + + # Copy project file + - name: LLDP Project - copy project code + vars: + project_title: "LLDP Scanner" + working_dir: "{{ lldp_project_working_dir }}" + template: + src: project_template.j2 + dest: "{{ lldp_project_working_dir }}/project.cfg" + owner: "{{ admin_username }}" + group: "{{ admin_username }}" + mode: 0644 + +... \ No newline at end of file diff --git a/tasks/main.yaml b/tasks/main.yaml new file mode 100644 index 0000000..64b11a4 --- /dev/null +++ b/tasks/main.yaml @@ -0,0 +1,37 @@ +--- + +- name: Check for pi user + shell: "getent passwd | grep pi" + register: pi_user_output + ignore_errors: true + +- name: Set pi_user_exists + set_fact: + pi_user_exists: "{{ not pi_user_output.failed | bool }}" + +- name: Create pi user + when: not pi_user_exists | bool + user: + name: "pi" + password: "{{ pi_default_password | password_hash('sha512') }}" + shell: /bin/bash + +- name: Check for pi-top platform + shell: pi-top --help + register: pitop_output + ignore_errors: true + +- name: Set deb_base + set_fact: + deb_base: true + when: pitop_output.failed + ignore_errors: true + +- name: Onboard if base debian + include_tasks: onboard.yaml + when: deb_base + +- name: Install the requested project + include_tasks: "{{ function }}.yaml" + +... \ No newline at end of file diff --git a/tasks/onboard.yaml b/tasks/onboard.yaml new file mode 100644 index 0000000..7897df3 --- /dev/null +++ b/tasks/onboard.yaml @@ -0,0 +1,28 @@ +--- + +# Install prereq new APT source +- name: prereqs - install apt packages + apt: + name: pi-top-os-apt-source + state: present + +# update APT with new source +- name: Update APT + apt: + update_cache: yes + +# Install pi-top platform +- name: Install Pi-Top Platform - Will take less than 10 minutes + apt: + name: + - pt-device-support + state: present + +# Install postreq OS utilities needed for user projects +- name: postreqs - full OS install, will take 15 minutes or so + apt: + name: pt-os + state: present + + +... \ No newline at end of file diff --git a/tasks/purge-defaults.yaml b/tasks/purge-defaults.yaml new file mode 100644 index 0000000..6122713 --- /dev/null +++ b/tasks/purge-defaults.yaml @@ -0,0 +1,15 @@ +--- + +- name: Create the purge path + file: + path: "{{ archive_path }}" + state: directory + mode: '0755' + +- name: Move default projects + shell: | + mv {{ project_path }}/{{ item }} {{ archive_path }} + ignore_errors: true + loop: "{{ default_projects }}" + +... \ No newline at end of file diff --git a/templates/project_template.j2 b/templates/project_template.j2 new file mode 100644 index 0000000..ac19fe7 --- /dev/null +++ b/templates/project_template.j2 @@ -0,0 +1,5 @@ +[project] +title={{ project_title }} +start=python3 -B app.py +exit_condition=HOLD_CANCEL + diff --git a/templates/service_template.j2 b/templates/service_template.j2 new file mode 100644 index 0000000..204175d --- /dev/null +++ b/templates/service_template.j2 @@ -0,0 +1,15 @@ + +[Unit] +Description={{ svc_desc }} +After=network.target + +[Service] +User=root +Group=root +WorkingDirectory={{ working_dir }} +ExecStartPre=/bin/sleep 5 +ExecStart={{ exec_start }} +Restart=always + +[Install] +WantedBy=multi-user.target