def __print_summary(self): s = "\n######################## FCJP ##########################\n" summary = self.summary() for item in summary.keys(): s += '\t[\"{}\"] : {}\n'.format(item, summary.get(item)) s += "########################################################\n" LOG.info(s)
def setJson(self, json): try: ljson = loads(json) return self.setDict(ljson) except JSONDecodeError: LOG.exception('Error on getting new device via JSON.') return False
def cimi(key, default=None): value = default if key == 'leader': value = CPARAMS.LEADER_FLAG elif key == 'topology': value = [] # 1. Try to get the real topology cimi_topology = CIMI.get_topology() if len(cimi_topology) > 0: used_topology = cimi_topology # used_topology = list() # for item in cimi_topology: # TODO: Dataclay doesnt sync device static information to the leader # qdeviceID = CIMI.get_deviceID_from_IP(item[1]) # if qdeviceID != '': # used_topology.append((qdeviceID, item[1])) else: used_topology = CPARAMS.TOPOLOGY_FLAG try: for item in used_topology: i = {'deviceID': item[0], 'deviceIP': item[1]} value.append(i) except: LOG.exception( 'Topology Environment variable format is not correct.') value = [] return value
def getIPfromFile(file_path=CPARAMS.VPN_FILE_PATH): """ Get the IP of the device in the VPN network from the JSON file generated by the VPN client component. :param file_path: Path to the VPN JSON file :return: string with IP of the device, empty if failure """ ret_ip = '' try: with open(file_path, mode='r') as json_file: json_txt = json_file.readlines()[0] ljson = json.loads(json_txt) if ljson['status'] == 'connected': ret_ip = str(ljson['ip']) LOG.debug( 'VPN IP successfully parsed from JSON file at \'{}\'. Content: {} IP: {}' .format(file_path, str(ljson), ret_ip)) else: LOG.warning( 'VPN JSON status != \'connected\': Content: {}'.format( str(ljson))) except OSError: LOG.exception('VPN file cannot be open or found at \'{}\'.'.format( file_path)) except (IndexError, KeyError): LOG.exception('VPN error on parsing the IP.') except: LOG.exception('VPN generic error.') finally: return ret_ip
def __keeper(self): """ Thread that reduces the TTL of a backup and demotes if TTL <= 0 :return: """ LOG.debug('Keeper is running') with self.backupDatabaseLock: self.backupDatabase = [] # Restart database while self._connected: with self.backupDatabaseLock: for backup in self.backupDatabase: # Reduce TTL backup.TTL -= 1 if backup.TTL < 0: # Backup is down LOG.warning( 'Backup {}[{}] is DOWN with TTL: {}'.format( backup.deviceID, backup.deviceIP, backup.TTL)) self.__send_demotion_message(backup.deviceIP) # Remove from list self.backupDatabase.remove( backup) # TODO: Inform CIMI? LOG.debug('Backup removed from database.') else: # Backup is ok LOG.debug('Backup {}[{}] is OK with TTL: {}'.format( backup.deviceID, backup.deviceIP, backup.TTL)) if self._connected: sleep(self._lpp.get(self._lpp.TIME_KEEPER)) LOG.warning('Keeper thread stopped')
def createAgentResource(agentResource): """ Create a new Agent Resource in CIMI :param agentResource: Agent resource dicc formated :return: Agent resource ID """ URL = CIMIcalls.CIMI_URL + CIMIcalls.CIMI_AGENT_RESOURCE payload = agentResource try: r = requests.post(URL, headers=CIMIcalls.CIMI_HEADERS, verify=False, json=payload) rjson = r.json() LOG.debug( 'CIMI create agent [{}] status_code {} resource-id {}'.format( URL, r.status_code, rjson.get('resource-id'))) LOG.debug('CIMI reply: {}'.format(r.text)) if r.status_code == 409: LOG.error( 'CIMI create agent already exists! resource-id {}'.format( rjson.get('resource-id'))) elif r.status_code not in [200, 201]: LOG.error( 'CIMI create Agent error dettected! Payload Sent: {}'. format(payload)) return str(rjson.get('resource-id')) except: LOG.exception('CIMI agent [{}] failed'.format(URL)) return ''
def __trigger_triggerCAUclient(self): # payload = { # 'MACaddr': self.MACaddr, # 'detectedLeaderID': self.detectedLeaderID, # 'deviceID': self.deviceID, # 'IDkey': self.IDkey # } s_caucl = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s_caucl.connect(CPARAMS.CAU_CLIENT_ADDR) s_caucl.settimeout(15.) s_caucl.send('detectedLeaderID={},deviceID={}\n'.format( self.detectedLeaderID, self.deviceID).encode()) reply = s_caucl.recv(4092).decode() LOG.debug(self.TAG + 'CAU_client reply: {}'.format(reply)) s_caucl.close() if 'OK' in reply: self.isAuthenticated = True self.secureConnection = True return True else: LOG.warning( self.TAG + 'CAU_client reply \'{}\' evaluated as error'.format(reply)) self.isAuthenticated = False self.secureConnection = False return False
def __becomeLeader(self): # TODO """ :return: """ # 1- Shutdown/Notify all the modules involving Agent to Leader transiction. if self._leaderFailed: # Only if leader fails, triggers are needed, otherwise no action is required try: r = requests.get( URLS.build_url_address( '{}leader'.format(URLS.URL_POLICIES_ROLECHANGE), portaddr=( '127.0.0.1', '46050'))) #TODO Addr+Prt by CPARAMS; Parametrize LOG.info( self.TAG + 'Trigger to AgentStart Switch done. {}'.format(r.json())) self._imLeader = True self._imBackup = False except Exception as ex: LOG.exception(self.TAG + '_becomeLeader trigger to AgentStart failed') self.th_keep = threading.Thread(name='ar_keeper', target=self.__keeper, daemon=True) self.th_keep.start()
def post(self): """Reelection of the Leader""" found = False deviceIP = '' deviceID = api.payload['deviceID'] for device in cimi('topology', default=[]): # TODO: use real topology if device.get('deviceID') == deviceID: found = True deviceIP = device.get('deviceIP') break if not found: LOG.error('Device {} not found in the topology'.format(deviceID)) return {'deviceID': deviceID, 'deviceIP': deviceIP}, 404 if not arearesilience.imLeader(): LOG.error( 'Device is not a Leader, cannot perform a reelection in a non-leader device.' ) return {'deviceID': deviceID, 'deviceIP': deviceIP}, 401 correct = LeaderReelection.reelection(arearesilience, deviceID, deviceIP) if correct: return {'deviceID': deviceID, 'deviceIP': deviceIP}, 200 else: return {'deviceID': deviceID, 'deviceIP': deviceIP}, 403
def post(self): """Keepalive entrypoint for Leader""" if not arearesilience.imLeader(): # It's not like I don't want you to send me messages or anything, b-baka! return { 'deviceID': agentstart.deviceID, 'backupPriority': arearesilience.PRIORITY_ON_FAILURE }, 405 deviceIP = '' if 'deviceIP' not in api.payload else api.payload[ 'deviceIP'] correct, priority = arearesilience.receive_keepalive( api.payload['deviceID'], deviceIP) LOG.debug( 'Device {} has sent a keepalive. Result correct: {}, Priority: {}, deviceIP: {}' .format(api.payload['deviceID'], correct, priority, deviceIP)) if correct: # Authorized return { 'deviceID': agentstart.deviceID, 'backupPriority': priority }, 200 else: # Not Authorized return { 'deviceID': agentstart.deviceID, 'backupPriority': priority }, 403
def receivePolicies(self, payload): for key in payload: if key in self.__POLICIES.keys(): self.__POLICIES[key].set_json(payload[key]) LOG.info('Policies Received from Leader.') for policy in self.__POLICIES.keys(): LOG.debug('[{}] - {}'.format(policy, self.__POLICIES[policy].get_json())) return True
def get_topology(): resource, CIMIid = CIMIcalls.getAgentResource() topology = [] device_id = 0 if 'childrenIPs' in resource: for childrenIP in resource['childrenIPs']: topology.append((str(device_id), str(childrenIP))) LOG.debug('{} devices found in childrenIPs Agent Resource.'.format( len(topology))) return topology
def recv_reply(self, payload, deviceIP): try: dev_obj = DeviceInformation(dict=payload) dev_obj.deviceIP = deviceIP with self._db_lock: self._db.update({dev_obj.deviceID: dev_obj}) LOG.debug('Topology added/modified device: {}'.format(dev_obj)) return True except: LOG.exception('Error on receiving reply from device to a beacon.') return False
def setDict(self, dict): try: self.deviceID = str(dict.get('deviceID')) self.deviceIP = str(dict.get('deviceIP')) self.cpu_cores = int(dict.get('cpu_cores')) self.mem_avail = float(dict.get('mem_avail')) self.stg_avail = float(dict.get('stg_avail')) return True except: LOG.exception('Error on getting new device via Dict.') return False
def set_json(self, json): with self.__lock: try: ljson = loads(json) for key in ljson.keys(): if key in self.POLICIES.keys(): self.POLICIES[key] = ljson[key] return True except JSONDecodeError: LOG.exception('Error on getting new policies.') return False
def recommender_get_ips(): topology = CIMI.get_topology() agent_res, res_id = CIMI.getAgentResource() if res_id != '' and 'device_ip' in agent_res: self_device_ip = agent_res['device_ip'] else: self_device_ip = None response = [{'ipaddress': ip[1]} for ip in topology] if self_device_ip is not None: response.append({'ipaddress': self_device_ip}) LOG.debug('Recommender API response: \"{}\"'.format(response)) return jsonify(response), 200
def receive_keepalive(self, deviceID): with self.backupDatabaseLock: for backup in self.backupDatabase: if backup.deviceID == deviceID: # It's a match backup.TTL = int(self._lpp.get(self._lpp.MAX_TTL)) LOG.debug( 'backupID: {}; backupIP: {}; priority: {}; Keepalive received correctly' .format(backup.deviceID, backup.deviceIP, backup.priority)) return True, backup.priority return False, self.PRIORITY_ON_DEMOTION
def __trigger_startScan(self): r = requests.get(self.URL_DISCOVERY) rjson = r.json() if 'found_leaders' in rjson and 'used_mac' in rjson and len( rjson['found_leaders']) > 0: self.detectedLeaderID, self.MACaddr, self.bssid = rjson[ 'found_leaders'][0]['Leader ID'], rjson['used_mac'], rjson[ 'found_leaders'][0]['Bssid'] else: LOG.error( self.TAG + 'Discovery is not detecting a Leader \'{}\''.format(rjson)) self.detectedLeaderID, self.MACaddr, self.bssid = None, None, None
def debug(): sleep(10) # Give some time to the webservice LOG.info('Starting LDiscovery...') if CPARAMS.LEADER_FLAG: r = requests.get(URLS.build_url_address('{}beacon/start'.format(URLS.URL_LDISCOVERY_CONTROL), portaddr=('127.0.0.1', CPARAMS.POLICIES_PORT))) else: r = requests.get(URLS.build_url_address('{}scan/start'.format(URLS.URL_LDISCOVERY_CONTROL), portaddr=('127.0.0.1', CPARAMS.POLICIES_PORT))) LOG.info('LDiscovery started with status_code = {}'.format(r.status_code)) LOG.info('Starting Area Resilience...') r = requests.get(URLS.build_url_address(URLS.URL_POLICIES, portaddr=('127.0.0.1', CPARAMS.POLICIES_PORT))) LOG.debug('Area Resilience request result: {}'.format(r.json())) LOG.debug('Stopping thread activity.') return
def __trigger_switch_discovery(self): payload = { 'broadcast_frequency': 100, 'interface_name': CPARAMS.WIFI_DEV_FLAG, 'config_file': CPARAMS.WIFI_CONFIG_FILE, 'leader_id': self.deviceID } r = requests.post(self.URL_DISCOVERY_SWITCH_LEADER, json=payload) rjson = r.json() LOG.debug( self.TAG + 'Discovery broadcast start trigger received code: {} with msg: {}'. format(r.status_code, rjson['message'])) self.discovery_switched = rjson['message'] if r.status_code != 200: LOG.warning( self.TAG + 'Discovery broadcast failed with code {}. DHCP trigger is not performed.' .format(r.status_code)) else: payload2 = {'interface_name': CPARAMS.WIFI_DEV_FLAG} r2 = requests.post(self.URL_DISCOVERY_DHCP, json=payload2) rjson2 = r2.json() self.discovery_switched += '|| DHCP: ' + rjson2['message'] if r2.status_code == 200: LOG.debug( self.TAG + 'Discovery DHCP trigger successfully done with message: {}.' .format(rjson2['message'])) return True else: LOG.warning(self.TAG + 'Discovery DHCP trigger failed with code {}'. format(r2.status_code)) return False
def checkCIMIstarted(): """ Check if CIMI is up. :return: True if CIMI is started, False otherwise. """ URL = CIMIcalls.CIMI_URL + CIMIcalls.CIMI_API_ENTRY try: r = requests.get(URL, headers=CIMIcalls.CIMI_HEADERS, verify=False) LOG.debug('CIMI [{}] status_code {}, content {}'.format( URL, r.status_code, r.text)) return True except Exception as ex: LOG.debug('CIMI [{}] failed. Exception: {}'.format(URL, ex)) return False
def stop(self): """ Stop all the module activity :return: """ if self.isStarted: self._connected = False if self.th_proc is not None: while self.th_proc.is_alive(): LOG.debug(self.TAG + 'Waiting {} to resume activity...'.format( self.th_proc.name)) sleep(0.5) if self.th_keep is not None: while self.th_keep.is_alive(): LOG.debug(self.TAG + 'Waiting {} to resume activity...'.format( self.th_keep.name)) sleep(0.1) LOG.info(self.TAG + 'All threads stoped. AreaResilience module is stopped.') else: LOG.info(self.TAG + 'Module is not started') return
def get_resource(resource_id): """ Get resource by ID if exists :param resource_id: CIMI resource id :return: status_code and resource if successful, None otherwise """ URL = CIMIcalls.CIMI_URL + '/' + resource_id try: r = requests.get(URL, headers=CIMIcalls.CIMI_HEADERS, verify=False) rjson = r.json() LOG.debug('CIMI GET resource [{}] status_code {}'.format( URL, r.status_code)) return r.status_code, rjson except: LOG.exception('CIMI GET resource [{}] failed.'.format(URL)) return None, None
def addBackup(self, deviceID, deviceIP, priority): found = False with self.backupDatabaseLock: for backup in self.backupDatabase: if backup.deviceID == deviceID: LOG.debug(self.TAG + 'Backup {} found!'.format(deviceID)) found = True break if not found: correct = self.__send_election_message(deviceIP) if correct: new_backup = BackupEntry(deviceID, deviceIP, priority) with self.backupDatabaseLock: self.backupDatabase.append(new_backup) LOG.info('Backup {}[{}] added with priority {}'.format( deviceID, deviceIP, priority)) return correct
def start(self, deviceID): # TODO: Give deviceID at startup? """ :return: """ self._deviceID = deviceID if self.isStarted: LOG.warning(self.TAG + 'Procedure is already started...') return False else: self.th_proc = threading.Thread(name='area_res', target=self.__common_flow, daemon=True) self.th_proc.start() self.isStarted = True LOG.info(self.TAG + 'Module Started') return True
def startScanning(self): if self._isStarted or self._isScanning: LOG.warning( 'LDiscovery is already started: isStarted={} isScanning={}'. format(self._isStarted, self._isScanning)) return False self._th_proc = threading.Thread(name='LDiscS', target=self.__scanning_flow, daemon=True) self._connected = True self._isStarted = True self._isScanning = True self.leaderIP = None self.leaderID = None self._th_proc.start() LOG.info('LDiscovery successfully started in Scan Mode.') return True
def __categorize_device(self): try: cpu_cores = int( psutil.cpu_count()) if psutil.cpu_count() is not None else -1 mem_avail = float(psutil.virtual_memory().available / (2**30)) storage_avail = float( sum([ psutil.disk_usage(disk.mountpoint).free for disk in psutil.disk_partitions() ]) / 2**30) except: LOG.exception('Categorization not successful') cpu_cores = 0 mem_avail = .0 storage_avail = .0 finally: return cpu_cores, mem_avail, storage_avail
def delete_resource(resource_id): """ Delete resource by ID in CIMI :param resource_id: CIMI resource ID :return: status_code if successful, None otherwise """ URL = CIMIcalls.CIMI_URL + '/' + resource_id try: r = requests.delete(URL, headers=CIMIcalls.CIMI_HEADERS, verify=False) # rjson = r.json() LOG.debug('CIMI DELETE resource [{}] status_code {}'.format( URL, r.status_code)) return r.status_code except: LOG.exception('CIMI DELETE resource [{}] failed.'.format(URL)) return None
def startBeaconning(self): if self._isStarted or self._isBroadcasting: LOG.warning( 'LDiscovery is already started: isStarted={} isBroadcasting={}' .format(self._isStarted, self._isBroadcasting)) return False self._th_proc = threading.Thread(name='LDiscB', target=self.__beaconning_flow, daemon=True) self._connected = True self._isStarted = True self._isBroadcasting = True self.leaderIP = None self.leaderID = self._deviceID self._db = {} self._th_proc.start() LOG.info('LDiscovery successfully started in Beacon Mode.') return True
def modify_resource(resource_id, payload): """ Modify resource by ID in CIMI :param resource_id: CIMI resource id :param payload: new content of the resource :return: status_code if successful, None otherwise """ URL = CIMIcalls.CIMI_URL + '/' + resource_id try: r = requests.put(URL, headers=CIMIcalls.CIMI_HEADERS, verify=False, json=payload) # rjson = r.json() LOG.debug( 'CIMI EDIT resource [{}] status_code {} content {}'.format( URL, r.status_code, r.content)) return r.status_code except: LOG.exception('CIMI EDIT resource [{}] failed.'.format(URL)) return None