479 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			479 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env python3
 | |
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| # Copyright (c) 2021 Battelle Energy Alliance, LLC.  All rights reserved.
 | |
| 
 | |
| # script for configuring sensor network interface controller(s)
 | |
| 
 | |
| import locale
 | |
| import os
 | |
| import sys
 | |
| import netifaces
 | |
| import fileinput
 | |
| import re
 | |
| from dialog import Dialog
 | |
| from debinterface.interfaces import Interfaces
 | |
| from sensorcommon import *
 | |
| 
 | |
| class Constants:
 | |
|   DHCP = 'dhcp'
 | |
|   STATIC = 'static'
 | |
|   UNASSIGNED = 'manual'
 | |
| 
 | |
|   DEV_IDENTIFIER_FILE = '/etc/installer'
 | |
|   DEV_UNKNOWN = 'unknown'
 | |
|   DEV_AGGREGATOR = 'aggregator'
 | |
|   DEV_SENSOR = 'sensor'
 | |
|   DEV_VALID = {DEV_AGGREGATOR, DEV_SENSOR}
 | |
|   MSG_ERR_DEV_INVALID = f'Could not determine installation type (not one of {DEV_VALID})'
 | |
| 
 | |
|   CONFIG_IFACE = 'Interface Configuration'
 | |
| 
 | |
|   SENSOR_BACKUP_CONFIG = '/tmp/sensor_interface.bak'
 | |
|   SENSOR_INTERFACES_CONFIG = '/etc/network/interfaces.d/sensor'
 | |
|   ETC_HOSTS = '/etc/hosts'
 | |
| 
 | |
|   TIME_SYNC_NTP = 'ntp'
 | |
|   TIME_SYNC_HTPDATE = 'htpdate'
 | |
|   TIME_SYNC_HTPDATE_CRON = '/etc/cron.d/htpdate'
 | |
|   TIME_SYNC_HTPDATE_TEST_COMMAND = '/usr/sbin/htpdate -4 -a -b -d'
 | |
|   TIME_SYNC_HTPDATE_COMMAND = '/usr/sbin/htpdate -4 -a -b -l -s'
 | |
|   TIME_SYNC_NTP_CONFIG = '/etc/ntp.conf'
 | |
| 
 | |
|   MSG_CONFIG_MODE = 'Configuration Mode'
 | |
|   MSG_BACKGROUND_TITLE = 'Sensor Configuration'
 | |
|   MSG_CONFIG_HOST = ('Hostname', 'Configure sensor hostname')
 | |
|   MSG_CONFIG_INTERFACE = ('Interface', 'Configure an interface\'s IP address')
 | |
|   MSG_CONFIG_TIME_SYNC = ('Time Sync', 'Configure time synchronization')
 | |
|   MSG_CONFIG_STATIC_TITLE = 'Provide the values for static IP configuration'
 | |
|   MSG_ERR_ROOT_REQUIRED = 'Elevated privileges required, run as root'
 | |
|   MSG_ERR_BAD_HOST = 'Invalid host or port'
 | |
|   MSG_MESSAGE_DHCP = 'Configuring for DHCP provided address...'
 | |
|   MSG_MESSAGE_ERROR = 'Error: {}\n\nPlease try again.'
 | |
|   MSG_MESSAGE_STATIC = 'Configuring for static IP address...'
 | |
|   MSG_MESSAGE_UNASSIGNED = 'Configuring for no IP address...'
 | |
|   MSG_NETWORK_START_ERROR = 'Error occured while configuring network interface!\n\n'
 | |
|   MSG_NETWORK_START_SUCCESS = 'Network interface configuration completed successfully!\n\n'
 | |
|   MSG_NETWORK_STOP_ERROR = 'Error occured while bringing down the network interface!\n\n'
 | |
|   MSG_NETWORK_STOP_SUCCESS = 'Brought down the network interface successfully!\n\n'
 | |
|   MSG_TIME_SYNC_TYPE = 'Select time synchronization method'
 | |
|   MSG_TIME_SYNC_HTPDATE_CONFIG = 'Provide values for HTTP/HTTPS Server'
 | |
|   MSG_TIME_SYNC_TEST_SUCCESS = 'Server time retrieved successfully!\n\n'
 | |
|   MSG_TIME_SYNC_CONFIG_SUCCESS = 'Time synchronization configured successfully!\n\n'
 | |
|   MSG_TIME_SYNC_TEST_FAILURE = 'Server time could not be retrieved. Ignore error?\n\n'
 | |
|   MSG_TIME_SYNC_NTP_CONFIG = 'Provide values for NTP Server'
 | |
|   MSG_TESTING_CONNECTION = 'Testing {} connection...'
 | |
|   MSG_TESTING_CONNECTION_FAILURE = "Connection error: could not connect to {}:{}"
 | |
|   MSG_SET_HOSTNAME_CURRENT = 'Current sensor identification information\n\n'
 | |
|   MSG_SET_HOSTNAME_SUCCESS = 'Set sensor hostname successfully!\n\n'
 | |
|   MSG_IDENTIFY_NICS = 'Do you need help identifying network interfaces?'
 | |
|   MSG_SELECT_INTERFACE = 'Select interface to configure'
 | |
|   MSG_SELECT_BLINK_INTERFACE = 'Select capture interface to identify'
 | |
|   MSG_BLINK_INTERFACE = '{} will blink for {} seconds'
 | |
|   MSG_SELECT_SOURCE = 'Select address source'
 | |
|   MSG_WELCOME_TITLE = 'Welcome to the sensor network interface controller utility!'
 | |
| 
 | |
| # the main dialog window used for the duration of this tool
 | |
| d = Dialog(dialog='dialog', autowidgetsize=True)
 | |
| d.set_background_title(Constants.MSG_BACKGROUND_TITLE)
 | |
| 
 | |
| ###################################################################################################
 | |
| # if the given interface is up, "ifdown" it
 | |
| def network_stop(selected_iface):
 | |
|   iface_state = "unknown"
 | |
|   with open(f"/sys/class/net/{selected_iface}/operstate", 'r') as f:
 | |
|     iface_state = f.readline().strip()
 | |
| 
 | |
|   if (iface_state == "up"):
 | |
|     command = f"ifdown {selected_iface}"
 | |
|   else:
 | |
|     command = f"cat /sys/class/net/{selected_iface}/operstate"
 | |
| 
 | |
|   return run_process(command, stderr=True)
 | |
| 
 | |
| ###################################################################################################
 | |
| # if the given interface is not up, "ifup" it
 | |
| def network_start(selected_iface):
 | |
|   iface_state = "unknown"
 | |
|   with open(f"/sys/class/net/{selected_iface}/operstate", 'r') as f:
 | |
|     iface_state = f.readline().strip()
 | |
| 
 | |
|   if (iface_state != "up"):
 | |
|     command = f"ifup {selected_iface}"
 | |
|   else:
 | |
|     command = f"cat /sys/class/net/{selected_iface}/operstate"
 | |
| 
 | |
|   return run_process(command, stderr=True)
 | |
| 
 | |
| ###################################################################################################
 | |
| # for a given interface, bring it down, write its new settings, and bring it back up
 | |
| def write_and_display_results(interfaces, selected_iface):
 | |
| 
 | |
|   ecode, stop_results = network_stop(selected_iface)
 | |
|   stop_results = list(filter(lambda x: (len(x) > 0) and ('Internet Systems' not in x) and ('Copyright' not in x) and ('All rights' not in x) and ('For info' not in x), stop_results))
 | |
|   if ecode == 0:
 | |
|     stop_text = Constants.MSG_NETWORK_STOP_SUCCESS
 | |
|   else:
 | |
|     stop_text = Constants.MSG_NETWORK_STOP_ERROR
 | |
| 
 | |
|   interfaces.writeInterfaces()
 | |
| 
 | |
|   ecode, start_results = network_start(selected_iface)
 | |
|   start_results = list(filter(lambda x: (len(x.strip()) > 0) and ('Internet Systems' not in x) and ('Copyright' not in x) and ('All rights' not in x) and ('For info' not in x), start_results))
 | |
|   if ecode == 0:
 | |
|     start_text = Constants.MSG_NETWORK_START_SUCCESS
 | |
|   else:
 | |
|     start_text = Constants.MSG_NETWORK_START_ERROR
 | |
| 
 | |
|   code = d.msgbox(stop_text + "\n".join(stop_results) + "\n\n. . .\n\n" + start_text + "\n".join(start_results))
 | |
| 
 | |
| ###################################################################################################
 | |
| ###################################################################################################
 | |
| def main():
 | |
|   locale.setlocale(locale.LC_ALL, '')
 | |
| 
 | |
|   # make sure we are being run as root
 | |
|   if os.getuid() != 0:
 | |
|     print(Constants.MSG_ERR_ROOT_REQUIRED)
 | |
|     sys.exit(1)
 | |
| 
 | |
|   # what are we (sensor vs. aggregator)
 | |
|   installation = Constants.DEV_UNKNOWN
 | |
|   modeChoices = []
 | |
|   try:
 | |
|     with open(Constants.DEV_IDENTIFIER_FILE, 'r') as f:
 | |
|       installation = f.readline().strip()
 | |
|   except:
 | |
|     pass
 | |
|   if (installation == Constants.DEV_SENSOR):
 | |
|     modeChoices = [Constants.MSG_CONFIG_INTERFACE, Constants.MSG_CONFIG_HOST, Constants.MSG_CONFIG_TIME_SYNC]
 | |
|   elif (installation == Constants.DEV_AGGREGATOR):
 | |
|     modeChoices = [Constants.MSG_CONFIG_HOST, Constants.MSG_CONFIG_TIME_SYNC]
 | |
|   else:
 | |
|     print(Constants.MSG_ERR_DEV_INVALID)
 | |
|     sys.exit(1)
 | |
| 
 | |
|   start_dir = os.getcwd()
 | |
|   quit_flag = False
 | |
| 
 | |
|   while not quit_flag:
 | |
|     os.chdir(start_dir)
 | |
|     try:
 | |
| 
 | |
|       # welcome
 | |
|       code = d.yesno(Constants.MSG_WELCOME_TITLE, yes_label="Continue", no_label="Quit")
 | |
|       if (code == Dialog.CANCEL or code == Dialog.ESC):
 | |
|         quit_flag = True
 | |
|         raise CancelledError
 | |
| 
 | |
|       # configuring an interface or setting the hostname?
 | |
|       code, config_mode = d.menu(Constants.MSG_CONFIG_MODE, choices=modeChoices)
 | |
|       if code != Dialog.OK:
 | |
|         quit_flag = True
 | |
|         raise CancelledError
 | |
| 
 | |
|       if (config_mode == Constants.MSG_CONFIG_HOST[0]):
 | |
|         ##### system hostname configuration ##################################################################################################
 | |
| 
 | |
|         # get current host/identification information
 | |
|         ecode, host_get_output = run_process('hostnamectl', stderr=True)
 | |
|         if (ecode == 0):
 | |
|           emsg_str = '\n'.join(host_get_output)
 | |
|           code = d.msgbox(text=f"{Constants.MSG_SET_HOSTNAME_CURRENT}{emsg_str}")
 | |
| 
 | |
|           code, hostname_get_output = run_process('hostname', stderr=False)
 | |
|           if (code == 0) and (len(hostname_get_output) > 0):
 | |
|             old_hostname = hostname_get_output[0].strip()
 | |
|           else:
 | |
|             old_hostname = ""
 | |
| 
 | |
|           # user input for new hostname
 | |
|           while True:
 | |
|             code, new_hostname = d.inputbox("Sensor hostname", init=old_hostname)
 | |
|             if (code == Dialog.CANCEL) or (code == Dialog.ESC):
 | |
|               raise CancelledError
 | |
|             elif (len(new_hostname) <= 0):
 | |
|               code = d.msgbox(text=Constants.MSG_MESSAGE_ERROR.format(f'Invalid hostname specified'))
 | |
|             else:
 | |
|               break
 | |
| 
 | |
|           # set new hostname
 | |
|           ecode, host_set_output = run_process(f'hostnamectl set-hostname {new_hostname.strip()}', stderr=True)
 | |
|           if (ecode == 0):
 | |
|             ecode, host_get_output = run_process('hostnamectl', stderr=True)
 | |
|             emsg_str = '\n'.join(host_get_output)
 | |
|             code = d.msgbox(text=f"{Constants.MSG_SET_HOSTNAME_SUCCESS}{emsg_str}")
 | |
| 
 | |
|             # modify /etc/hosts 127.0.1.1 entry
 | |
|             local_hosts_re = re.compile(r"^\s*127\.0\.1\.1\b")
 | |
|             with fileinput.FileInput(Constants.ETC_HOSTS, inplace=True, backup='.bak') as file:
 | |
|               for line in file:
 | |
|                 if local_hosts_re.search(line) is not None:
 | |
|                   print(f"127.0.1.1\t{new_hostname}")
 | |
|                 else:
 | |
|                   print(line, end='')
 | |
| 
 | |
|           else:
 | |
|             # error running hostnamectl set-hostname
 | |
|             emsg_str = '\n'.join(host_get_output)
 | |
|             code = d.msgbox(text=Constants.MSG_MESSAGE_ERROR.format(f"Getting hostname failed with {ecode}:{emsg_str}"))
 | |
| 
 | |
|         else:
 | |
|           # error running hostnamectl
 | |
|           emsg_str = '\n'.join(host_get_output)
 | |
|           code = d.msgbox(text=Constants.MSG_MESSAGE_ERROR.format(f"Getting hostname failed with {ecode}:{emsg_str}"))
 | |
| 
 | |
|       elif (config_mode == Constants.MSG_CONFIG_TIME_SYNC[0]):
 | |
|         ##### time synchronization configuration##############################################################################################
 | |
|         time_sync_mode = ''
 | |
|         code = Dialog.OK
 | |
|         while (len(time_sync_mode) == 0) and (code == Dialog.OK):
 | |
|           code, time_sync_mode = d.radiolist(Constants.MSG_TIME_SYNC_TYPE, choices=[(Constants.TIME_SYNC_HTPDATE, 'Use a Malcolm server (or another HTTP/HTTPS server)', (installation == Constants.DEV_SENSOR)),
 | |
|                                                                                     (Constants.TIME_SYNC_NTP, 'Use an NTP server', False)])
 | |
|         if (code != Dialog.OK):
 | |
|           raise CancelledError
 | |
| 
 | |
|         elif (time_sync_mode == Constants.TIME_SYNC_HTPDATE):
 | |
|           # sync time via htpdate, run via cron
 | |
| 
 | |
|           http_host = ''
 | |
|           http_port = ''
 | |
|           while True:
 | |
|             # host/port for htpdate
 | |
|             code, values = d.form(Constants.MSG_TIME_SYNC_HTPDATE_CONFIG,
 | |
|                                   [('Host', 1, 1, '', 1,  25, 30, 255),
 | |
|                                    ('Port', 2, 1, '9200', 2, 25, 6, 5)])
 | |
|             values = [x.strip() for x in values]
 | |
| 
 | |
|             if (code == Dialog.CANCEL) or (code == Dialog.ESC):
 | |
|               raise CancelledError
 | |
| 
 | |
|             elif (len(values[0]) <= 0) or (len(values[1]) <= 0) or (not values[1].isnumeric()):
 | |
|               code = d.msgbox(text=Constants.MSG_ERR_BAD_HOST)
 | |
| 
 | |
|             else:
 | |
|               http_host = values[0]
 | |
|               http_port = values[1]
 | |
|               break
 | |
| 
 | |
|           # test with htpdate to see if we can connect
 | |
|           ecode, test_output = run_process(f"{Constants.TIME_SYNC_HTPDATE_TEST_COMMAND} {http_host}:{http_port}")
 | |
|           if ecode == 0:
 | |
|             emsg_str = '\n'.join(test_output)
 | |
|             code = d.msgbox(text=f"{Constants.MSG_TIME_SYNC_TEST_SUCCESS}{emsg_str}")
 | |
|           else:
 | |
|             emsg_str = '\n'.join(test_output)
 | |
|             code = d.yesno(text=f"{Constants.MSG_TIME_SYNC_TEST_FAILURE}{emsg_str}",
 | |
|                            yes_label="Ignore Error", no_label="Start Over")
 | |
|             if code != Dialog.OK:
 | |
|               raise CancelledError
 | |
| 
 | |
|           # get polling interval
 | |
|           code, htpdate_interval = d.rangebox(f"Time synchronization polling interval (minutes)",
 | |
|                                               width=60, min=1, max=60, init=15)
 | |
|           if (code == Dialog.CANCEL or code == Dialog.ESC):
 | |
|             raise CancelledError
 | |
| 
 | |
|           # stop and disable the ntp process
 | |
|           run_process('/bin/systemctl stop ntp')
 | |
|           run_process('/bin/systemctl disable ntp')
 | |
| 
 | |
|           # write out htpdate file for cron
 | |
|           with open(Constants.TIME_SYNC_HTPDATE_CRON, 'w+') as f:
 | |
|             f.write('SHELL=/bin/bash\n')
 | |
|             f.write('PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n')
 | |
|             f.write('\n')
 | |
|             f.write(f'*/{htpdate_interval} * * * * root {Constants.TIME_SYNC_HTPDATE_COMMAND} {http_host}:{http_port}\n')
 | |
|             f.write('\n')
 | |
|           code = d.msgbox(text=f"{Constants.MSG_TIME_SYNC_CONFIG_SUCCESS}")
 | |
| 
 | |
|         elif (time_sync_mode == Constants.TIME_SYNC_NTP):
 | |
|           # sync time via ntp, run via service
 | |
| 
 | |
|           ntp_host = ''
 | |
|           while True:
 | |
|             # host/port for ntp
 | |
|             code, values = d.form(Constants.MSG_TIME_SYNC_NTP_CONFIG,
 | |
|                                   [('Host', 1, 1, '', 1,  25, 30, 255)])
 | |
|             values = [x.strip() for x in values]
 | |
| 
 | |
|             if (code == Dialog.CANCEL) or (code == Dialog.ESC):
 | |
|               raise CancelledError
 | |
| 
 | |
|             elif (len(values[0]) <= 0):
 | |
|               code = d.msgbox(text=Constants.MSG_ERR_BAD_HOST)
 | |
| 
 | |
|             else:
 | |
|               ntp_host = values[0]
 | |
|               break
 | |
| 
 | |
|           # disable htpdate (no need to have two sync-ers) by removing it from cron
 | |
|           if os.path.exists(Constants.TIME_SYNC_HTPDATE_CRON):
 | |
|             os.remove(Constants.TIME_SYNC_HTPDATE_CRON)
 | |
| 
 | |
|           # write out ntp config file (changing values in place)
 | |
|           server_written = False
 | |
|           server_re = re.compile(r"^\s*#?\s*(server)\s*.+?$")
 | |
|           with fileinput.FileInput(Constants.TIME_SYNC_NTP_CONFIG, inplace=True, backup='.bak') as file:
 | |
|             for line in file:
 | |
|               line = line.rstrip("\n")
 | |
|               server_match = server_re.search(line)
 | |
|               if server_match is not None:
 | |
|                 if not server_written:
 | |
|                   print(f'server {ntp_host}')
 | |
|                   server_written = True
 | |
|                 else:
 | |
|                   print(f"{'' if line.startswith('#') else '#'}{line}")
 | |
|               else:
 | |
|                 print(line)
 | |
| 
 | |
|           # enable and start the ntp process
 | |
|           run_process('/bin/systemctl stop ntp')
 | |
|           run_process('/bin/systemctl enable ntp')
 | |
|           ecode, start_output = run_process('/bin/systemctl start ntp', stderr=True)
 | |
|           if ecode == 0:
 | |
|             code = d.msgbox(text=f"{Constants.MSG_TIME_SYNC_CONFIG_SUCCESS}")
 | |
|           else:
 | |
|             code = d.msgbox(text=Constants.MSG_MESSAGE_ERROR.format('\n'.join(start_output)))
 | |
| 
 | |
|         else:
 | |
|           raise CancelledError
 | |
| 
 | |
|       else:
 | |
|         ##### interface IP address configuration #############################################################################################
 | |
| 
 | |
|         # read configuration from /etc/network/interfaces.d/sensor (or /etc/network/interfaces if for some reason it doesn't exist)
 | |
|         if os.path.isfile(Constants.SENSOR_INTERFACES_CONFIG):
 | |
|           interfaces = Interfaces(interfaces_path=Constants.SENSOR_INTERFACES_CONFIG, backup_path=Constants.SENSOR_BACKUP_CONFIG)
 | |
|         else:
 | |
|           interfaces = Interfaces(backup_path=Constants.SENSOR_BACKUP_CONFIG)
 | |
| 
 | |
|         # determine a list of available (non-virtual) adapters
 | |
|         available_adapters = get_available_adapters()
 | |
| 
 | |
|         while (len(available_adapters) > 0) and (d.yesno(Constants.MSG_IDENTIFY_NICS) == Dialog.OK):
 | |
|           code, blinky_iface = d.radiolist(Constants.MSG_SELECT_BLINK_INTERFACE, choices=[(adapter.name, adapter.description, False) for adapter in available_adapters])
 | |
|           if (code == Dialog.OK) and (len(blinky_iface) > 0):
 | |
|             if (d.yesno(Constants.MSG_BLINK_INTERFACE.format(blinky_iface, NIC_BLINK_SECONDS), yes_label="Ready", no_label="Cancel") == Dialog.OK):
 | |
|               identify_adapter(adapter=blinky_iface, duration=NIC_BLINK_SECONDS, background=True)
 | |
|               code = d.pause(f"Identifying {blinky_iface}", seconds=NIC_BLINK_SECONDS, width=60, height=15)
 | |
|           elif (code != Dialog.OK):
 | |
|             break
 | |
| 
 | |
|         code, tag = d.menu(Constants.MSG_SELECT_INTERFACE, choices=[(adapter.name, adapter.description) for adapter in available_adapters])
 | |
|         if code != Dialog.OK:
 | |
|           raise CancelledError
 | |
| 
 | |
|         # which interface are wer configuring?
 | |
|         selected_iface = tag
 | |
| 
 | |
|         # check if selected_iface already has entry in system configuration
 | |
|         configured_iface = None
 | |
|         for adapter in interfaces.adapters:
 | |
|           item = adapter.export()
 | |
|           if item['name'] == selected_iface:
 | |
|             configured_iface = item
 | |
|             break
 | |
| 
 | |
|         # if it was already configured, remove from configured adapter list to be replaced by the new settings
 | |
|         if configured_iface is not None:
 | |
|           interfaces.removeAdapterByName(selected_iface)
 | |
| 
 | |
|         # static, dynamic, or unassigned IP address?
 | |
|         code, tag = d.menu(Constants.MSG_SELECT_SOURCE, choices=[(Constants.STATIC, 'Static IP (recommended)'), (Constants.DHCP, 'Dynamic IP'), (Constants.UNASSIGNED, 'No IP')])
 | |
|         if code != Dialog.OK:
 | |
|           raise CancelledError
 | |
| 
 | |
|         if tag == Constants.DHCP:
 | |
|           # DHCP ##########################################################
 | |
|           code = d.infobox(Constants.MSG_MESSAGE_DHCP)
 | |
| 
 | |
|           interfaces.addAdapter({
 | |
|             'name': selected_iface,
 | |
|             'auto': True,
 | |
|             'hotplug': True,
 | |
|             'addrFam': 'inet',
 | |
|             'source': Constants.DHCP}, 0)
 | |
| 
 | |
|           write_and_display_results(interfaces, selected_iface)
 | |
| 
 | |
|         elif tag == Constants.UNASSIGNED:
 | |
|           # unassigned (but up) ###########################################
 | |
|           code = d.infobox(Constants.MSG_MESSAGE_UNASSIGNED)
 | |
| 
 | |
|           interfaces.addAdapter({
 | |
|             'name': selected_iface,
 | |
|             'auto': True,
 | |
|             'hotplug': True,
 | |
|             'addrFam': 'inet',
 | |
|             'source': Constants.UNASSIGNED,
 | |
|             'pre-up': 'ip link set dev $IFACE up',
 | |
|             'post-up': '/usr/local/bin/nic-capture-setup.sh $IFACE',
 | |
|             'post-down': 'ip link set dev $IFACE down'}, 0)
 | |
| 
 | |
|           write_and_display_results(interfaces, selected_iface)
 | |
| 
 | |
|         elif tag == Constants.STATIC:
 | |
|           # static ########################################################
 | |
| 
 | |
|           # see if the adapter currently has an IP address, use it as a starting suggestion
 | |
|           try:
 | |
|             previous_ip = netifaces.ifaddresses(selected_iface)[netifaces.AF_INET][0]['addr']
 | |
|             previous_gw = '.'.join(previous_ip.split('.')[0:3] + ['1'])
 | |
|           except Exception as e:
 | |
|             code = d.msgbox(text=Constants.MSG_MESSAGE_ERROR.format(e))
 | |
|             previous_ip = "192.168.0.10"
 | |
|             previous_gw = "192.168.0.1"
 | |
|           if previous_ip.startswith('172.'):
 | |
|             previous_mask = "255.255.0.0"
 | |
|           elif previous_ip.startswith('10.'):
 | |
|             previous_mask = "255.0.0.0"
 | |
|           else:
 | |
|             previous_mask = "255.255.255.0"
 | |
| 
 | |
|           while True:
 | |
|             code, values = d.form(Constants.MSG_CONFIG_STATIC_TITLE, [
 | |
|                                   # title, row_1, column_1, field, row_1, column_20, field_length, input_length
 | |
|                                   ('IP Address', 1, 1, previous_ip, 1, 20, 15, 15),
 | |
|                                   # title, row_2, column_1, field, row_2, column_20, field_length, input_length
 | |
|                                   ('Netmask', 2, 1, previous_mask, 2, 20, 15, 15),
 | |
|                                   # title, row_3, column_1, field, row_3, column_20, field_length, input_length
 | |
|                                   ('Gateway', 3, 1, previous_gw, 3, 20, 15, 15)
 | |
|                                   ])
 | |
|             values = [x.strip() for x in values]
 | |
| 
 | |
|             if (code == Dialog.CANCEL or code == Dialog.ESC):
 | |
|               raise CancelledError
 | |
| 
 | |
|             elif (len(values[0]) <= 0) or (len(values[1]) <= 0) or (len(values[2]) <= 0):
 | |
|               code = d.msgbox(text=Constants.MSG_MESSAGE_ERROR.format("Invalid value(s), please try again"))
 | |
| 
 | |
|             else:
 | |
|               code = d.infobox(Constants.MSG_MESSAGE_STATIC)
 | |
| 
 | |
|               interfaces.addAdapter({
 | |
|                 'name': selected_iface,
 | |
|                 'auto': True,
 | |
|                 'hotplug': True,
 | |
|                 'addrFam': 'inet',
 | |
|                 'source': Constants.STATIC,
 | |
|                 'address': values[0],
 | |
|                 'netmask': values[1],
 | |
|                 'gateway': values[2]}, 0)
 | |
| 
 | |
|               write_and_display_results(interfaces, selected_iface)
 | |
|               break
 | |
| 
 | |
|     except CancelledError as c:
 | |
|       # d.msgbox(text=Constants.MSG_CANCEL_ERROR)
 | |
|       # just start over
 | |
|       continue
 | |
| 
 | |
|     except Exception as e:
 | |
|       d.msgbox(text=Constants.MSG_MESSAGE_ERROR.format(e))
 | |
|       raise
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|   main()
 | |
|   clearquit()
 |