multiple evolutions

This commit is contained in:
Quentin WEPHRE
2025-12-04 08:11:00 +01:00
parent e9715dc239
commit abd00f9e04
9 changed files with 403 additions and 264 deletions

View File

@@ -40,7 +40,7 @@ allowed_name_characters.append('.')
logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s', filename='data_config_debug.log', filemode='w', level=logging.DEBUG, datefmt='%Y%m%d%H%M%S') logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s', filename='data_config_debug.log', filemode='w', level=logging.DEBUG, datefmt='%Y%m%d%H%M%S')
dir_name = 'I-Sight_Generated_Files' dir_name = 'I-Sight_Generated_Files'
input_datamodel = 'DATAMODEL_1.0.6_LIBERTY.xlsx' input_datamodel = 'DATAMODEL_1.0.6_CW.xlsx'
shell_script_name = dir_name + '/I-Sight_Configuration_' shell_script_name = dir_name + '/I-Sight_Configuration_'
global_shell_script_name = dir_name + '/I-Sight_Global_Configuration.sh' global_shell_script_name = dir_name + '/I-Sight_Global_Configuration.sh'
@@ -208,7 +208,7 @@ def jq_filter(current_device, dsh, dsh_global, row_device):
jq_data["enable"] = False jq_data["enable"] = False
jq_data["properties"] = [{"key": "deviceType", "value": "AC_GATEWAY"}, {"key": "cdid", "value": current_device}] jq_data["properties"] = [{"key": "deviceType", "value": "AC_GATEWAY"}, {"key": "cdid", "value": current_device}]
jq_data["outputTopic"] = filter jq_data["outputTopic"] = filter
jq_data["sendOutThreshold"] = {"mode": "bySize", "size": int(128000), "time": int(30), "sizeIdleTimer": {"enable": True, "time": int(30)}} jq_data["sendOutThreshold"] = {"mode": "bySize", "size": int(128000), "time": int(30), "sizeIdleTimer": {"enable": True, "time": int(5)}}
jq_data["minPublishInterval"] = int(0) jq_data["minPublishInterval"] = int(0)
jq_data["samplingMode"] = "allValues" jq_data["samplingMode"] = "allValues"
jq_data["customSamplingRate"] = False jq_data["customSamplingRate"] = False

View File

@@ -15,20 +15,21 @@ if CONNECTION_STRING == "":
print("Provide a connection string for the Iot Hub before running the script!") print("Provide a connection string for the Iot Hub before running the script!")
exit(13) exit(13)
SITE_NAME = "LIBERTY" SITE_NAME = "Bell"
registry_manager = IoTHubRegistryManager.from_connection_string(CONNECTION_STRING) registry_manager = IoTHubRegistryManager.from_connection_string(CONNECTION_STRING)
query_spec = QuerySpecification(query="SELECT * FROM devices WHERE IS_DEFINED(tags.site) AND tags.site = '" + SITE_NAME + "' AND capabilities.iotEdge = true") #query_spec = QuerySpecification(query="SELECT * FROM devices WHERE IS_DEFINED(tags.site) AND tags.site = '" + SITE_NAME + "' AND capabilities.iotEdge = true")
query_spec = QuerySpecification(query="SELECT * FROM devices WHERE IS_DEFINED(tags.site) AND tags.site = '" + SITE_NAME + "' AND capabilities.iotEdge = false")
query_result = registry_manager.query_iot_hub(query_spec) query_result = registry_manager.query_iot_hub(query_spec)
devices = [] devices = []
for item in query_result.items: for item in query_result.items:
deviceId = str(item.device_id) deviceId = str(item.device_id)
site = str(item.tags['site']) site = str(item.tags.get('site')) if item.tags.get('site') else None
number = int(item.tags['number']) number = int(item.tags.get('number')) if item.tags.get('number') else None
cloud_version = str(item.tags['version']) cloud_version = str(item.tags.get('version')) if item.tags.get('version') else None
devices.append([deviceId, site, number, cloud_version]) devices.append([deviceId, site, number, cloud_version])
ordered_devices = sorted(devices, key = lambda x: (x[1], x[2])) ordered_devices = sorted(devices, key = lambda x: (x[1], x[2]))

View File

@@ -31,14 +31,18 @@ for twin in query_result.items:
"number": twin.tags.get("number") if twin.tags else None, "number": twin.tags.get("number") if twin.tags else None,
"site": twin.tags.get("site") if twin.tags else None, "site": twin.tags.get("site") if twin.tags else None,
"connection_state": twin.connection_state, "connection_state": twin.connection_state,
"last_activity_time": twin.last_activity_time, "last_activity_time": twin.last_activity_time
}) })
df = pd.DataFrame(rows) df = pd.DataFrame(rows)
df['number'] = pd.to_numeric(df['number'], errors='coerce')
df['number'] = df['number'].astype('Int64')
df_sorted = df.sort_values(by=["site", "number"]).reset_index(drop=True) df_sorted = df.sort_values(by=["site", "number"]).reset_index(drop=True)
print(df_sorted) for row in df_sorted.itertuples():
if "cube" not in row.device_id:
print(f"\"{row.device_id}\", \"{row.site}\", \"{row.number}\",")
# Compute difference in hours (float) # Compute difference in hours (float)
df_sorted["time_since_last_activity_hours"] = df_sorted["last_activity_time"].apply( df_sorted["time_since_last_activity_hours"] = df_sorted["last_activity_time"].apply(

View File

@@ -0,0 +1,64 @@
from azure.iot.hub import IoTHubRegistryManager
from azure.iot.hub.protocol.models import QuerySpecification, Module
from azure.iot.hub.models import CloudToDeviceMethod, CloudToDeviceMethodResult
from dotenv import load_dotenv
from isight_device import iSightDevice
import json
import os
import pandas as pd
load_dotenv()
CONNECTION_STRING = str(os.getenv("CONNECTION_STRING_INOX_PROD"))
if CONNECTION_STRING == "":
print("Provide a connection string for the Iot Hub before running the script!")
exit(13)
registry_manager = IoTHubRegistryManager.from_connection_string(CONNECTION_STRING)
query_spec = QuerySpecification(query="SELECT * FROM devices WHERE IS_DEFINED(tags.site) AND capabilities.iotEdge = true ")
query_result = registry_manager.query_iot_hub(query_spec)
devices = []
for item in query_result.items:
devices.append(iSightDevice(str(item.device_id), str(item.tags['site']), int(item.tags['number']), str(item.tags['version'])))
devices.sort(key = lambda d: (d.site, d.number))
rows = []
for device in devices:
print(device, end="\t")
current_device_modules = registry_manager.get_modules(device.deviceId)
for module in current_device_modules:
if (module.module_id == "thingspro-agent"):
device.setModule(module)
method_name = "thingspro-api-v1"
payload = {
"method": "GET",
"path": "/device/general"
}
module_id = "thingspro-agent"
try:
direct_method = CloudToDeviceMethod(method_name = method_name, payload = payload)
response = registry_manager.invoke_device_module_method(device_id = device.deviceId, module_id = module_id, direct_method_request = direct_method)
#print(response)
#print(json.dumps(response.payload, indent = 2))
hostname = response.payload['data']['hostName']
serial = response.payload['data']['serialNumber']
version = response.payload['data']['firmwareVersion']
description = response.payload['data']['description']
print(hostname + " " + serial + " " + version + " " + description)
rows.append({
"hostname": hostname,
"site": device.getSite(),
"number": device.getNumber(),
"cloud_version": device.getVersion(),
"device_version": version
})
except Exception as e:
print(f"Error: {e}")
df = pd.DataFrame(rows)
df.to_excel("thingspro-version.xlsx", index=False)

View File

@@ -87,7 +87,7 @@ def set_ssh_status(base_url, token):
else: else:
raise raise
def activate_ssh(ip_address): def activate_ssh(ip_address, silent = False):
# Ensure the URL uses HTTPS # Ensure the URL uses HTTPS
url = ip_address url = ip_address
@@ -104,17 +104,23 @@ def activate_ssh(ip_address):
if not verify_ssl: if not verify_ssl:
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
if not silent:
print(f"HTTPS", end=" ", flush=True) print(f"HTTPS", end=" ", flush=True)
try: try:
token = authenticate(url) token = authenticate(url)
if not silent:
print(f"", end="", flush=True) print(f"", end="", flush=True)
except Exception as e: except Exception as e:
if not silent:
print(f"", flush=True) print(f"", flush=True)
raise raise
if not silent:
print(f"SSH", end=" ", flush=True) print(f"SSH", end=" ", flush=True)
try: try:
set_ssh_status(url, token) set_ssh_status(url, token)
if not silent:
print(f"", end="\n", flush=True) print(f"", end="\n", flush=True)
except Exception as e: except Exception as e:
if not silent:
print(f"", flush=True) print(f"", flush=True)
raise raise

View File

@@ -10,11 +10,11 @@ from azure.iot.hub.models import Twin, TwinProperties
load_dotenv(override=True) load_dotenv(override=True)
ip_address_prefix = "10.81.60." ip_address_prefix = "10.81.56."
ssh_command = "hostname" ssh_command = "hostname"
csv_filename = "Grandpuits_01.csv" csv_filename = "DK2_01.csv"
SITE_NAME = "Grandpuits" SITE_NAME = "DK2"
ssh_username = os.getenv("DEFAULT_CUBE_LINUX_ADMIN_USER") ssh_username = os.getenv("DEFAULT_CUBE_LINUX_ADMIN_USER")
ssh_password = os.getenv("DEFAULT_CUBE_LINUX_ADMIN_PASSWORD") ssh_password = os.getenv("DEFAULT_CUBE_LINUX_ADMIN_PASSWORD")

View File

@@ -6,12 +6,14 @@ import json
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
import time import time
from tqdm import tqdm
load_dotenv() load_dotenv()
# Function to authenticate and get token # Function to authenticate and get token
def authenticate(device_ip, payload): def authenticate(device_ip, payload):
auth_url = f"https://{device_ip}:8443/api/v1/auth" auth_url = f"https://{device_ip}:8443/api/v1/auth"
try:
response = requests.post(auth_url, json=payload, verify=False) response = requests.post(auth_url, json=payload, verify=False)
if response.status_code == 200: if response.status_code == 200:
token = response.json()["data"]["token"] token = response.json()["data"]["token"]
@@ -21,9 +23,11 @@ def authenticate(device_ip, payload):
else: else:
print(f"Authentication failed. Status code: {response.status_code}") print(f"Authentication failed. Status code: {response.status_code}")
return None return None
except Exception as e:
raise Exception("Authentication failed!") from e
# Function to send PATCH request # Function to update connection string through PATCH request
def send_patch_request(device_ip, token, connection_string): def update_connection_string(device_ip, token, connection_string):
headers = { headers = {
"mx-api-token": token "mx-api-token": token
} }
@@ -35,29 +39,33 @@ def send_patch_request(device_ip, token, connection_string):
} }
} }
patch_url = f"https://{device_ip}:8443/api/v1/azure-iotedge" patch_url = f"https://{device_ip}:8443/api/v1/azure-iotedge"
try:
response = requests.patch(patch_url, json=payload, headers=headers, verify=False) response = requests.patch(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200: if response.status_code == 200:
print(f"PATCH request successful for device {device_ip}") print(f"PATCH request successful for device {device_ip}")
else: else:
print(f"Failed to send PATCH request to device {device_ip}. Status code: {response.status_code}") print(f"Failed to send PATCH request to device {device_ip}. Status code: {response.status_code}")
except Exception as e:
raise Exception("Update connection string failed!") from e
# Function to send PATCH request # Function to update NTP
def patch_time(device_ip, token): def update_ntp(device_ip, token):
headers = { headers = {
"mx-api-token": token "mx-api-token": token
} }
# payload = { payload = {
# "ntp": { "ntp": {
# "source": "timeserver", "source": "timeserver",
# "server": "10.84.171.254", "server": "10.84.171.254",
# "enable": True "enable": True
# } }
# } }
payload = { payload = {
"timezone": "America/Chicago" "timezone": "America/Chicago"
} }
patch_url = f"https://{device_ip}:8443/api/v1/device/time" patch_url = f"https://{device_ip}:8443/api/v1/device/time"
try:
response = requests.patch(patch_url, json=payload, headers=headers, verify=False) response = requests.patch(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200: if response.status_code == 200:
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
@@ -69,11 +77,12 @@ def patch_time(device_ip, token):
print(time + " " + timezone + " " + last + " " + server + " " + str(enabled)) print(time + " " + timezone + " " + last + " " + server + " " + str(enabled))
else: else:
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
#print(json.dumps(json_data, indent=2)) except Exception as e:
raise Exception("Update NTP failed!") from e
# Function to send UPGRADE request # Function to create an upgrade job
def send_upgrade_request(device_ip, token, upgrade_url): def create_upgrade_job(device_ip, token, upgrade_url):
headers = { headers = {
"mx-api-token": token "mx-api-token": token
} }
@@ -83,13 +92,15 @@ def send_upgrade_request(device_ip, token, upgrade_url):
"url": upgrade_url, "url": upgrade_url,
} }
patch_url = f"https://{device_ip}:8443/api/v1/upgrades" patch_url = f"https://{device_ip}:8443/api/v1/upgrades"
try:
response = requests.post(patch_url, json=payload, headers=headers, verify=False) response = requests.post(patch_url, json=payload, headers=headers, verify=False)
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
#print(json.dumps(json_data, indent=4, sort_keys=True))
id = json_data['data']['id'] id = json_data['data']['id']
return id return id
except Exception as e:
raise Exception("Create upgrade job failed") from e
# Function to send UPGRADE request # Function to get upgrade job
def get_upgrade_job(device_ip, token, id): def get_upgrade_job(device_ip, token, id):
headers = { headers = {
"mx-api-token": token "mx-api-token": token
@@ -97,24 +108,22 @@ def get_upgrade_job(device_ip, token, id):
payload = { payload = {
} }
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/{id}" patch_url = f"https://{device_ip}:8443/api/v1/upgrades/{id}"
try:
response = requests.get(patch_url, json=payload, headers=headers, verify=False) response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200: if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#print(json_str)
#print(json_data['data'][json_data['count'] - 1]['parameter']['url'], json_data['data'][json_data['count'] - 1]['state'], json_data['count'])
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
getid = json_data['data']['id'] getid = json_data['data']['id']
created = json_data['data']['createdAt'] created = json_data['data']['createdAt']
started = json_data['data']['startedAt']
cur_status = json_data['data']['state'] cur_status = json_data['data']['state']
current_tasks = json_data['data']['completedTask'] current_tasks = json_data['data']['completedTask']
total_tasks = json_data['data']['totalTask'] total_tasks = json_data['data']['totalTask']
print("JOB #" + str(getid) + " " + str(current_tasks) + "/" + str(total_tasks)) print(f"Upgrade job #{str(getid)} ({str(current_tasks)}/{str(total_tasks)}) {str(cur_status)}")
print("CREATED ON: " + str(created))
print("CURRENT STATUS: " + str(cur_status))
print(json.dumps(json_data, indent=2))
else: else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}") print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content) print(response.content)
except Exception as e:
raise Exception("Failed getting upgrade job!") from e
def get_upgrade_jobs(device_ip, token): def get_upgrade_jobs(device_ip, token):
headers = { headers = {
@@ -123,11 +132,9 @@ def get_upgrade_jobs(device_ip, token):
payload = { payload = {
} }
patch_url = f"https://{device_ip}:8443/api/v1/upgrades" patch_url = f"https://{device_ip}:8443/api/v1/upgrades"
try:
response = requests.get(patch_url, json=payload, headers=headers, verify=False) response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200: if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#print(json_str)
#print(json_data['data'][json_data['count'] - 1]['parameter']['url'], json_data['data'][json_data['count'] - 1]['state'], json_data['count'])
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
count = json_data['count'] count = json_data['count']
print(str(count)) print(str(count))
@@ -140,12 +147,13 @@ def get_upgrade_jobs(device_ip, token):
print("JOB #" + str(getid) + " " + str(current_tasks) + "/" + str(total_tasks)) print("JOB #" + str(getid) + " " + str(current_tasks) + "/" + str(total_tasks))
print("CREATED ON: " + str(created)) print("CREATED ON: " + str(created))
print("CURRENT STATUS: " + str(cur_status)) print("CURRENT STATUS: " + str(cur_status))
print(json.dumps(json_data, indent=4, sort_keys=True))
else: else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}") print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content) print(response.content)
except Exception as e:
raise Exception("Failed getting all upgrade jobs!") from e
def get_last_job(device_ip, token): def get_last_upgrade_job(device_ip, token):
headers = { headers = {
"mx-api-token": token "mx-api-token": token
} }
@@ -155,9 +163,6 @@ def get_last_job(device_ip, token):
try: try:
response = requests.get(patch_url, json=payload, headers=headers, verify=False) response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200: if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#print(json_str)
#print(json_data['data'][json_data['count'] - 1]['parameter']['url'], json_data['data'][json_data['count'] - 1]['state'], json_data['count'])
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
last_job = int(json_data['count'] - 1) last_job = int(json_data['count'] - 1)
getid = json_data['data'][last_job]['id'] getid = json_data['data'][last_job]['id']
@@ -171,15 +176,14 @@ def get_last_job(device_ip, token):
for task in range(total_tasks): for task in range(total_tasks):
if json_data['data'][last_job]['tasks'][task]['type'] == "download": if json_data['data'][last_job]['tasks'][task]['type'] == "download":
print(f"Downloaded: {json_data['data'][last_job]['tasks'][task]['progress']}%") print(f"Downloaded: {json_data['data'][last_job]['tasks'][task]['progress']}%")
#print(json.dumps(json_data, indent=4, sort_keys=True))
return getid return getid
else: else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}") print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content) print(response.content)
except Exception as e: except Exception as e:
print(f"Connection failed {e}") raise Exception("Failed getting last upgrade job!") from e
# Function to send UPGRADE request # Function to start upgrade job
def start_upgrade_job(device_ip, token, id): def start_upgrade_job(device_ip, token, id):
headers = { headers = {
"mx-api-token": token "mx-api-token": token
@@ -187,6 +191,7 @@ def start_upgrade_job(device_ip, token, id):
payload = { payload = {
} }
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/{id}/start" patch_url = f"https://{device_ip}:8443/api/v1/upgrades/{id}/start"
try:
response = requests.put(patch_url, json=payload, headers=headers, verify=False) response = requests.put(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200: if response.status_code == 200:
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
@@ -196,51 +201,51 @@ def start_upgrade_job(device_ip, token, id):
else: else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}") print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode()) print(response.content.decode())
except Exception as e:
raise Exception("Failed starting upgrade job!") from e
# Function to send UPGRADE request # Function to send a PUT request
def put_API(device_ip, token): def put_API(device_ip, token):
headers = { headers = {
"mx-api-token": token "mx-api-token": token
} }
payload = { payload = {
} }
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/3/start" patch_url = "" #f"https://{device_ip}:8443/api/v1/upgrades/3/start"
try:
if patch_url == "":
raise Exception("Empty URL!")
response = requests.put(patch_url, json=payload, headers=headers, verify=False) response = requests.put(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200: if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#json_data = json.loads(response.content.decode())
#json_str = json.dumps(json_data)
#print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
print(json_data['data']['firmwareVersion']) print(json_data['data']['firmwareVersion'])
else: else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}") print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode()) print(response.content.decode())
except Exception as e:
raise Exception("Failed sending PUT request!") from e
def get_API(device_ip, token): def get_version(device_ip, token):
headers = { headers = {
"mx-api-token": token "mx-api-token": token
} }
payload = { payload = {
} }
patch_url = f"https://{device_ip}:8443/api/v1/device/general" patch_url = f"https://{device_ip}:8443/api/v1/device/general"
try:
response = requests.get(patch_url, json=payload, headers=headers, verify=False) response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200: if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#json_data = json.loads(response.content.decode())
#json_str = json.dumps(json_data)
#print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
hostname = json_data['data']['hostName'] hostname = json_data['data']['hostName']
serial = json_data['data']['serialNumber'] serial = json_data['data']['serialNumber']
version = json_data['data']['firmwareVersion'] version = json_data['data']['firmwareVersion']
description = json_data['data']['description'] description = json_data['data']['description']
print(hostname + " " + serial + " " + version + " " + description) print(hostname + " " + serial + " " + version + " " + description)
#json_str = json.dumps(json_data, indent=2)
#print(json_str)
else: else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}") print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode()) print(response.content.decode())
except Exception as e:
raise Exception("Failed getting version!") from e
def get_time(device_ip, token): def get_time(device_ip, token):
headers = { headers = {
@@ -249,22 +254,19 @@ def get_time(device_ip, token):
payload = { payload = {
} }
patch_url = f"https://{device_ip}:8443/api/v1/device/time" patch_url = f"https://{device_ip}:8443/api/v1/device/time"
try:
response = requests.get(patch_url, json=payload, headers=headers, verify=False) response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200: if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#json_data = json.loads(response.content.decode())
#json_str = json.dumps(json_data)
#print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
time = json_data['data']['time'] time = json_data['data']['time']
timezone = json_data['data']['timezone'] timezone = json_data['data']['timezone']
last = json_data['data']['lastUpdateTime'] last = json_data['data']['lastUpdateTime']
print(time + " " + timezone + " " + last) print(time + " " + timezone + " " + last)
#json_str = json.dumps(json_data, indent=2)
#print(json_str)
else: else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}") print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode()) print(response.content.decode())
except Exception as e:
raise Exception("Failed getting time!") from e
def delete_API(device_ip, token): def delete_API(device_ip, token):
headers = { headers = {
@@ -272,95 +274,63 @@ def delete_API(device_ip, token):
} }
payload = { payload = {
} }
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/5" patch_url = "" #f"https://{device_ip}:8443/api/v1/upgrades/5"
try:
if patch_url == "":
raise Exception("Empty URL!")
response = requests.delete(patch_url, json=payload, headers=headers, verify=False) response = requests.delete(patch_url, json=payload, headers=headers, verify=False)
print(response.status_code) print(response.status_code)
json_data = json.loads(response.content.decode()) json_data = json.loads(response.content.decode())
json_str = json.dumps(json_data, indent=2) json_str = json.dumps(json_data, indent=2)
print(json_str) print(json_str)
except Exception as e:
raise Exception("Failed sending DELETE request!") from e
# Read the Excel file def visual_wait(total_seconds):
# excel_file_path = "" # "total=total_seconds" sets the bar max value
# if excel_file_path == "": # "bar_format" removes the default stats to keep it clean
# print("Provide Excel file path before running the script!") with tqdm(total=total_seconds, bar_format="{desc} [{bar}]") as pbar:
# exit(11) # Loop backwards from 200 down to 1
# df = pd.read_excel(excel_file_path) for remaining in range(total_seconds, 0, -1):
# df = df[df["device_name"].notnull()] # Manually update the text description to show the countdown
pbar.set_description_str(f"Waiting {remaining}s")
# Iterate over each row in the DataFrame # Advance the visual bar by 1 step
pbar.update(1)
time.sleep(1)
# Final update to show 0s at the very end
pbar.set_description_str(f"Finished waiting!")
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# for index, row in df.iterrows():
# device_name = row['device_name']
# device_ip_address_https = row['device_ip_address_http']
# connection_string = row['connection_string']
# upgrade_url = "" #https://files.thingsprocloud.com/package/moxa-aig-301-series-includes-security-patch-firmware-v1.0.deb.yaml
# if upgrade_url == "":
# print("Provide upgrade URL before running the script!")
# exit(12)
# # Authenticate and get token
# payload_auth = {
# "acceptEULA": True,
# "name": "",
# "password": ""
# }
# if payload_auth["name"] == "" or payload_auth["password"] == "":
# print("Provide the credentials before running the script!")
# exit(10)
# print(device_name, end="")
# token = authenticate(device_ip_address_https, payload_auth)
# if token:
# get_API(device_ip_address_https, token)
# print("\n")
default_user = str(os.getenv("DEFAULT_MOXA_USER")) default_user = str(os.getenv("DEFAULT_MOXA_USER"))
default_password = str(os.getenv("DEFAULT_MOXA_PASSWORD")) default_password = str(os.getenv("DEFAULT_MOXA_PASSWORD"))
moxa_range = [i for i in range(131, 132) if i not in (136, 137)] moxa_range = [i for i in range(132, 159) ]
moxa_range.remove(137)
for i in moxa_range: for i in moxa_range:
device_ip_address = str("10.84.157." + str(i)) device_ip_address = str("10.84.157." + str(i))
print(device_ip_address, end=" ") print(device_ip_address)
payload_auth = { payload_auth = {
"acceptEULA": True, "acceptEULA": True,
"name": default_user, "name": default_user,
"password": default_password "password": default_password
} }
upgrade_url = "http://10.84.157.137:8080/1.8.1.yaml"
try:
token = authenticate(device_ip_address, payload_auth) token = authenticate(device_ip_address, payload_auth)
print(hash(token))
upgrade_url = "http://10.84.157.137:8080/1.7.0.yaml"
if token: if token:
#send_upgrade_request(device_ip_address, token, upgrade_url) get_version(device_ip_address, token)
#time.sleep(10) get_last_upgrade_job(device_ip_address, token)
id = get_last_job(device_ip_address, token) # id = create_upgrade_job(device_ip_address, token, upgrade_url)
#time.sleep(10) # visual_wait(3)
# start_upgrade_job(device_ip_address, token, id) # start_upgrade_job(device_ip_address, token, id)
#time.sleep(120) # visual_wait(3)
#input("Continue?") # get_upgrade_job(device_ip_address, token, id)
else: # visual_wait(30)
raise(Exception("Authentication failed!")) except Exception as e:
print(f"Exception for {device_ip_address}: {e}")
# upgrade_url = "https://10.84.157.137/Upgrade_AIG-301_2.5.0-4404_IMG_1.5_to_1.6.0.yaml" continue
# device_ip_address = str("10.84.157." + str(i))
# print(f"{device_ip_address}")
# #print(device_ip_address, end="")
# token = authenticate(device_ip_address, payload_auth)
# if token:
# #id = send_upgrade_request(device_ip_address,token,upgrade_url)
# #print(id)
# get_last_job(device_ip_address, token)
# #start_upgrade_job(device_ip_address, token, id)
# #put_API(device_ip_address, token)
# #patch_time(device_ip_address,token)
# #get_time(device_ip_address, token)
# #delete_API(device_ip_address,token)
# #get_API(device_ip_address, token)
# else:
# print("Authentication failed!")

View File

@@ -11,3 +11,4 @@ fabric
ruamel.yaml ruamel.yaml
netmiko netmiko
pexpect pexpect
tqdm

View File

@@ -175,6 +175,14 @@ def find_config_value(config_content, option):
# If the loop finishes without finding the option, return None # If the loop finishes without finding the option, return None
return None return None
def cloud_configuration_csv(result):
lightTelemetry = find_config_value(result, "light-telemetry")
telemetryOn = find_config_value(result, "telemetry-on")
compressionEnabled = find_config_value(result, "compression-enabled")
remoteUpdateOn = find_config_value(result, "remote-update-on")
connectionString = find_config_value(result, "connection-string")
return f"{lightTelemetry};{telemetryOn};{compressionEnabled};{remoteUpdateOn};{connectionString};"
def cloud_configuration_check(hostname, result, iot_hub, proxy_host, proxy_port): def cloud_configuration_check(hostname, result, iot_hub, proxy_host, proxy_port):
print(f"\tLight telemetry:", end=" ", flush=True) print(f"\tLight telemetry:", end=" ", flush=True)
status = find_config_value(result, "light-telemetry") status = find_config_value(result, "light-telemetry")
@@ -185,7 +193,7 @@ def cloud_configuration_check(hostname, result, iot_hub, proxy_host, proxy_port)
print(f"\tTelemetry:", end=" ", flush=True) print(f"\tTelemetry:", end=" ", flush=True)
status = find_config_value(result, "telemetry-on") status = find_config_value(result, "telemetry-on")
if status == "true": if status == "False":
print(f"", end="\n", flush=True) print(f"", end="\n", flush=True)
else: else:
print(f"") print(f"")
@@ -437,12 +445,55 @@ def write_remote_config_base64_sudo(c, remote_path, content, sudo_pass, user_own
# Re-raise the exception for the main loop. # Re-raise the exception for the main loop.
raise raise
def check_for_specific_curl_error(c):
def execute_command(c, command):
"""Executes a simple command on the remote device."""
try:
result = c.run(command, hide=True)
return result.stdout
except Exception as e:
raise
"""
Checks for the specific cURL exit code 35.
Args:
c: The connection object.
Returns:
True if the expected error is caught, False otherwise.
"""
try:
# We call execute_command, but expect it to fail and raise an exception
result = execute_command(c, "curl -m 15 -x https://10.81.35.126:8080 https://iot-ingest-ess-prod.azure-devices.net")
# If the command somehow succeeds, the expected error did not occur.
print(f"Success (unexpected): {result.strip()}", end="\n", flush=True)
return False
except Exception as e:
# The command failed as expected. Now, check if it's the RIGHT failure.
error_message = str(e)
# Check for the unique identifiers of your expected error.
is_exit_code_35 = "Exit code: 35" in error_message
is_ssl_version_error = "wrong version number" in error_message
if is_exit_code_35 and is_ssl_version_error:
# This is the exact error you were expecting.
# print("Caught expected cURL error (Exit code 35, SSL wrong version number).")
return True
else:
# This is a different, unexpected error.
print(f"\n[cURL] An unexpected exception occurred: {e}")
return False
def main(): def main():
"""Main function to parse arguments and orchestrate tasks.""" """Main function to parse arguments and orchestrate tasks."""
ip_address_prefix = "10.81.56." # DK2 subnet ip_address_prefix = "10.84.165." # DK2 subnet
ip_address_range = list(range(129, 145)) # From 129 to 144 (16 CUBEs) ip_address_range = list(range(131, 188)) # From 129 to 144 (16 CUBEs)
# ip_address_range.append(72) # Add 85 after 74. # ip_address_range.append(85) # Add 85 after 74.
hosts = [f"{ip_address_prefix}{suffix}" for suffix in ip_address_range] hosts = [f"{ip_address_prefix}{suffix}" for suffix in ip_address_range]
ssh_port = 11022 ssh_port = 11022
@@ -459,34 +510,47 @@ def main():
for host in hosts: for host in hosts:
print(f"{host}", end=" - ", flush=True) #print(f"{host}", end=" - ", flush=True)
hostname = "" hostname = ""
result = "" result = ""
try: try:
activate_ssh(host) activate_ssh(host, True)
except Exception as e: except Exception as e:
print(f"Exception: {e}") print(f"Exception: {e}")
continue continue
with Connection(host=host, user=ssh_user, port=ssh_port, connect_timeout=60, connect_kwargs=connect_args) as c: with Connection(host=host, user=ssh_user, port=ssh_port, connect_timeout=60, connect_kwargs=connect_args) as c:
# try:
# print(f"Hostname:", end=" ", flush=True)
# result = execute_command(c, "hostname")
# print(f"{result.strip()}", end="\n", flush=True)
# hostname = str.lower(result)
# except Exception as e:
# print(f"[Hostname] Exception: {e}")
# continue
# print(f"cURL:", end=" ", flush=True)
# result = check_for_specific_curl_error(c)
# if result:
# print(f"✅", end="\n", flush=True)
# else:
# print(f"❌", end="\n", flush=True)
try: try:
print(f"Hostname:", end=" ", flush=True)
result = execute_command(c, "hostname") result = execute_command(c, "hostname")
print(f"{result.strip()}", end="\n", flush=True) print(f"{host};{result.strip()}", end=";", flush=True)
hostname = str.lower(result) hostname = str.lower(result)
except Exception as e: except Exception as e:
print(f"[Hostname] Exception: {e}") print(f"{host};ERROR")
continue continue
try: try:
print(f"cURL:", end=" ", flush=True) result = read_remote_config_sudo(c, "/etc/cube/config-azure.properties", ssh_password)
result = execute_command(c, "curl -m 15 -x https://10.81.35.126:8080 https://iot-ingest-ess-prod.azure-devices.net") print(cloud_configuration_csv(result))
print(f"{result.strip()}", end="\n", flush=True)
except Exception as e: except Exception as e:
print(f"[cURL] Exception: {e}")
continue continue
# try: # try:
@@ -508,6 +572,35 @@ def main():
# continue # continue
# cloud_configuration_check(hostname, result, "iot-ingest-ess-prod.azure-devices.net", "10.81.35.126", "8080") # cloud_configuration_check(hostname, result, "iot-ingest-ess-prod.azure-devices.net", "10.81.35.126", "8080")
# result_telemetry_off = set_config_field(result, "telemetry-on", False)
# result = result_telemetry_off
# cloud_configuration_check(hostname, result, "iot-ingest-ess-prod.azure-devices.net", "10.81.35.126", "8080")
# try:
# write_remote_config_sudo(c, "/etc/cube/config-azure.properties", result, ssh_password, "cube", "root", "644")
# print(f"✅", end="\n", flush=True)
# except Exception as e:
# print(f"❌", end="\n", flush=True)
# print(f"[Proxy configuration] Exception: {e}")
# continue
# print(f"Checking Cloud configuration:", end=" ", flush=True)
# try:
# result = read_remote_config_sudo(c, "/etc/cube/config-azure.properties", ssh_password)
# print(f"✅", end="\n", flush=True)
# except Exception as e:
# print(f"❌", end="\n", flush=True)
# print(f"[Proxy verification] Exception: {e}")
# continue
# try:
# print(f"Restarting cube-web-cloudagent: ", end=" ", flush=True)
# execute_sudo_command(c, "systemctl restart cube-web-cloudagent", ssh_password)
# print(f"✅", end="\n", flush=True)
# except Exception as e:
# print(f"❌", end="\n", flush=True)
# print(f"[Restarting cube-web-cloudagent] Exception: {e}")
# continue
# print(f"Setting proxy configuration:", end="\n", flush=True) # print(f"Setting proxy configuration:", end="\n", flush=True)
# result_proxy_host = set_config_field(result, "proxy-host", "10.81.35.126", True) # result_proxy_host = set_config_field(result, "proxy-host", "10.81.35.126", True)