Merge branch 'optional-tickets' into dev

* Fixes #36
This commit is contained in:
2Shirt 2018-05-17 21:02:17 -06:00
commit 0a8db0a3d9
9 changed files with 130 additions and 41 deletions

View file

@ -1,5 +1,7 @@
# Wizard Kit: Functions - Backup # Wizard Kit: Functions - Backup
import ctypes
from functions.disk import * from functions.disk import *
# Regex # Regex
@ -30,9 +32,41 @@ def backup_partition(disk, par):
def fix_path(path): def fix_path(path):
"""Replace invalid filename characters with underscores.""" """Replace invalid filename characters with underscores."""
return REGEX_BAD_PATH_NAMES.sub('_', path) local_drive = path[1:2] == ':'
new_path = REGEX_BAD_PATH_NAMES.sub('_', path)
if local_drive:
new_path = '{}:{}'.format(new_path[0:1], new_path[2:])
return new_path
def prep_disk_for_backup(destination, disk, ticket_number): def get_volume_display_name(mountpoint):
"""Get display name from volume mountpoint and label, returns str."""
name = mountpoint
try:
kernel32 = ctypes.windll.kernel32
vol_name_buffer = ctypes.create_unicode_buffer(1024)
fs_name_buffer = ctypes.create_unicode_buffer(1024)
serial_number = None
max_component_length = None
file_system_flags = None
vol_info = kernel32.GetVolumeInformationW(
ctypes.c_wchar_p(mountpoint),
vol_name_buffer,
ctypes.sizeof(vol_name_buffer),
serial_number,
max_component_length,
file_system_flags,
fs_name_buffer,
ctypes.sizeof(fs_name_buffer)
)
name = '{} "{}"'.format(name, vol_name_buffer.value)
except:
pass
return name
def prep_disk_for_backup(destination, disk, backup_prefix):
"""Gather details about the disk and its partitions. """Gather details about the disk and its partitions.
This includes partitions that can't be backed up, This includes partitions that can't be backed up,
@ -71,10 +105,10 @@ def prep_disk_for_backup(destination, disk, ticket_number):
par['Image Name'] = par['Name'] if par['Name'] else 'Unknown' par['Image Name'] = par['Name'] if par['Name'] else 'Unknown'
if 'IP' in destination: if 'IP' in destination:
par['Image Path'] = r'\\{}\{}\{}'.format( par['Image Path'] = r'\\{}\{}\{}'.format(
destination['IP'], destination['Share'], ticket_number) destination['IP'], destination['Share'], backup_prefix)
else: else:
par['Image Path'] = r'{}:\{}'.format( par['Image Path'] = r'{}:\{}'.format(
ticket_number, destination['Letter']) destination['Letter'], backup_prefix)
par['Image Path'] += r'\{}_{}.wim'.format( par['Image Path'] += r'\{}_{}.wim'.format(
par['Number'], par['Image Name']) par['Number'], par['Image Name'])
par['Image Path'] = fix_path(par['Image Path']) par['Image Path'] = fix_path(par['Image Path'])
@ -115,6 +149,19 @@ def select_backup_destination(auto_select=True):
{'Name': 'Main Menu', 'Letter': 'M'}, {'Name': 'Main Menu', 'Letter': 'M'},
] ]
# Add local disks
for d in psutil.disk_partitions():
if re.search(r'^{}'.format(global_vars['Env']['SYSTEMDRIVE']), d.mountpoint, re.IGNORECASE):
# Skip current OS drive
pass
elif 'fixed' in d.opts:
# Skip DVD, etc
destinations.append({
'Name': 'Local Disk - {}'.format(
get_volume_display_name(d.mountpoint)),
'Letter': re.sub(r'^(\w):\\.*$', r'\1', d.mountpoint),
})
# Size check # Size check
for dest in destinations: for dest in destinations:
if 'IP' in dest: if 'IP' in dest:

View file

@ -190,12 +190,17 @@ def extract_item(item, filter='', silent=False):
print_standard('Extracting "{item}"...'.format(item=item)) print_standard('Extracting "{item}"...'.format(item=item))
try: try:
run_program(cmd) run_program(cmd)
except FileNotFoundError:
if not silent:
print_warning('WARNING: Archive not found')
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
if not silent: if not silent:
print_warning('WARNING: Errors encountered while exctracting data') print_warning('WARNING: Errors encountered while exctracting data')
def get_ticket_number(): def get_ticket_number():
"""Get TicketNumber from user, save in LogDir, and return as str.""" """Get TicketNumber from user, save in LogDir, and return as str."""
if not ENABLED_TICKET_NUMBERS:
return None
ticket_number = None ticket_number = None
while ticket_number is None: while ticket_number is None:
_input = input('Enter ticket number: ') _input = input('Enter ticket number: ')
@ -208,6 +213,15 @@ def get_ticket_number():
f.write(ticket_number) f.write(ticket_number)
return ticket_number return ticket_number
def get_simple_string(prompt='Enter string'):
"""Get string from user (only alphanumeric/space chars) and return as str."""
simple_string = None
while simple_string is None:
_input = input('{}: '.format(prompt))
if re.match(r'^(\w|-| )+$', _input, re.ASCII):
simple_string = _input.strip()
return simple_string
def human_readable_size(size, decimals=0): def human_readable_size(size, decimals=0):
"""Convert size in bytes to a human-readable format and return a str.""" """Convert size in bytes to a human-readable format and return a str."""
# Prep string formatting # Prep string formatting

View file

@ -534,21 +534,21 @@ def select_destination(folder_path, prompt='Select destination'):
return path return path
def select_source(ticket_number): def select_source(backup_prefix):
"""Select backup from those found on the BACKUP_SERVERS for the ticket.""" """Select backup from those found on the BACKUP_SERVERS matching the prefix."""
selected_source = None selected_source = None
local_sources = [] local_sources = []
remote_sources = [] remote_sources = []
sources = [] sources = []
mount_backup_shares(read_write=False) mount_backup_shares(read_write=False)
# Check for ticket folders on servers # Check for prefix folders on servers
for server in BACKUP_SERVERS: for server in BACKUP_SERVERS:
if server['Mounted']: if server['Mounted']:
print_standard('Scanning {}...'.format(server['Name'])) print_standard('Scanning {}...'.format(server['Name']))
for d in os.scandir(r'\\{IP}\{Share}'.format(**server)): for d in os.scandir(r'\\{IP}\{Share}'.format(**server)):
if (d.is_dir() if (d.is_dir()
and d.name.lower().startswith(ticket_number.lower())): and d.name.lower().startswith(backup_prefix.lower())):
# Add folder to remote_sources # Add folder to remote_sources
remote_sources.append({ remote_sources.append({
'Name': '{:9}| File-Based: [DIR] {}'.format( 'Name': '{:9}| File-Based: [DIR] {}'.format(
@ -558,19 +558,19 @@ def select_source(ticket_number):
'Source': d}) 'Source': d})
# Check for images and subfolders # Check for images and subfolders
for ticket_path in remote_sources.copy(): for prefix_path in remote_sources.copy():
for item in os.scandir(ticket_path['Source'].path): for item in os.scandir(prefix_path['Source'].path):
if item.is_dir(): if item.is_dir():
# Add folder to remote_sources # Add folder to remote_sources
remote_sources.append({ remote_sources.append({
'Name': r'{:9}| File-Based: [DIR] {}\{}'.format( 'Name': r'{:9}| File-Based: [DIR] {}\{}'.format(
ticket_path['Server']['Name'], # Server prefix_path['Server']['Name'], # Server
ticket_path['Source'].name, # Ticket folder prefix_path['Source'].name, # Prefix folder
item.name, # Sub-folder item.name, # Sub-folder
), ),
'Server': ticket_path['Server'], 'Server': prefix_path['Server'],
'Sort': r'{}\{}'.format( 'Sort': r'{}\{}'.format(
ticket_path['Source'].name, # Ticket folder prefix_path['Source'].name, # Prefix folder
item.name, # Sub-folder item.name, # Sub-folder
), ),
'Source': item}) 'Source': item})
@ -586,15 +586,15 @@ def select_source(ticket_number):
remote_sources.append({ remote_sources.append({
'Disabled': bool(not is_valid_wim_file(subitem)), 'Disabled': bool(not is_valid_wim_file(subitem)),
'Name': r'{:9}| Image-Based: {:>7} {}\{}\{}'.format( 'Name': r'{:9}| Image-Based: {:>7} {}\{}\{}'.format(
ticket_path['Server']['Name'], # Server prefix_path['Server']['Name'], # Server
size, # Size (duh) size, # Size (duh)
ticket_path['Source'].name, # Ticket folder prefix_path['Source'].name, # Prefix folder
item.name, # Sub-folder item.name, # Sub-folder
subitem.name, # Image file subitem.name, # Image file
), ),
'Server': ticket_path['Server'], 'Server': prefix_path['Server'],
'Sort': r'{}\{}\{}'.format( 'Sort': r'{}\{}\{}'.format(
ticket_path['Source'].name, # Ticket folder prefix_path['Source'].name, # Prefix folder
item.name, # Sub-folder item.name, # Sub-folder
subitem.name, # Image file subitem.name, # Image file
), ),
@ -608,14 +608,14 @@ def select_source(ticket_number):
remote_sources.append({ remote_sources.append({
'Disabled': bool(not is_valid_wim_file(item)), 'Disabled': bool(not is_valid_wim_file(item)),
'Name': r'{:9}| Image-Based: {:>7} {}\{}'.format( 'Name': r'{:9}| Image-Based: {:>7} {}\{}'.format(
ticket_path['Server']['Name'], # Server prefix_path['Server']['Name'], # Server
size, # Size (duh) size, # Size (duh)
ticket_path['Source'].name, # Ticket folder prefix_path['Source'].name, # Prefix folder
item.name, # Image file item.name, # Image file
), ),
'Server': ticket_path['Server'], 'Server': prefix_path['Server'],
'Sort': r'{}\{}'.format( 'Sort': r'{}\{}'.format(
ticket_path['Source'].name, # Ticket folder prefix_path['Source'].name, # Prefix folder
item.name, # Image file item.name, # Image file
), ),
'Source': item}) 'Source': item})
@ -682,8 +682,8 @@ def select_source(ticket_number):
else: else:
selected_source = sources[int(selection)-1]['Source'] selected_source = sources[int(selection)-1]['Source']
else: else:
print_error('ERROR: No backups found for ticket: {}.'.format( print_error('ERROR: No backups found using prefix: {}.'.format(
ticket_number)) backup_prefix))
umount_backup_shares() umount_backup_shares()
pause("Press Enter to exit...") pause("Press Enter to exit...")
exit_script() exit_script()

View file

@ -125,9 +125,9 @@ def menu_diags(*args):
if diag_modes[int(selection)-1]['Name'] != 'Quick drive test': if diag_modes[int(selection)-1]['Name'] != 'Quick drive test':
# Save log for non-quick tests # Save log for non-quick tests
ticket_number = get_ticket_number() ticket_number = get_ticket_number()
global_vars['LogDir'] = '{}/Tickets/{}'.format( global_vars['LogDir'] = '{}/Logs/{}'.format(
global_vars['Env']['HOME'], global_vars['Env']['HOME'],
ticket_number) ticket_number if ticket_number else global_vars['Date-Time'])
os.makedirs(global_vars['LogDir'], exist_ok=True) os.makedirs(global_vars['LogDir'], exist_ok=True)
global_vars['LogFile'] = '{}/Hardware Diagnostics.log'.format( global_vars['LogFile'] = '{}/Hardware Diagnostics.log'.format(
global_vars['LogDir']) global_vars['LogDir'])

View file

@ -75,10 +75,21 @@ def menu_backup():
}} }}
set_title('{}: Backup Menu'.format(KIT_NAME_FULL)) set_title('{}: Backup Menu'.format(KIT_NAME_FULL))
# Set ticket Number # Set backup prefix
clear_screen() clear_screen()
print_standard('{}\n'.format(global_vars['Title'])) print_standard('{}\n'.format(global_vars['Title']))
ticket_number = get_ticket_number() ticket_number = get_ticket_number()
if ENABLED_TICKET_NUMBERS:
backup_prefix = ticket_number
else:
backup_prefix = get_simple_string(prompt='Enter backup name prefix')
backup_prefix = backup_prefix.replace(' ', '_')
# Assign drive letters
try_and_print(
message = 'Assigning letters...',
function = assign_volume_letters,
other_results = other_results)
# Mount backup shares # Mount backup shares
mount_backup_shares(read_write=True) mount_backup_shares(read_write=True)
@ -87,10 +98,6 @@ def menu_backup():
destination = select_backup_destination(auto_select=False) destination = select_backup_destination(auto_select=False)
# Scan disks # Scan disks
try_and_print(
message = 'Assigning letters...',
function = assign_volume_letters,
other_results = other_results)
result = try_and_print( result = try_and_print(
message = 'Getting disk info...', message = 'Getting disk info...',
function = scan_disks, function = scan_disks,
@ -107,11 +114,12 @@ def menu_backup():
raise GenericAbort raise GenericAbort
# "Prep" disk # "Prep" disk
prep_disk_for_backup(destination, disk, ticket_number) prep_disk_for_backup(destination, disk, backup_prefix)
# Display details for backup task # Display details for backup task
clear_screen() clear_screen()
print_info('Create Backup - Details:\n') print_info('Create Backup - Details:\n')
if ENABLED_TICKET_NUMBERS:
show_data(message='Ticket:', data=ticket_number) show_data(message='Ticket:', data=ticket_number)
show_data( show_data(
message = 'Source:', message = 'Source:',
@ -293,6 +301,7 @@ def menu_setup():
# Display details for setup task # Display details for setup task
clear_screen() clear_screen()
print_info('Setup Windows - Details:\n') print_info('Setup Windows - Details:\n')
if ENABLED_TICKET_NUMBERS:
show_data(message='Ticket:', data=ticket_number) show_data(message='Ticket:', data=ticket_number)
show_data(message='Installing:', data=windows_version['Name']) show_data(message='Installing:', data=windows_version['Name'])
show_data( show_data(

View file

@ -2,6 +2,7 @@
# Features # Features
ENABLED_UPLOAD_DATA = False ENABLED_UPLOAD_DATA = False
ENABLED_TICKET_NUMBERS = False
# STATIC VARIABLES (also used by BASH and BATCH files) # STATIC VARIABLES (also used by BASH and BATCH files)
## NOTE: There are no spaces around the = for easier parsing in BASH and BATCH ## NOTE: There are no spaces around the = for easier parsing in BASH and BATCH

View file

@ -29,8 +29,11 @@ if __name__ == '__main__':
'FileNotFoundError': 'File not found', 'FileNotFoundError': 'File not found',
}, },
'Warning': {}} 'Warning': {}}
if ENABLED_TICKET_NUMBERS:
print_info('Starting System Checklist for Ticket #{}\n'.format( print_info('Starting System Checklist for Ticket #{}\n'.format(
ticket_number)) ticket_number))
else:
print_info('Starting System Checklist\n')
# Configure # Configure
print_info('Configure') print_info('Configure')

View file

@ -31,8 +31,11 @@ if __name__ == '__main__':
'GenericRepair': 'Repaired', 'GenericRepair': 'Repaired',
'UnsupportedOSError': 'Unsupported OS', 'UnsupportedOSError': 'Unsupported OS',
}} }}
if ENABLED_TICKET_NUMBERS:
print_info('Starting System Diagnostics for Ticket #{}\n'.format( print_info('Starting System Diagnostics for Ticket #{}\n'.format(
ticket_number)) ticket_number))
else:
print_info('Starting System Diagnostics\n')
# Sanitize Environment # Sanitize Environment
print_info('Sanitizing Environment') print_info('Sanitizing Environment')

View file

@ -18,16 +18,28 @@ if __name__ == '__main__':
stay_awake() stay_awake()
clear_screen() clear_screen()
print_info('{}: User Data Transfer Tool\n'.format(KIT_NAME_FULL)) print_info('{}: User Data Transfer Tool\n'.format(KIT_NAME_FULL))
# Get backup name prefix
ticket_number = get_ticket_number() ticket_number = get_ticket_number()
if ENABLED_TICKET_NUMBERS:
backup_prefix = ticket_number
else:
backup_prefix = get_simple_string(prompt='Enter backup name prefix')
backup_prefix = backup_prefix.replace(' ', '_')
# Set destination
folder_path = r'{}\Transfer'.format(KIT_NAME_SHORT) folder_path = r'{}\Transfer'.format(KIT_NAME_SHORT)
dest = select_destination(folder_path=folder_path, dest = select_destination(folder_path=folder_path,
prompt='Which disk are we transferring to?') prompt='Which disk are we transferring to?')
source = select_source(ticket_number)
# Set source items
source = select_source(backup_prefix)
items = scan_source(source, dest) items = scan_source(source, dest)
# Transfer # Transfer
clear_screen() clear_screen()
print_info('Transfer Details:\n') print_info('Transfer Details:\n')
if ENABLED_TICKET_NUMBERS:
show_data('Ticket:', ticket_number) show_data('Ticket:', ticket_number)
show_data('Source:', source.path) show_data('Source:', source.path)
show_data('Destination:', dest) show_data('Destination:', dest)