From d7ed31153e66731737d52b2e99fe926437923e00 Mon Sep 17 00:00:00 2001 From: mcw-work Date: Wed, 24 Apr 2024 12:41:28 +0100 Subject: [PATCH 1/2] Add script for setting managed mode (no automatic refreshes) --- README.md | 3 +++ core/snaps/snap-http-managed-mode.py | 10 ++++++++++ 2 files changed, 13 insertions(+) create mode 100644 core/snaps/snap-http-managed-mode.py diff --git a/README.md b/README.md index c074dc8..f109234 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,9 @@ _Note: some scripts may require python3-requests deb (or PyPI requests) in order - **Tutorial**: Set the refresh timer using Python and the snap-http library - [**set-refresh-timer.py**](./core/snaps/set-refresh-timer.py) +- **Tutorial**: Put device into managed mode (disable automatic snap refreshes) + - [**snap-http-remove.py**](./core/snaps/snap-http-managed-mode.py) + ### Snap Services - **Tutorial**: Enable a snap service using Python and the snap-http library diff --git a/core/snaps/snap-http-managed-mode.py b/core/snaps/snap-http-managed-mode.py new file mode 100644 index 0000000..c424a2e --- /dev/null +++ b/core/snaps/snap-http-managed-mode.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 + +from landscape.client import snap_http + +snap_http.set_conf( + "system", + { + "refresh.hold": "forever", + }, +) \ No newline at end of file From 949fe48504c09c4a011f8381fbe8a06577e6608f Mon Sep 17 00:00:00 2001 From: mcw-work Date: Tue, 20 May 2025 13:50:11 +0100 Subject: [PATCH 2/2] Add snap-debug-info.sh script to README.md Add snap-debug-info.sh script to debugging directory --- README.md | 5 ++ debugging/snap-debug-info.sh | 148 +++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 debugging/snap-debug-info.sh diff --git a/README.md b/README.md index f109234..fb604b3 100644 --- a/README.md +++ b/README.md @@ -177,3 +177,8 @@ _Note: some scripts may require python3-requests deb (or PyPI requests) in order - **Tutorial**: Remove a user from a Core device - [**remove-user.py**](./core/users/remove-user.py) + +### Debugging + +- **Tutorial**: Collect a large amount of SnapD and core system information that could be useful when debugging a system with Canonical Support + - [**remove-user.py**](./debugging/snap-debug-info.sh) diff --git a/debugging/snap-debug-info.sh b/debugging/snap-debug-info.sh new file mode 100644 index 0000000..58a6c8e --- /dev/null +++ b/debugging/snap-debug-info.sh @@ -0,0 +1,148 @@ +#!/bin/bash + +# This script collects information about the status of a device to aid in debugging. +# There is a slight limitation when trying to extract logs using the journalctl +# command. +# +# If your Landscape snap is based on Core 22 and your device is Core 24, you will not +# be able to extract logs using the journalctl command. This is because the journalctl +# command does not support the log format used by Core 24. +# +# If you are using Core 24, you can resovle this by using a Landscape client track +# that is based on Core 24. + + +# Collect snapd information +# PRINT DEBUG INFO +echo "SNAP DEBUG INFO REPORT" +echo "=================================" +echo "" +echo "UTC DATE:" +echo "=================================" +date --utc + +echo "UPTIME:" +echo "=================================" +uptime -p + +echo "DISK SPACE:" +echo "=================================" +df -h + +# System Logs +echo "SNAPD JOURNAL OUTPUT:" +echo "=================================" +journalctl -u snapd --no-pager + +echo "" +echo "SNAPD JOURNAL DENIED OUTPUT:" +echo "=================================" +# Filter journal output for lines containing "DENIED" +journalctl -u snapd --no-pager | grep "DENIED" + +echo "" +echo "\nSNAPD PROCESS INFORMATION:" +echo "=================================" +ps -ax | grep snapd + + +# Run Python script to collect snapd information + +python3 << END +import socket +import pprint +import subprocess +import json +from http.client import HTTPResponse +from io import BytesIO + +BASE_URL = "http://localhost/v2" +SNAPD_SOCKET = "/run/snapd.socket" + + +def print_services(apps, indent=0): + for app in apps: + line = ( + " " * indent + + f"- {app['name']} " + f"(snap: {app['snap']}, " + f"active: {app['active']}, " + f"enabled: {app['enabled']})" + ) + print(line) + + +def make_API_call(method, path): + sock = socket.socket(family=socket.AF_UNIX) + sock.connect(SNAPD_SOCKET) + + url = BASE_URL + path + response = HTTPResponse(sock, method=method, url=url) + + request = BytesIO() + request.write( + f"{method} {url} HTTP/1.1\r\nHost: localhost\r\n\r\n".encode()) + + sock.sendall(request.getvalue()) + response.begin() + response_body = response.read() + response.close() + sock.close() + + response_type = response.getheader("Content-Type") + if response_type == "application/json": + return json.loads(response_body)["result"] + else: + response_code = response.getcode() + is_async = response_code == 202 + return { + "type": "async" if is_async else "sync", + "status_code": response_code, + "result": response_body, + } + +print("\nSystem Information:") +print("=================================") +pprint.pprint(make_API_call("GET", "/system-info")) + +# Get SnapD Info +print("\nModel and Serial Information:") +print("=================================") +pprint.pprint(make_API_call("GET", "/model/serial")) + +print("\nInstalled Snap Information:") +print("=================================") +pprint.pprint(make_API_call("GET", "/apps")) + +print("\nSnap Services Information:") +print("=================================") +response_json = make_API_call("GET", "/apps") + +# Extract the JSON part from the HTTP response + +filtered = [ + { + "name": app.get("name"), + "snap": app.get("snap"), + "active": app.get("active"), + "enabled": app.get("enabled"), + } + for app in response_json + if "daemon" in app +] + +print_services(filtered) + +print("\nInterface Connection Information:") +print("=================================") +pprint.pprint(make_API_call("GET", "/connections")) + +print("\nSnapD Changes Information:") +print("=================================") +pprint.pprint(make_API_call("GET", "/changes?select=all")) + +print("\nValidation Sets Information:") +print("=================================") +pprint.pprint(make_API_call("GET", "/validation-sets")) + +END