From 211930cde395aea9f65b5d5cbf0d9276cb35520e Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 28 Jul 2025 06:21:45 -0700 Subject: [PATCH] all working i think --- {files => archive}/app.py | 0 .../docker-compose-node.yaml.j2 | 0 archive/gsysctl.yaml | 80 +++++++ .../image_refresh_node/Dockerfile | 0 .../image_refresh_node/package.json | 0 .../image_refresh_node/server.js | 0 archive/index.php.old | 39 ++++ archive/js_site/app.js | 58 +++++ archive/js_site/index.php | 19 ++ archive/js_site/style.css | 26 +++ {tasks => archive}/photo_refresh copy.yaml | 0 {templates => archive}/record_snapshots.sh.j2 | 0 defaults/main.yaml | 40 +++- files/service_control_api/app.py | 85 ++++++++ files/service_control_api/website/index.php | 203 ++++++++++++++++++ files/service_control_api/website/styles.css | 80 +++++++ tasks/chrome.yaml | 35 +++ tasks/cosmos_autologin.yaml | 19 +- tasks/gps_service.yaml | 10 - tasks/kiosk.yaml | 63 +++--- tasks/main.yaml | 41 ++-- tasks/photo_refresh.yaml | 6 + tasks/service_control.yaml | 135 ++++++++++++ tasks/timelapse.yaml | 22 -- tasks/ustreamer.yaml | 8 - templates/chrome-app.service.j2 | 12 +- templates/create_timelapse.sh.j2 | 7 +- templates/docker-compose-php.yaml.j2 | 8 +- templates/service_control.service.j2 | 15 ++ templates/timelapse_service.sh.j2 | 6 +- 30 files changed, 900 insertions(+), 117 deletions(-) rename {files => archive}/app.py (100%) rename {templates => archive}/docker-compose-node.yaml.j2 (100%) create mode 100644 archive/gsysctl.yaml rename {files => archive}/image_refresh_node/Dockerfile (100%) rename {files => archive}/image_refresh_node/package.json (100%) rename {files => archive}/image_refresh_node/server.js (100%) create mode 100644 archive/index.php.old create mode 100644 archive/js_site/app.js create mode 100644 archive/js_site/index.php create mode 100644 archive/js_site/style.css rename {tasks => archive}/photo_refresh copy.yaml (100%) rename {templates => archive}/record_snapshots.sh.j2 (100%) create mode 100644 files/service_control_api/app.py create mode 100644 files/service_control_api/website/index.php create mode 100644 files/service_control_api/website/styles.css create mode 100644 tasks/chrome.yaml create mode 100644 tasks/service_control.yaml create mode 100644 templates/service_control.service.j2 diff --git a/files/app.py b/archive/app.py similarity index 100% rename from files/app.py rename to archive/app.py diff --git a/templates/docker-compose-node.yaml.j2 b/archive/docker-compose-node.yaml.j2 similarity index 100% rename from templates/docker-compose-node.yaml.j2 rename to archive/docker-compose-node.yaml.j2 diff --git a/archive/gsysctl.yaml b/archive/gsysctl.yaml new file mode 100644 index 0000000..03ff2e8 --- /dev/null +++ b/archive/gsysctl.yaml @@ -0,0 +1,80 @@ +--- + +############################################### +# Prepare for docker container +# https://github.com/shakg/g-systemctl +############################################### + + + +- name: set docker folder variable + set_fact: + docker_root: "/opt/cosmos/gsc" + +# clear folder first +- name: gsc - delete old folder + shell: "rm -R {{ docker_root }}" + +# Create docker Folder +- name: g-systemctl - create docker_root folder + file: + path: "{{ docker_root }}" + state: directory + mode: '0755' + owner: root + group: root + +- name: g-systemctl - clone the git + git: + repo: "https://github.com/shakg/g-systemctl" + dest: "{{ docker_root }}" + +############################################### +# Start docker container +############################################### + + +- name: Replace golang version number + ansible.builtin.replace: + path: "{{ docker_root }}/backend/Dockerfile" + regexp: '^FROM golang:.*-alpine as development' + replace: 'FROM golang:1.24-alpine as development' + +# Replace g-systemctl docker-compose file +- name: g-systemctl - replace docker-compose + copy: + dest: "{{ docker_root }}/docker-compose.yaml" + content: | + version: '3.8' + + services: + frontend: + container_name: gsc-frontend + network_mode: bridge + restart: always + build: + context: ./frontend + target: production + ports: + - "80:80" + + backend: + container_name: gsc-backend + network_mode: bridge + restart: always + build: + context: ./backend + target: production + ports: + - "8080:8080" + privileged: true + +- name: "g-systemctl - build and run containers" + shell: "docker-compose -f {{ docker_root }}/docker-compose.yaml up -d" + register: local_index_output +- debug: | + msg="{{ local_index_output.stdout_lines }}" + msg="{{ local_index_output.stderr_lines }}" + + +... \ No newline at end of file diff --git a/files/image_refresh_node/Dockerfile b/archive/image_refresh_node/Dockerfile similarity index 100% rename from files/image_refresh_node/Dockerfile rename to archive/image_refresh_node/Dockerfile diff --git a/files/image_refresh_node/package.json b/archive/image_refresh_node/package.json similarity index 100% rename from files/image_refresh_node/package.json rename to archive/image_refresh_node/package.json diff --git a/files/image_refresh_node/server.js b/archive/image_refresh_node/server.js similarity index 100% rename from files/image_refresh_node/server.js rename to archive/image_refresh_node/server.js diff --git a/archive/index.php.old b/archive/index.php.old new file mode 100644 index 0000000..79033f2 --- /dev/null +++ b/archive/index.php.old @@ -0,0 +1,39 @@ + + + + + + API Call Example + + + + +

+

+ +
+ + Loading... +
+ + + + + \ No newline at end of file diff --git a/archive/js_site/app.js b/archive/js_site/app.js new file mode 100644 index 0000000..3c2aae4 --- /dev/null +++ b/archive/js_site/app.js @@ -0,0 +1,58 @@ +document.addEventListener('DOMContentLoaded', function () { + // Initially set button state to "Loading..." + updateButtonState("Loading..."); + + // Set an interval to check the API every second + setInterval(checkAPIStatus, 1000); // 1000 ms = 1 second +}); + +// Function to update the button text based on the API state +function updateButtonState(status) { + const button = document.getElementById('statusButton'); + + if (status === "active") { + button.innerHTML = "Stop Service"; + button.style.backgroundColor = "#FF6347"; // Red for stopping + button.onclick = stopService; + } else if (status === "inactive") { + button.innerHTML = "Start Service"; + button.style.backgroundColor = "#32CD32"; // Green for starting + button.onclick = startService; + } else if (status === "failed") { + button.innerHTML = "Service Failed!"; + button.style.backgroundColor = "#FF6347"; // Red for failed + button.onclick = null; + }else { + button.innerHTML = "Unknown"; + button.style.backgroundColor = "#808080"; // Gray for error + button.onclick = null; + } +} + +// Simulate API call and handle response +function checkAPIStatus() { + // Replace with your actual API endpoint + fetch('http://172.17.0.1:5000/status') + .then(response => response.json()) + .then(data => { + const apiStatus = data.Status; + updateButtonState(apiStatus); + }) + .catch(error => { + console.error('Error fetching API status:', error); + updateButtonState('error'); + }); +} + + +// Function to start the service (this would make the API call to start it) +function startService() { + console.log('Starting service...'); + // You can call an API to start the service here +} + +// Function to stop the service (this would make the API call to stop it) +function stopService() { + console.log('Stopping service...'); + // You can call an API to stop the service here +} diff --git a/archive/js_site/index.php b/archive/js_site/index.php new file mode 100644 index 0000000..2cff265 --- /dev/null +++ b/archive/js_site/index.php @@ -0,0 +1,19 @@ + + + + + + API Status Button + + + +
+ +
+ + + + diff --git a/archive/js_site/style.css b/archive/js_site/style.css new file mode 100644 index 0000000..e65fdac --- /dev/null +++ b/archive/js_site/style.css @@ -0,0 +1,26 @@ +body { + font-family: Arial, sans-serif; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + background-color: #f4f4f9; +} + +#app { + text-align: center; +} + +button { + padding: 15px 30px; + font-size: 18px; + cursor: pointer; + border: none; + border-radius: 5px; + transition: background-color 0.3s ease; +} + +button:active { + transform: scale(0.98); +} diff --git a/tasks/photo_refresh copy.yaml b/archive/photo_refresh copy.yaml similarity index 100% rename from tasks/photo_refresh copy.yaml rename to archive/photo_refresh copy.yaml diff --git a/templates/record_snapshots.sh.j2 b/archive/record_snapshots.sh.j2 similarity index 100% rename from templates/record_snapshots.sh.j2 rename to archive/record_snapshots.sh.j2 diff --git a/defaults/main.yaml b/defaults/main.yaml index 271848b..b7bdbcc 100644 --- a/defaults/main.yaml +++ b/defaults/main.yaml @@ -1,30 +1,58 @@ --- -packages: +main_packages: + - gpsd + - gpsd-clients + - bc + - ffmpeg + - imagemagick + - ustreamer - ffmpeg - ethtool - python3 - python3-venv - pip - python-is-python3 - - dbus-user-session - apache2 - php + +autologin_packages: - kde-plasma-desktop - clinfo - mesa-utils - vulkan-tools - wayland-utils - xscreensaver + - dbus-user-session # chrome kiosk variables kiosk_service_templates: - chrome_resolution: "720,405" chrome_website: "http://127.0.0.1:7123/stream" service_name: chrome_webcam - - chrome_resolution: "720,595" - chrome_website: "http://127.0.0.1:3000" + extra_service_configs: | + After=ustreamer.service + Wants=ustreamer.service + user_data_dir: "/opt/chrome/one" + extra_chrome_configs: | + --user-data-dir=/opt/chrome/one \ + - chrome_resolution: "720,550" + chrome_website: "http://127.0.0.1:8081" service_name: chrome_timelapse_control + extra_service_configs: "" + user_data_dir: "/opt/chrome/two" + extra_chrome_configs: | + --window-position="0,410" \ + --user-data-dir="/opt/chrome/two" \ + +create_data_dir: true + +# timelapse scripts for templating +timelapse_script_templates: + - src: timelapse_service.sh.j2 + dest: "{{ working_folder }}/timelapse_service.sh" + - src: create_timelapse.sh.j2 + dest: "{{ working_folder }}/create_timelapse.sh" # this will be the parent folder where the photos will be stored @@ -38,11 +66,15 @@ working_folder: "/opt/carputer/timelapse" # other folder variables gps_service_directory: "/opt/cosmos/gps_service" photo_refresh_folder: "/opt/cosmos/photo_refresh" +service_control_folder: "/opt/cosmos/timelapse_service_control" # ustreamer variables video_device: "/dev/video0" resolution: "1920x1080" ustreamer_port: "7123" +# other rando vars +cpu_architecture: "amd64" +extra_volumes: "" ... \ No newline at end of file diff --git a/files/service_control_api/app.py b/files/service_control_api/app.py new file mode 100644 index 0000000..68d4d4b --- /dev/null +++ b/files/service_control_api/app.py @@ -0,0 +1,85 @@ +import subprocess +import requests +from lxml import html +from flask import Flask, request, jsonify +import json + +app = Flask(__name__) + +def start_service(): + command = "systemctl start timelapse.service" + try: + # Run the command using subprocess.run() + process = subprocess.Popen(command, shell=True) + + except subprocess.CalledProcessError as e: + return {"Error": e.strip('\n')} + + command = "systemctl status timelapse.service | grep Active | cut -d ':' -f 2- | cut -b 2-" + try: + # Run the command using subprocess.run() + result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True) + return {"Message": result.stdout.strip('\n')} + + except subprocess.CalledProcessError as e: + return {"Error": e.strip('\n')} + +def stop_service(): + command = "systemctl stop timelapse.service" + try: + # Run the command using subprocess.run() + process = subprocess.Popen(command, shell=True) + + except subprocess.CalledProcessError as e: + return {"Error": e.strip('\n')} + + command = "systemctl status timelapse.service | grep Active | cut -d ':' -f 2- | cut -b 2-" + try: + # Run the command using subprocess.run() + result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True) + return {"Message": result.stdout.strip('\n')} + except subprocess.CalledProcessError as e: + return {"Error": e.strip('\n')} + +def service_status(): + command = "systemctl status timelapse.service | grep Active | cut -d ':' -f 2- | cut -b 2-" + try: + # Run the command using subprocess.run() + result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True) + command = "systemctl status timelapse.service | grep Active | cut -d ':' -f 2 | cut -d ' ' -f 2" + status = subprocess.run(command, shell=True, check=True, capture_output=True, text=True) + return {"Message": result.stdout.strip('\n'), "Status": status.stdout.strip('\n')} + except subprocess.CalledProcessError as e: + return {"Error": e.strip('\n')} + +@app.route('/start', methods=['GET']) +def start(): + try: + return jsonify(start_service()) + except ValueError as e: + print(e) + return jsonify({'error': e}), 400 + +@app.route('/stop', methods=['GET']) +def stop(): + try: + return jsonify(stop_service()) + except ValueError as e: + print(e) + return jsonify({'error': e}), 400 + +@app.route('/status', methods=['GET']) +def status(): + try: + return jsonify(service_status()) + except ValueError as e: + print(e) + return jsonify({'error': e}), 400 + +@app.route('/test', methods=['GET']) +def test(): + return jsonify({'message': 'Hello there'}) + +if __name__ == '__main__': + app.run(debug=True, host='0.0.0.0', port=5000) + \ No newline at end of file diff --git a/files/service_control_api/website/index.php b/files/service_control_api/website/index.php new file mode 100644 index 0000000..c1bd76d --- /dev/null +++ b/files/service_control_api/website/index.php @@ -0,0 +1,203 @@ +"; + $button_recent = true; + $button_result = runAPI($_GET['action']); + $debug_string = $debug_string."Button Result: ".$button_result."
"; + sleep(1); +} + +function runAPI($submitted_status) { + if(!isset($debug_string)){ + $debug_string = ""; + } + $debug_string = $debug_string."runAPI called, ".$submitted_status."
"; + switch ($submitted_status) { + case "stop": + $apiUrl = "http://172.17.0.1:5000/stop"; + break; + case "start": + $apiUrl = "http://172.17.0.1:5000/start"; + break; + default: + $apiUrl = "http://172.17.0.1:5000/status"; + break; + } + // API URL + $debug_string = $debug_string."After switch, apiUrl is ".$apiUrl."
"; + // Use file_get_contents or cURL to fetch the API data + $response = file_get_contents($apiUrl); + + if ($response === FALSE) { + $debug_string = $debug_string."Response ERROR!!
"; + return "error"; // API error + } + + // Decode the JSON response (assuming the API returns JSON) + $data = json_decode($response, true); + $debug_string = $debug_string."Data from API call: ".$data['Message']."
"; + // Assuming the API returns a single word result (like "success", "failure", etc.) + return isset($data['Status']) ? $data['Status'] : 'unknown'; +} + +// Check if the button was clicked via AJAX request +// if ($_SERVER['REQUEST_METHOD'] === 'POST') { +// $button_recent = true; +// $status_at_submit = $_POST['status']; +// echo "Set when clicked, second in code - ".$status_at_submit."
"; +// // Get the API result +// $apiResult = runAPI($status_at_submit); +// // Return the result as a JSON response +// echo json_encode(['status' => $apiResult]); +// exit; +// } + +// URL of the external API +$apiUrl = "http://172.17.0.1:5000/status"; + +// Use file_get_contents to fetch data from the API +$response = file_get_contents($apiUrl); + +// Check if the request was successful +if ($response === FALSE) { + $data = "Failed to fetch data."; +} +else { + // Decode the JSON response (assuming the API returns JSON) + $data = json_decode($response, true); + // If you want to display specific data, adjust this part + // For example, if the API returns a 'message' key, display it + if (isset($data['Message'])) { + $message = $data['Message']; + } else { + $message = "No message found in the response."; + } + if (isset($data['Status'])) { + $status = $data['Status']; + } else { + $status = "None"; + } +} + +switch ($status) { + case "active": + $button_text = "Stop Service"; + $button_active = true; + break; + case "inactive": + $button_text = "Start Service"; + $button_active = true; + break; + case "failed": + $button_text = "Start Service - Warning"; + $button_active = true; + break; + case "deactivating": + $button_text = "Service Stopping..."; + $button_active = false; + break; + default: + $button_text = "Error, No Status"; + $button_active = false; + $status="unknown"; + break; +} + +if($button_active && !$button_recent){ + $action = ""; + if($status == "active"){ + $action = "stop"; + } + else if($status == "inactive"){ + $action = "start"; + } + else if($status == "failed"){ + $action = "start"; + } + $button_action = ' onclick="location.href=\'/?action='.$action.'\'" '; +} + +if($button_recent){ + /* + $delay = 5; // Number of seconds before redirection + echo "You will be redirected in $delay seconds."; + header("Refresh: $delay; url=https://example.com"); + exit(); + */ + header("Location: http://".$http_host); + exit(); // Always include exit() after headers are sent +} + +?> + + + + + + + + API Data Display + + + + + +
+ +
+ +

+

+

+

+ + ".htmlspecialchars($message)."

Current Date:
".date("F j, Y, g:i:s a")."

"; + ?> +

+ +
+ + + + + + + diff --git a/files/service_control_api/website/styles.css b/files/service_control_api/website/styles.css new file mode 100644 index 0000000..2bc2238 --- /dev/null +++ b/files/service_control_api/website/styles.css @@ -0,0 +1,80 @@ + +body { + font-family: Arial, sans-serif; + margin: 0; + padding: 0; + background-color: #2c3e50; /* Dark background color */ + color: #bdc3c7; /* Dimmer text color */ + zoom: 1.5 +} +.container { + max-width: 500px; + margin: 0 auto; + margin-top: 20px; + padding: 20px; + background-color: #34495e; /* Darker background for container */ + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); /* Slightly darker shadow */ +} +.api-data { + font-size: 1.4rem; + color: #bdc3c7; /* Dimmer text color */ +} +.loading { + font-size: 1.2rem; + background-color: #34495e; /* Darker background for container-wide */ +} +.status-button { + padding: 10px 20px; + font-size: 1.5rem; + border: none; + cursor: pointer; + margin-top: 20px; + border-radius: 5px; +} +.button-container { + display: flex; + justify-content: center; /* This centers the button horizontally */ +} +button { + background: radial-gradient(circle, #ff7e5f 0%, #feb47b 100%); + border: none; + color: white; + font-size: 30px; + padding: 25px 50px; + text-align: center; + text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); + border-radius: 30px; + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); + transition: all 0.3s cubic-bezier(.25,.8,.25,1); +} + +button:hover { + transform: scale(1.05); + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); +} +.inactive { + background-color: #0b660e; + background: radial-gradient(circle, #0b660e 0%, #2b922f 100%); + color: #bdc3c7; /* Dimmer text color */ +} +.active { + background-color: #a5150b; + background: radial-gradient(circle, #a5150b 0%, #d6382d 100%); + color: #bdc3c7; /* Dimmer text color */ +} +.failed { + background-color: #671281; + background: radial-gradient(circle, #671281 0%, #8423a1 100%); + color: #bdc3c7; /* Dimmer text color */ +} +.deactivating { + background-color: #003699; + background: radial-gradient(circle, #003699 0%, #337aff 100%); + color: #bdc3c7; /* Dimmer text color */ +} +.unknown { + background-color: #ec701e; + background: radial-gradient(circle, #c9580d 0%, #ec701e 100%); + color: #bdc3c7; /* Dimmer text color */ +} \ No newline at end of file diff --git a/tasks/chrome.yaml b/tasks/chrome.yaml new file mode 100644 index 0000000..4fbe0fb --- /dev/null +++ b/tasks/chrome.yaml @@ -0,0 +1,35 @@ +--- + +############################################### +# Install Chrome +- name: Chrome - Chrome - Check if installed + command: dpkg -l google-chrome-stable + register: chrome_installed + ignore_errors: true + +- name: Chrome - Chrome - Set chrome_present variable + set_fact: + chrome_present: "{{ chrome_installed.rc == 0 }}" + +- name: Chrome - Install Chrome + include_tasks: /var/jenkins_home/ansible/roles/install_apps/tasks/chrome.yaml + when: not chrome_present | bool + +- name: Chrome - Create User Service Folder + file: + path: /home/cosmos/.config/systemd/user + state: directory + owner: cosmos + group: cosmos + mode: '0700' + +- name: Chrome - clear user cache + shell: "rm -R /home/cosmos/.config/google-chrome" + +############################################### +# Configure Kiosks + +- name: Set up Chrome Kiosk Services + include_tasks: kiosk.yaml + loop: "{{ kiosk_service_templates }}" +... \ No newline at end of file diff --git a/tasks/cosmos_autologin.yaml b/tasks/cosmos_autologin.yaml index b4e2509..ddbad0c 100644 --- a/tasks/cosmos_autologin.yaml +++ b/tasks/cosmos_autologin.yaml @@ -8,7 +8,7 @@ apt: name: "{{ item }}" state: present - loop: "{{ packages }}" + loop: "{{ autologin_packages }}" # Set sddm as def - name: prereqs - enable sddm in xdm @@ -32,21 +32,6 @@ dest: /etc/sddm.conf mode: 0644 -############################################### -# Install Chrome -- name: prereqs - Chrome - Check if installed - command: dpkg -l google-chrome-stable - register: chrome_installed - ignore_errors: true - -- name: prereqs - Chrome - Set chrome_present variable - set_fact: - chrome_present: "{{ chrome_installed.rc == 0 }}" - -- name: prereqs - Install Chrome - include_tasks: /var/jenkins_home/ansible/roles/install_apps/tasks/chrome.yaml - when: not chrome_present | bool - ############################################### # Apply Profile # Create Cosmos user folder @@ -61,7 +46,7 @@ # Extract profile - name: prereqs - extract cosmos user profile unarchive: - src: /var/jenkins_home/ansible-files/lldp_scan/cosmos.tar.gz + src: /var/jenkins_home/ansible-files/profile/cosmos.tar.gz dest: /home owner: cosmos group: cosmos diff --git a/tasks/gps_service.yaml b/tasks/gps_service.yaml index 9f376d9..7164c5a 100644 --- a/tasks/gps_service.yaml +++ b/tasks/gps_service.yaml @@ -9,16 +9,6 @@ owner: root group: root -# install packages -- name: gps_service - Install Packages - apt: - name: - - gpsd - - gpsd-clients - state: present - register: apt_result - ignore_errors: true - - name: gps_service - Enable and start gpsd system service become: true systemd: diff --git a/tasks/kiosk.yaml b/tasks/kiosk.yaml index 07b8549..af50e82 100644 --- a/tasks/kiosk.yaml +++ b/tasks/kiosk.yaml @@ -6,45 +6,48 @@ # so i can make a list of variables again ############################################### -- name: Chrome Kiosk - Create User Service Folder +- name: Chrome Kiosk - display info + debug: + msg: + - "Chrome Kiosk Configuring" + - "Kiosk Service Name: {{ item.service_name }}" + - "Chrome Website: {{ item.chrome_website }}" + - "Chrome App Resolution: {{ item.chrome_resolution }}" + +# Create user data dir Folder +- name: timelapse - create working folder + when: create_data_dir | bool file: - path: /home/cosmos/.config/systemd/user + path: "{{ item.user_data_dir }}" state: directory + mode: '0755' owner: cosmos group: cosmos - mode: '0700' -- name: configure kiosks - block: +- name: Chrome Kiosk - user stop service + command: "systemctl --user -M cosmos@ stop {{ item.service_name }}.service" + ignore_errors: true - - name: Chrome Kiosk - user stop service - command: "systemctl --user -M cosmos@ stop {{ service_name }}.service" - ignore_errors: true +# - name: Chrome Kiosk - Kill chrome if running otherwise +# command: pkill chrome +# ignore_errors: true - - name: Chrome Kiosk - Kill chrome if running otherwise - command: pkill chrome - ignore_errors: true +- name: Chrome Kiosk - Copy chrome service file + template: + src: chrome-app.service.j2 + dest: "/home/cosmos/.config/systemd/user/{{ item.service_name }}.service" + owner: cosmos + group: cosmos + mode: 0600 - - name: Chrome Kiosk - Copy chrome service file - template: - src: chrome-app.service.j2 - dest: "/home/cosmos/.config/systemd/user/{{ service_name }}.service" - owner: cosmos - group: cosmos - mode: 0600 +- name: Chrome Kiosk - user daemon reload + command: "systemctl --user -M cosmos@ daemon-reload" + register: user_daemon_reload - - name: Chrome Kiosk - user daemon reload - command: "systemctl --user -M cosmos@ daemon-reload" - register: user_daemon_reload - - - name: Chrome Kiosk - user enable service - command: "systemctl --user -M cosmos@ enable {{ service_name }}.service" - - - name: Chrome Kiosk - user start service - command: "systemctl --user -M cosmos@ start {{ service_name }}.service" - - loop: "{{ timelapse_script_templates }}" - +- name: Chrome Kiosk - user enable service + command: "systemctl --user -M cosmos@ enable {{ item.service_name }}.service" +- name: Chrome Kiosk - user start service + command: "systemctl --user -M cosmos@ start {{ item.service_name }}.service" ... \ No newline at end of file diff --git a/tasks/main.yaml b/tasks/main.yaml index b522d14..283214e 100644 --- a/tasks/main.yaml +++ b/tasks/main.yaml @@ -4,24 +4,41 @@ # Playbook for configuring GOLE as Road Trip Carputer ########################################################### # Steps: +### Packages ### uStreamer +### GPS Service ### Timelapse Service -### Sharing Page +### Photo Refresh Page ### Cosmos Autologin ### Top Cam Feed Kiosk ### Bottom Service Control Panel -#- name: Install ustreamer -# include_tasks: ustreamer.yaml -# -#- name: Install gps_service -# include_tasks: gps_service.yaml -# -#- name: install timelapse service -# include_tasks: timelapse.yaml -# -#- name: Install photo refresh site -# include_tasks: photo_refresh.yaml +- name: Install Packages + apt: + name: "{{ item }}" + state: present + loop: "{{ main_packages }}" + +- name: Install ustreamer + include_tasks: ustreamer.yaml + +- name: Install gps_service + include_tasks: gps_service.yaml + +- name: install timelapse service + include_tasks: timelapse.yaml + +- name: Install photo refresh site + include_tasks: photo_refresh.yaml + +- name: Install cosmos autologin user + include_tasks: cosmos_autologin.yaml + +- name: Install timelapse service control + include_tasks: service_control.yaml + +- name: Set up Chrome Kiosk Services + include_tasks: chrome.yaml ... \ No newline at end of file diff --git a/tasks/photo_refresh.yaml b/tasks/photo_refresh.yaml index 5a793a7..68fb7f5 100644 --- a/tasks/photo_refresh.yaml +++ b/tasks/photo_refresh.yaml @@ -36,6 +36,12 @@ - name: start photo_refresh block: + - name: set container_name + set_fact: + container_name: "photo_refresh" + container_http_port: "8080" + extra_volumes: | + - {{ working_folder }}/small_thumbs:/var/www/html/capture - name: photo_refresh - template config template: diff --git a/tasks/service_control.yaml b/tasks/service_control.yaml new file mode 100644 index 0000000..ceccdca --- /dev/null +++ b/tasks/service_control.yaml @@ -0,0 +1,135 @@ +--- + +############################################### +# This will be a big one, gonne need the API +# for service interaction, as well as the +# web server code +############################################### + +############################################### +# This part sets up python serice control api +############################################### + +- name: service control api + when: false + block: + + # Stop service + - name: service_control api - stop service api + systemd: + name: service_control.service + state: stopped + ignore_errors: yes + + # Create API Folder + - name: service_control api - create api folder + file: + path: "{{ service_control_folder }}" + state: directory + mode: '0755' + + # Copy API Code + - name: service_control api - copy api code + copy: + src: service_control_api/app.py + dest: "{{ service_control_folder }}/app.py" + mode: 0644 + + # Create service_control api service + - name: service_control api - create requirement file + copy: + dest: "{{ service_control_folder }}/requirements.txt" + content: | + Flask==2.1.0 + pytz + requests + lxml + Werkzeug==2.0 + mode: 0644 + + # build venv + - name: service_control api - build venv + pip: + virtualenv: "{{ service_control_folder }}/venv" + requirements: "{{ service_control_folder }}/requirements.txt" + virtualenv_command: python3 -m venv + state: present + + # Create service_control api service + - name: service_control api - create service file + # vars: + template: + src: service_control.service.j2 + dest: /etc/systemd/system/service_control.service + mode: 0644 + + # daemon reload + - name: service_control api - daemon reload + systemd: + daemon_reload: yes + + # Enable and start + - name: service_control api - enable and start service api + systemd: + name: service_control.service + state: started + enabled: yes + + + +############################################### +# This part sets up serice control website +############################################### + +- name: service control web interface + when: true + block: + + - name: set docker folder variable + set_fact: + service_control_web_folder: "{{ service_control_folder }}/web" + + # Create docker Folder + - name: service_control_website - create service_control_web_folder folder + file: + path: "{{ service_control_web_folder }}" + state: directory + mode: '0755' + owner: root + group: root + + - name: service_control_website - copy files for docker container + copy: + src: "service_control_api/website/" + dest: "{{ service_control_web_folder }}/html" + mode: 0755 + owner: root + group: root + + ############################################### + # Start photo_refresh + ############################################### + + - name: start service_control_website + block: + - name: set container_name + set_fact: + container_name: "service_control_website" + container_http_port: "8081" + + - name: service_control_website - template config + template: + src: docker-compose-php.yaml.j2 + dest: "{{ service_control_web_folder }}/docker-compose.yaml" + mode: 0644 + + - name: "service_control_website - Start container at 0.0.0.0:{{ container_http_port }}" + shell: "docker-compose -f {{ service_control_web_folder }}/docker-compose.yaml up -d" + register: local_index_output + - debug: | + msg="{{ local_index_output.stdout_lines }}" + msg="{{ local_index_output.stderr_lines }}" + + + +... diff --git a/tasks/timelapse.yaml b/tasks/timelapse.yaml index ed91a8a..45a025a 100644 --- a/tasks/timelapse.yaml +++ b/tasks/timelapse.yaml @@ -1,16 +1,5 @@ --- -# install packages -- name: photo_refresh - Install Packages - apt: - name: - - bc - - ffmpeg - - imagemagick - state: present - register: apt_result - ignore_errors: true - # Create working Folder - name: timelapse - create working folder file: @@ -18,17 +7,6 @@ state: directory mode: '0755' -- name: timelapse - set template vars - set_fact: - # timelapse related scripts - timelapse_script_templates: - - src: timelapse_service.sh.j2 - dest: "{{ working_folder }}/timelapse_service.sh" - - src: record_snapshots.sh.j2 - dest: "{{ working_folder }}/record_snapshots.sh" - - src: create_timelapse.sh.j2 - dest: "{{ working_folder }}/create_timelapse.sh" - - name: timelapse - template scripts template: src: "{{ item.src }}" diff --git a/tasks/ustreamer.yaml b/tasks/ustreamer.yaml index 3bfb93a..5ca427b 100644 --- a/tasks/ustreamer.yaml +++ b/tasks/ustreamer.yaml @@ -1,13 +1,5 @@ --- -- name: ustreamer - Install Packages - apt: - name: - - ustreamer - state: present - register: apt_result - ignore_errors: true - - name: ustreamer - Create user user: name: "ustreamer" diff --git a/templates/chrome-app.service.j2 b/templates/chrome-app.service.j2 index b385f14..0c9127a 100755 --- a/templates/chrome-app.service.j2 +++ b/templates/chrome-app.service.j2 @@ -1,8 +1,8 @@ [Unit] Description=Chrome -After=lldp_api.service After=sddm.service + [Service] Restart=always RestartSec=3s @@ -13,8 +13,12 @@ ExecStart=/usr/bin/google-chrome \ --no-first-run \ --ignore-ssl-errors \ --disable-usb-keyboard-detect \ - --window-size={{ chrome_resolution }}' - --app="{{ chrome_website }}" + --window-size="{{ item.chrome_resolution }}" \ + --app="{{ item.chrome_website }}" \ +{{ item.extra_chrome_configs}} + +{{ item.extra_service_configs }} [Install] -WantedBy=graphical-session.target \ No newline at end of file +WantedBy=graphical-session.target + diff --git a/templates/create_timelapse.sh.j2 b/templates/create_timelapse.sh.j2 index 3b6e665..b962baa 100644 --- a/templates/create_timelapse.sh.j2 +++ b/templates/create_timelapse.sh.j2 @@ -1,10 +1,9 @@ #!/bin/bash # end the loop -rm $WORKING_DIR/run -sleep 5 +rm $RUN_FILE +rm $WORKING_DIR/*temp*.jpg # create timelapse -/bin/ffmpeg -r 30 -pattern_type glob -i "$WORKING_DIR/*.jpg" \ --vf "scale=1920x1080" -vcodec libx264 /$WORKING_DIR/00-timelapse.mp4 +/bin/ffmpeg -r 30 -pattern_type glob -i "$WORKING_DIR/*.jpg" -vf "scale=1920x1080" -vcodec libx264 /$WORKING_DIR/00-timelapse.mp4 & diff --git a/templates/docker-compose-php.yaml.j2 b/templates/docker-compose-php.yaml.j2 index 4bcf205..3833e80 100644 --- a/templates/docker-compose-php.yaml.j2 +++ b/templates/docker-compose-php.yaml.j2 @@ -1,12 +1,12 @@ services: - photo_refresh: - container_name: photo_refresh + {{ container_name }}: + container_name: {{ container_name }} image: php:8.0-apache ports: - - 8080:80 + - {{ container_http_port }}:80 volumes: - ./html:/var/www/html/ - - {{ working_folder }}/small_thumbs:/var/www/html/capture + {{ extra_volumes }} network_mode: bridge restart: always diff --git a/templates/service_control.service.j2 b/templates/service_control.service.j2 new file mode 100644 index 0000000..82458f1 --- /dev/null +++ b/templates/service_control.service.j2 @@ -0,0 +1,15 @@ + +[Unit] +Description=Timelapse Service Control API +After=network.target + +[Service] +User=root +Group=root +WorkingDirectory={{ service_control_folder }} +ExecStartPre=/bin/sleep 5 +ExecStart={{ service_control_folder }}/venv/bin/python {{ service_control_folder }}/app.py +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/templates/timelapse_service.sh.j2 b/templates/timelapse_service.sh.j2 index c2cdc01..d3552e3 100644 --- a/templates/timelapse_service.sh.j2 +++ b/templates/timelapse_service.sh.j2 @@ -1,5 +1,5 @@ #!/bin/bash -trap "source {{ working_folder }}/create_timelapse.sh &" SIGINT SIGTERM +trap "source {{ working_folder }}/create_timelapse.sh" SIGINT SIGTERM # initialize all the variables # basic things @@ -12,6 +12,7 @@ CITY=$(echo $WHERES_GALI | jq .city) STATE=$(echo $WHERES_GALI | jq .state) ZIPCODE=$(echo $WHERES_GALI | jq .postcode) DISPLAY_NAME=$(echo $WHERES_GALI | jq .display_name) +RUN_FILE={{ working_folder }}/run # Generate Status Report mkdir -p $WORKING_DIR @@ -28,8 +29,9 @@ echo "/bin/ffmpeg -r 30 -pattern_type glob -i "$WORKING_DIR/*.jpg" \\" >> {{ wo echo "-vf "scale=1920x1080" -vcodec libx264 /$WORKING_DIR/00-timelapse.mp4" >> {{ working_folder }}/generate_timelapses.sh # capture time +touch $RUN_FILE i=1 -while [ $i ] +while [ -e $RUN_FILE ] do FILENAME=$(printf "img-%05d" "$i") # old API based latlon