Compare commits

..

17 Commits

22 changed files with 809 additions and 32 deletions

View File

@ -1,3 +1,5 @@
These will be my windows ansible environment
Matt-Cloud Windows Ansible Platform
I need to put it up on Github to sync jenkinsfiles
This will run in my jenkins instance at https://jenkins.matt-cloud.com
Since I am building this out after getting experienced in ansible & jenkins, I will set it up securely so I can share it all

5
ansible.cfg Normal file
View File

@ -0,0 +1,5 @@
[defaults]
roles_path = /var/jenkins_home/ansible-windows/roles
ansible_root = /var/jenkins_home/ansible-windows

187
inventory/inventory.sh Executable file
View File

@ -0,0 +1,187 @@
#!/bin/bash
# Dynamic inventory generation script ansible windows
# Function to display usage
usage() {
echo "Windows Ansible Dynamic Inventory File Generation Script"
echo "Usage: $0 -i IP_LIST -u JENKINS_USER -g JENKINS_GROUP -w WINDOWS_USER -p ANSIBLE_PASSWORD [-a SERVER_SUBNET_GROUP] [-s] [-v] [-e]"
echo "Options:"
echo " -i IP_LIST Comma-separated list of IPs. Will not fail if blank, but why 0_o"
echo " -u JENKINS_USER Jenkins user"
echo " -g JENKINS_GROUP Jenkins primary group"
echo " -a SERVER_SUBNET_GROUP Jenkins group for SSH access, need to pass something when called"
echo " -w WINDOWS_USER Windows user"
echo " -p ANSIBLE_PASSWORD Password for the service account (Windows user)"
echo " -q Be quieter"
echo " -s Set variable to true if more than one IP is passed"
echo " -v Display Ansible Version"
exit 1
}
# Initialize variables with default values
skip=false
more_than_one=false
display_version=false
allsubnet_group=missing
be_quiet=false
# Parse command line options
while getopts ":i:u:w:p:g:a:svq" opt; do
case ${opt} in
i ) # process option i
IP_LIST=$OPTARG
;;
u ) # process option u
JENKINS_USER=$OPTARG
;;
w ) # process option w
WINDOWS_USER=$OPTARG
;;
p ) # process option p
ANSIBLE_PASSWORD=$OPTARG
;;
g ) # process option g
JENKINS_GROUP=$OPTARG
;;
s ) # process option s
skip=true
;;
v ) # process option v
display_version=true
;;
q ) # process option q
be_quiet=true
;;
a ) # process option a
allsubnet_group=$OPTARG
;;
\? ) usage
;;
esac
done
shift $((OPTIND -1))
# Check if all required options are provided
if [ -z "$JENKINS_USER" ] || [ -z "$JENKINS_GROUP" ] || [ -z "$WINDOWS_USER" ] || [ -z "$ANSIBLE_PASSWORD" ]; then
usage
fi
if $display_version; then
if ! $be_quiet; then
echo "Showing ansible version"
ansible --version
fi
fi
# Generate an 8-character hash from the IP list
hash=$(echo -n "$IP_LIST" | md5sum | cut -c 1-8)
if ! $be_quiet; then
echo "IP List:"
echo $IP_LIST
echo $hash
fi
# Define the inventory file path with the hash
inventory_file="/var/jenkins_home/ansible-windows/.inv/inventory-$hash.yml"
if $skip; then
IFS=',' read -ra IPS <<< "$IP_LIST"
if [ ${#IPS[@]} -gt 1 ]; then
more_than_one=true
fi
fi
if $skip; then
if ! $be_quiet; then
echo "Single host option set"
fi
if $more_than_one; then
if ! $be_quiet; then
echo "IP list provided, inventory will be emptied"
fi
IP_LIST=""
fi
fi
# Initialize the YAML inventory content
inventory_content="---
all:
hosts:
"
# Loop through each IP in the comma-separated list
# skip if restricted user and subnet
IFS=',' read -ra IPS <<< "$IP_LIST"
for IP in "${IPS[@]}"; do
ip_check=$(curl -s http://172.25.100.15:15010/ip_check?ip=${IP} | jq .in_subnets)
# if this is a restricted subnet, then check the group
if $ip_check; then
if ! $be_quiet; then
echo "Subnet restricted, checking group membership"
fi
if [ "$allsubnet_group" == "$SERVER_SUBNET_GROUP" ]; then
if ! $be_quiet; then
echo "IP Check Passed, adding endpoint ${IP} to inventory"
fi
inventory_content+=" ${IP}:
ansible_host: ${IP}
"
else
if ! $be_quiet; then
echo "Warning: User ${JENKINS_USER} not member of ${SERVER_SUBNET_GROUP}!"
echo "Auth Check Failed for endpoint ${IP}, not adding to inventory"
fi
fi
# if the subnet is not restricted, just add the endpoint to the inventory
else
if ! $be_quiet; then
echo "Unrestricted subnet, adding endpoint ${IP} to inventory"
fi
inventory_content+=" ${IP}:
ansible_host: ${IP}
"
fi
done
inventory_content+=" vars:
# windows user info
ansible_user: ${WINDOWS_USER}
ansible_password: '${ANSIBLE_PASSWORD}'
ansible_become_user: ${WINDOWS_USER}
ansible_become_pass: '${ANSIBLE_PASSWORD}'
# ansible connection info
ansible_connection: winrm
ansible_winrm_transport: basic
ansible_winrm_server_cert_validation: ignore
ansible_winrm_scheme: http
ansible_winrm_port: 5985
# jenkins user info
jenkins_user: '${JENKINS_USER}'
jenkins_group: '${JENKINS_GROUP}'
subnet_group_check: '${allsubnet_group}'
SERVER_SUBNET_GROUP: '${SERVER_SUBNET_GROUP}'
# other variables
ansible_python_interpreter: /usr/bin/python3
"
# Write the inventory content to the file
echo "$inventory_content" > $inventory_file
# secure inventory file
if ! $be_quiet; then
echo "Securing inventory file"
fi
chmod 700 $inventory_file
# echo inventory
if ! $be_quiet; then
echo "Inventory file created at $inventory_file with the following content:"
cat $inventory_file
fi

View File

@ -0,0 +1,75 @@
pipeline {
agent any
// Define parameters
parameters {
string(name: 'host_ip', description: 'Target System Address')
string(name: 'api_service_port', defaultValue: "5000", description: 'API Service Port, probably don\'t change this')
// reference for later
// choice(name: 'DEPLOY_ENV', choices: ['dev', 'staging', 'prod'], description: 'Environment to deploy to')
// booleanParam(name: 'rename_host', defaultValue: true, description: 'When checked hostname will be renamed')
// booleanParam(name: 'config_matt', defaultValue: true, description: 'config matt profile')
}
environment {
ANSIBLE_FORCE_COLOR = '1'
ansible_service_windows = credentials(' ansible-service-windows')
}
options {
ansiColor('xterm')
}
stages {
stage('Generate Inventory File') {
steps {
// Generate the dynamic inventory file
// Usage: $0 -i IP_LIST -u JENKINS_USER -g JENKINS_GROUP -w WINDOWS_USER -p ANSIBLE_PASSWORD [-a SERVER_SUBNET_GROUP] [-s] [-v] [-e]"
sh """
jenkins_group=\$(echo ${env.BUILD_USER_GROUPS} | sed 's/,/\\n/g' | grep -v \$SERVER_SUBNET_GROUP | grep Jenkins | head -n 1)
jenkins_subnet_group=\$(echo ${env.BUILD_USER_GROUPS} | sed 's/,/\\n/g' | grep -e authenticated -e \$SERVER_SUBNET_GROUP | sort -rf | head -n 1)
jenkins_user=\$(echo ${env.BUILD_USER})
cd /var/jenkins_home/ansible-windows
chmod +x /var/jenkins_home/ansible-windows/inventory/inventory.sh
/var/jenkins_home/ansible-windows/inventory/inventory.sh -a \$jenkins_subnet_group -g \$jenkins_group -u \$jenkins_user -w ${env.ansible_service_windows_USR} -p ${env.ansible_service_windows_PSW} -i ${params.host_ip}
"""
}
}
stage('Ansible Playbook') {
steps {
sh """
echo Generate Hash
echo ${params.host_ip}
hash=\$(echo -n ${params.host_ip} | md5sum | cut -c 1-8)
inventory_file="/var/jenkins_home/ansible-windows/.inv/inventory-\$hash.yml"
playbook_file="/var/jenkins_home/ansible-windows/playbooks/disk_service.yaml"
cd /var/jenkins_home/ansible-windows
ansible-playbook -i \$inventory_file \$playbook_file \
--ssh-common-args='-o StrictHostKeyChecking=no' \
--extra-vars "api_service_port=${params.api_service_port}"
"""
}
}
}
post {
always {
// Remove dynamic Inventory file
sh """
hash=\$(echo -n "${params.host_ip}" | md5sum | cut -c 1-8)
inventory_file="/var/jenkins_home/ansible-windows/.inv/inventory-\$hash.yml"
rm \$inventory_file
"""
}
}
}

View File

@ -0,0 +1,73 @@
pipeline {
agent any
// Define parameters
parameters {
string(name: 'host_ip', description: 'Target System Address')
// reference for later
// choice(name: 'DEPLOY_ENV', choices: ['dev', 'staging', 'prod'], description: 'Environment to deploy to')
// booleanParam(name: 'rename_host', defaultValue: true, description: 'When checked hostname will be renamed')
// booleanParam(name: 'config_matt', defaultValue: true, description: 'config matt profile')
}
environment {
ANSIBLE_FORCE_COLOR = '1'
ansible_service_windows = credentials(' ansible-service-windows')
}
options {
ansiColor('xterm')
}
stages {
stage('Generate Inventory File') {
steps {
// Generate the dynamic inventory file
// Usage: $0 -i IP_LIST -u JENKINS_USER -g JENKINS_GROUP -w WINDOWS_USER -p ANSIBLE_PASSWORD [-a SERVER_SUBNET_GROUP] [-s] [-v] [-e]"
sh """
jenkins_group=\$(echo ${env.BUILD_USER_GROUPS} | sed 's/,/\\n/g' | grep -v \$SERVER_SUBNET_GROUP | grep Jenkins | head -n 1)
jenkins_subnet_group=\$(echo ${env.BUILD_USER_GROUPS} | sed 's/,/\\n/g' | grep -e authenticated -e \$SERVER_SUBNET_GROUP | sort -rf | head -n 1)
jenkins_user=\$(echo ${env.BUILD_USER})
cd /var/jenkins_home/ansible-windows
chmod +x /var/jenkins_home/ansible-windows/inventory/inventory.sh
/var/jenkins_home/ansible-windows/inventory/inventory.sh -a \$jenkins_subnet_group -g \$jenkins_group -u \$jenkins_user -w ${env.ansible_service_windows_USR} -p ${env.ansible_service_windows_PSW} -i ${params.host_ip}
"""
}
}
stage('Ansible Playbook') {
steps {
sh """
echo Generate Hash
echo ${params.host_ip}
hash=\$(echo -n ${params.host_ip} | md5sum | cut -c 1-8)
inventory_file="/var/jenkins_home/ansible-windows/.inv/inventory-\$hash.yml"
playbook_file="/var/jenkins_home/ansible-windows/playbooks/server_init.yaml"
cd /var/jenkins_home/ansible-windows
ansible-playbook -i \$inventory_file \$playbook_file \
--ssh-common-args='-o StrictHostKeyChecking=no'
"""
}
}
}
post {
always {
// Remove dynamic Inventory file
sh """
hash=\$(echo -n "${params.host_ip}" | md5sum | cut -c 1-8)
inventory_file="/var/jenkins_home/ansible-windows/.inv/inventory-\$hash.yml"
rm \$inventory_file
"""
}
}
}

View File

@ -13,19 +13,7 @@ pipeline {
environment {
ANSIBLE_FORCE_COLOR = '1'
SATURN_BEHEMOTH = credentials('SATURN_BEHEMOTH')
pxe_proxy_password = credentials('pxe_proxy_password')
PXE_API_KEY = credentials('PXE_API_KEY')
LINUX_LDAP_PWD = credentials('LINUX_LDAP')
AUTHORIZED_KEY = credentials('AUTH_SSH_KEY')
TERRA_BEHEMOTH_SMB = credentials('TERRA_BEHEMOTH_SMB')
MATT_PASSWORD = credentials('MATT_PASSWORD')
matt_public_key = credentials('matt_public_key')
matt_private_key = credentials('matt_private_key')
cosmos_password = credentials('cosmos_password')
cosmos_root_password = credentials('cosmos_root_password')
vm_party_username_password = credentials('cosmos_root_password')
is_admin = '0'
ansible_service_windows = credentials(' ansible-service-windows')
}
options {
@ -33,19 +21,20 @@ pipeline {
}
stages {
stage('Generate Inventory File') {
steps {
// Generate the dynamic inventory file
// Usage: $0 -i IP_LIST -u JENKINS_USER -g JENKINS_GROUP -w WINDOWS_USER -p ANSIBLE_PASSWORD [-a SERVER_SUBNET_GROUP] [-s] [-v] [-e]"
sh """
jenkins_group=\$(echo ${env.BUILD_USER_GROUPS} | sed 's/,/\\n/g' | grep -v \$SERVER_SUBNET_GROUP | grep Jenkins | head -n 1)
jenkins_subnet_group=\$(echo ${env.BUILD_USER_GROUPS} | sed 's/,/\\n/g' | grep -e authenticated -e \$SERVER_SUBNET_GROUP | sort -rf | head -n 1)
jenkins_user=\$(echo ${env.BUILD_USER})
cd /var/jenkins_home/ansible
chmod +x /var/jenkins_home/ansible/inventory/inventory.sh
/var/jenkins_home/ansible/inventory/inventory.sh -v -s -a \$jenkins_subnet_group -g \$jenkins_group -u \$jenkins_user -i ${params.host_ip}
cd /var/jenkins_home/ansible-windows
chmod +x /var/jenkins_home/ansible-windows/inventory/inventory.sh
/var/jenkins_home/ansible-windows/inventory/inventory.sh -v -s -a \$jenkins_subnet_group -g \$jenkins_group -u \$jenkins_user -w ${env.ansible_service_windows_USR} -p ${env.ansible_service_windows_PSW} -i ${params.host_ip}
"""
}
@ -54,22 +43,17 @@ pipeline {
stage('Ansible Playbook') {
steps {
sh """
echo Generate Hash
echo ${params.host_ip}
hash=\$(echo -n ${params.host_ip} | md5sum | cut -c 1-8)
inventory_file="/var/jenkins_home/ansible/.inv/inventory-\$hash.yml"
cd /var/jenkins_home/ansible
inventory_file="/var/jenkins_home/ansible-windows/.inv/inventory-\$hash.yml"
playbook_file="/var/jenkins_home/ansible-windows/playbooks/test.yaml"
echo ansible-playbook -i \$inventory_file /var/jenkins_home/ansible/playbooks/test.yaml \
--ssh-common-args='-o StrictHostKeyChecking=no'\
--extra-vars "saturn_behemoth=${SATURN_BEHEMOTH} linux_ldap_pwd=${LINUX_LDAP_PWD} \
pxe_proxy_password=${pxe_proxy_password} PXE_API_KEY=${PXE_API_KEY} \
AUTHORIZED_KEY=${AUTHORIZED_KEY} TERRA_BEHEMOTH_SMB=${TERRA_BEHEMOTH_SMB} \
CIFS_USERNAME=${env.TERRA_BEHEMOTH_SMB_USR} CIFS_PASSWORD=${env.TERRA_BEHEMOTH_SMB_PSW} \
MATT_PASSWORD=${env.MATT_PASSWORD} host_ip=${params.host_ip} \
matt_public_key='${env.matt_public_key}' matt_private_key='${env.matt_private_key}' \
cosmos_password='${env.cosmos_password}' cosmos_root_password='${env.cosmos_root_password}' \
vm_party_username_password=${env.vm_party_username_password} }"
cd /var/jenkins_home/ansible-windows
ansible-playbook -i \$inventory_file \$playbook_file \
--ssh-common-args='-o StrictHostKeyChecking=no'
"""
}
}
@ -80,7 +64,7 @@ pipeline {
// Remove dynamic Inventory file
sh """
hash=\$(echo -n "${params.host_ip}" | md5sum | cut -c 1-8)
inventory_file="/var/jenkins_home/ansible/.inv/inventory-\$hash.yml"
inventory_file="/var/jenkins_home/ansible-windows/.inv/inventory-\$hash.yml"
rm \$inventory_file
"""

View File

@ -0,0 +1,15 @@
---
- name: Set up disk inventory service
hosts: all
become: yes
become_method: runas
roles:
- show_user_vars
- cosmos_init
- storage_api
...

View File

@ -0,0 +1,13 @@
---
- name: Matt-Cloud Windows VM Server Initialze
hosts: all
become: yes
become_method: runas
roles:
- show_user_vars
- cosmos_init
...

13
playbooks/test.yaml Normal file
View File

@ -0,0 +1,13 @@
---
- name: Ansible Windows Test
hosts: all
become: yes
become_method: runas
roles:
- show_user_vars
- display_hostname
...

View File

@ -0,0 +1,17 @@
---
windows_base_packages:
- googlechrome
- 7zip
- vlc
- windirstat
- putty
windows_features:
- NET-Framework-Features
- Telnet-Client
- Windows-Server-Backup
- RSAT-Print-Services
- RSAT-File-Services
...

View File

@ -0,0 +1,48 @@
---
- name: Install base packages
win_chocolatey:
name:
- "{{ windows_base_packages_item }}"
state: present
loop: "{{ windows_base_packages }}"
loop_control:
loop_var: windows_base_packages_item
- name: Install Server Services
ansible.windows.win_feature:
name:
- "{{ windows_features_item }}"
state: present
loop: "{{ windows_features }}"
loop_control:
loop_var: windows_features_item
- name: Disable ms_tcpip6 of all the Interface
community.windows.win_net_adapter_feature:
interface: '*'
state: disabled
component_id:
- ms_tcpip6
- name: disable IE Enhanced Security
block:
- name: disable for user
win_shell: 'Set-ItemProperty -Path "HKLM:\\SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}" -Name "IsInstalled" -Value 0'
- name: disable for admin
win_shell: 'Set-ItemProperty -Path "HKLM:\\SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}" -Name "IsInstalled" -Value 0'
- name: disable automatic updates
ansible.windows.win_regedit:
path: HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\AU
name: NoAutoUpdate
data: 1
- name: disable Firewall
win_shell: "netsh advfirewall set allprofiles state off"
...

View File

@ -0,0 +1,22 @@
---
- name: Check hostname
ansible.windows.win_command: hostname
register: hostname_output
- name: display hostname
debug:
msg: "Hostname: {{ hostname_output.stdout_lines[0] }}"
- name: Test API
win_shell: "C:\\Windows\\system32\\curl --silent http://{{ ansible_ssh_host }}:5000/disk"
register: api_test_output
- name: Show Test Results
debug:
msg: "{{ api_test_output.stdout_lines }}"
...

View File

@ -0,0 +1,14 @@
---
- name: show user vars
debug:
msg:
- "User email............ {{ jenkins_user}}"
- "Jenkins Group......... {{ jenkins_group}}"
- "SERVER_SUBNET_GROUP... {{ SERVER_SUBNET_GROUP }}"
- "subnet_group_check.... {{ subnet_group_check }}"
- "Host IP............... {{ ansible_ssh_host }}"
...

View File

@ -0,0 +1,3 @@
This role will install an API at port 5000 to get disk capacity data and disk health
This is used with the storage site visible to members of the disk-api group at groups.matt-cloud.com

View File

@ -0,0 +1,21 @@
---
cosmos_root_folder: "C:\\programdata\\cosmos"
python_service_root: "{{ cosmos_root_folder }}\\python"
storage_api_root: "{{ python_service_root }}\\disk_api"
python_venv: "{{storage_api_root}}\\venv"
python_venv_bin: "{{ python_venv }}\\Scripts\\python.exe"
python_venv_pip_bin: "{{ python_venv }}\\Scripts\\pip.exe"
nssm_folder: "{{ cosmos_root_folder }}\\nssm"
disk_service_name: "disk_api"
api_service_port: "5000"
...

View File

@ -0,0 +1,2 @@
Flask
psutil

View File

@ -0,0 +1,19 @@
---
###############################################
# Disk API Windows Service
###############################################
- name: set up python venv
include_tasks: python_venv.yaml
- name: build python exe
include_tasks: python_service.yaml
- name: set up nssm service
include_tasks: nssm.yaml
- name: set up scheduled task
include_tasks: update_task.yaml
...

View File

@ -0,0 +1,49 @@
---
- name: Copy CrystalDiskInfo archive
ansible.windows.win_copy:
src: /var/jenkins_home/ansible-files/programs/CrystalDiskInfo.zip
dest: "{{ storage_api_root }}\\CrystalDiskInfo.zip"
- name: Extract CrystalDiskInfo archive
community.windows.win_unzip:
src: "{{ storage_api_root }}\\CrystalDiskInfo.zip"
dest: "{{ storage_api_root }}\\dist\\"
- name: Install nssm
win_chocolatey:
name: nssm
state: present
- name: Install disk_api service
community.windows.win_nssm:
name: "{{ disk_service_name }}"
application: "{{ storage_api_root }}\\dist\\disk_service.exe"
- name: Set disk_api service startup auto and start
ansible.windows.win_service:
name: "{{ disk_service_name }}"
start_mode: auto
state: started
register: disk_service_status
- name: Show service result
debug:
msg:
- "name........ {{ disk_service_status.name }}"
- "exists...... {{ disk_service_status.exists }}"
- "path........ {{ disk_service_status.path }}"
- "start_mode.. {{ disk_service_status.start_mode }}"
- "state....... {{ disk_service_status.state }}"
- "username.... {{ disk_service_status.username }}"
- "failed...... {{ disk_service_status.failed }}"
- name: Test API
win_shell: "C:\\Windows\\system32\\curl http://{{ ansible_ssh_host }}:5000/disk"
register: api_test_output
- name: Show Test Results
debug:
msg: "{{ api_test_output.stdout_lines }}"
...

View File

@ -0,0 +1,47 @@
---
- name: Create service working folder
ansible.windows.win_file:
path: "{{ storage_api_root }}"
state: directory
- name: Stop service if running
ignore_errors: yes
ansible.windows.win_service:
name: "{{ disk_service_name }}"
state: stopped
- name: Check hostname
ansible.windows.win_command: hostname
register: hostname_output
- name: display hostname
debug:
msg: "Hostname: {{ hostname_output.stdout_lines[0] }}"
- name: Copy disk_service.py
ansible.windows.win_template:
src: disk_service.py
dest: "{{ storage_api_root }}\\disk_service.py"
- name: install pyinstaller
win_shell: "{{ python_venv_bin }} -m pip install pyinstaller"
- name: compile binary
become: no
win_shell: "{{ python_venv }}\\Scripts\\pyinstaller.exe -F {{ storage_api_root }}\\disk_service.py"
args:
chdir: "{{ storage_api_root }}"
- name: Open up port 5000
community.windows.win_firewall_rule:
name: _ansible_python_disk_service
description: "Firewall rule to allow traffic for Disk info API"
localport: 5000
action: allow
direction: in
protocol: tcp
state: present
enabled: true
...

View File

@ -0,0 +1,31 @@
---
- name: Ensure Python is installed
win_chocolatey:
name: python
state: present
- name: Create venv folder
ansible.windows.win_file:
path: "{{ python_venv }}"
state: directory
- name: Copy requirements.txt
ansible.windows.win_copy:
src: requirements.txt
dest: "{{ python_venv }}\\requirements.txt"
- name: Create virtual environment
win_shell: "python -m venv {{ python_venv }}"
- name: Upgrade pip in the virtual environment
win_shell: "{{ python_venv_bin }} -m pip install --upgrade pip"
args:
chdir: "{{ python_venv }}"
- name: Install Python dependencies from requirements.txt
win_shell: "{{ python_venv_bin }} -m pip install -r {{ python_venv }}\\requirements.txt"
args:
chdir: "{{ python_venv }}"
...

View File

@ -0,0 +1,20 @@
---
- name: Create Scheduled Task to run crystaldiskinfo
win_scheduled_task:
name: Update CrystalDiskInfo Cache File
username: SYSTEM
actions:
- path: "{{ storage_api_root }}\\dist\\DiskInfo64.exe"
arguments: |
/CopyExit
triggers:
- type: registration
- type: daily
start_boundary: '{{ ansible_date_time.date }}T01:00:00'
- type: boot
state: present
enabled: yes
...

View File

@ -0,0 +1,117 @@
from flask import Flask, jsonify
import psutil
import os
app = Flask(__name__)
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True
# Bits to Bytes etc
def bytes_to_human_readable(bytes):
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes < 1024.0:
return f"{bytes:.2f} {unit}"
bytes /= 1024.0
# Parse cache and return results
def get_crystal_disk_info():
try:
# Read the generated DiskInfo.txt file
with open("DiskInfo.txt", "r") as file:
output = file.read()
# Initialize a list to hold each drive's data
drives = []
# Split the file content into sections for each drive
drive_sections = output.split('----------------------------------------------------------------------------')
for section in drive_sections:
lines = section.strip().splitlines()
data = {
"Hostname": None,
"Disk Size": None,
"Model": None,
"Serial Number": None,
"Firmware": None,
"Temperature": None,
"Health Status": None,
"Power On Hours": None,
"Power On Count": None,
"Host Writes": None,
"Wear Level Count": None,
"Drive Letter": None
}
for line in lines:
if "Model" in line:
if ":" in line:
data["Model"] = line.split(":", 1)[1].strip()
elif "Serial Number" in line:
if ":" in line:
data["Serial Number"] = line.split(":", 1)[1].strip()
elif "Firmware" in line:
if ":" in line:
data["Firmware"] = line.split(":", 1)[1].strip()
elif "Temperature" in line:
if ":" in line:
data["Temperature"] = line.split(":", 1)[1].strip()
elif "Health Status" in line:
if ":" in line:
data["Health Status"] = line.split(":", 1)[1].strip()
elif "Power On Hours" in line:
if ":" in line:
data["Power On Hours"] = line.split(":", 1)[1].strip()
elif "Power On Count" in line:
if ":" in line:
data["Power On Count"] = line.split(":", 1)[1].strip()
elif "Host Writes" in line:
if ":" in line:
data["Host Writes"] = line.split(":", 1)[1].strip()
elif "Wear Level Count" in line:
if ":" in line:
data["Wear Level Count"] = line.split(":", 1)[1].strip()
elif "Drive Letter" in line:
if ":" in line:
data["Drive Letter"] = line.split(":", 1)[1].strip()
elif "Disk Size" in line:
if ":" in line:
data["Disk Size"] = line.split(":", 1)[1].strip()
if any(value is not None for value in data.values()):
drives.append(data)
data["Hostname"] = "{{ hostname_output.stdout_lines[0] }}"
if not drives:
raise ValueError("No drive data found")
return {"drives": drives}
except Exception as e:
return {"error": str(e)}
# Disk Info Function
def get_disk_info():
disk_info = []
partitions = psutil.disk_partitions()
for partition in partitions:
usage = psutil.disk_usage(partition.mountpoint)
disk_info.append({
'device': partition.device.replace('\\\\', '\\').rstrip('\\'),
#'mountpoint': partition.mountpoint,
#'fstype': partition.fstype,
'total': bytes_to_human_readable(usage.total),
'used': bytes_to_human_readable(usage.used),
'free': bytes_to_human_readable(usage.free),
'percent': usage.percent
})
return disk_info
# Flask endpoints
@app.route('/disk', methods=['GET'])
def disk():
return jsonify(get_disk_info())
@app.route('/health', methods=['GET'])
def drive_health():
return jsonify(get_crystal_disk_info())
if __name__ == '__main__':
app.run(host='0.0.0.0', port={{ api_service_port }})