def main(): '''Main entry function for the script.''' try: init_args(detectors) data = Data() for input_name, input in inputs.items(): t = dbg_time(f'INPUT: {input_name}') input(data) log.dbg(f'INPUT: Done in {t}s') input_post_process.post_process(data) for detector_name in args.license_detectors: func = detectors[detector_name] optional = detector_name in args.optional_license_detectors t = dbg_time(f'DETECTOR: {detector_name}') func(data, optional) log.dbg(f'DETECTOR: Done in {t}s') output_pre_process.pre_process(data) for generator_name, generator in generators.items(): output_file = args.__dict__[f'output_{generator_name}'] if output_file is not None: t = dbg_time(f'GENERATOR: {generator_name}') output_template.generate(data, output_file, Path(__file__).parent / generator) log.dbg(f'GENERATOR: Done in {t}s') except SbomException as e: log.die(str(e), exit_code=1)
def get_next_timestep(self): curr_time = float(self.data[1].split(',')[0]) prev_time = float(self.data[2].split(',')[0]) data = Data(self.getY(), self.getH(), self.getStd(), curr_time, prev_time) self.__truncate() return data
def GD(self, request, context): job_type = request.data_handling_type starter_node = Data(request.node_key, request.node_address) data = Data(request.data_key, request.data_value) cur_key = self.node_table.cur_node.key successor_key = self.node_table.finger_table.entries[n.successor].key # 만약 get 한 값이 들어왔을 때 if job_type == d.get_result: # 값이 없으면 not found를 출력하게끔 한 뒤 if data.value == "": data.value = "not found" # 실제 get 한 값들을 보여줌 logging.info( f"request key:{data.key[:10]}'s value is {data.value}, stored in {starter_node.value}" ) # 만약 자신의 data table에 접근해야 하는 값이라면 elif cur_key <= data.key < successor_key or successor_key < cur_key <= data.key or data.key < successor_key < cur_key: if job_type == d.get: self.get(starter_node, data) if job_type == d.set: self.data_table.set(data) logging.info( f"request key:{data.key[:10]}'s value is set to {data.value}, stored in {self.node_table.cur_node.value}" ) if job_type == d.delete: self.data_table.delete(data.key) logging.info( f"request key:{data.key[:10]} is deleted from {self.node_table.cur_node.value}" ) else: # 살아있는 가장 가까운 노드를 찾음 nearest_node = self.node_table.find_nearest_alive_node(data.key) # 그 노드에게 이 정보를 보낸 뒤 종료 threading.Thread( target=data_request, args=( starter_node, nearest_node, # Finger Table 구현되면 수정 필요 data, job_type)).start() return chord_pb2.HealthReply(pong=0)
def remove_duplicates(data: Data): '''Remove duplicated entries in data.files list.''' def is_not_visited(file: FileInfo): if file.file_path in visited: return False visited.add(file.file_path) return True visited = set() data.files = list(filter(is_not_visited, data.files))
def get(self, starter_node: Data, req_data: Data): try: value = self.data_table.get(req_data.key).value except ValueError: value = "" threading.Thread( target=data_request, args=( self.node_table.cur_node, starter_node, # Finger Table 구현되면 수정 필요 Data(req_data.key, value), d.get_result)).start()
def request_node_info(node: Data, which_info: int): """ 해당 노드에게 그 노드가 가지고 있는 노드들의 정보를 물어봅니다. ex) predecessor에게 predecessor가 가지고 있는 finger table의 데이터를 물어봄 :param node: 노드 정보를 물어볼 노드입니다. :param which_info: 해당 노드의 몇 번째 finger table의 정보, 혹은 predecessor인지를 물어봅니다. 규격은 utils.py의 class _NodeType를 사용합니다. :return: 요청한 노드의 정보가 존재하면 해당 노드의 정보를, param node가 죽었거나 해당 정보가 없으면 False를 return합니다. """ # which_info는 utils.NodeType 의 명세를 따름 try: with grpc.insecure_channel(node.value) as channel: stub = chord_pb2_grpc.GetNodeValueStub(channel) response = stub.GetNodeVal( chord_pb2.NodeDetail(node_address=node.value, which_node=which_info)) if response.node_key == "0": return False return Data(response.node_key, response.node_address) except _InactiveRpcError: return False
def __init__(self, ids, address: str, data_table: TableEntry): # generate node table super().__init__() host, port = address.split(":") # 현재 본인의 노드 정보와, predecessor 는 finger table에 없지만 필요하므로 별도로 선언함 self.cur_node = Data(ids, address) # 현재 네트워크에 존재하는 노드 수를 정의 self.network_node_num = 1 # 현재 존재하는 네트워크 노드 수 # finger table 정의 self.finger_table = TableEntry() # data table 정의 self.data_table = data_table # stop flag 정의 self.stop_flag = False # finger table update cycle 정의 self.finger_table_update_cycle = 0 # 보고서 상, 최초 init은 두 개의 노드가 있는 network이기 때문에, 해당 네트워크를 init해 줌 if port == "50051": self.predecessor = Data("0b03a4d8a7d8f8f4c7afae9aeda7d76b431f4cba", host + ":50054") self.finger_table.set("0b03a4d8a7d8f8f4c7afae9aeda7d76b431f4cba", host + ":50054") self.finger_table.entries.append(Data(ids, address)) self.network_node_num += 1 elif port == "50054": self.predecessor = Data("a09b0ce42948043810a1f2cc7e7079aec7582f29", host + ":50051") self.finger_table.set("t1", "t2") self.finger_table.set("t2", "t1") self.finger_table.entries[n.successor].update_info(self.predecessor, 0) self.finger_table.entries[n.d_successor].update_info(self.cur_node, 1) self.network_node_num += 1 else: self.predecessor = Data(ids, address) self.finger_table.set(ids, address) # 0 - successor self.finger_table.entries.append(Data(ids, address)) # 1 - double successor
def detect(data: Data, optional: bool): '''License detection using scancode-toolkit.''' if optional: filtered = tuple( filter(lambda file: len(file.licenses) == 0, data.files)) else: filtered = data.files if len(filtered) > 0: check_scancode() for result, file, _ in concurrent_pool_iter(run_scancode, filtered): for i in result['files'][0]['licenses']: friendly_id = '' if 'spdx_license_key' in i and i['spdx_license_key'] != '': friendly_id = i['spdx_license_key'] elif 'key' in i and i['key'] != '': friendly_id = i['key'] id = friendly_id.upper() if id in ('UNKNOWN-SPDX', 'LICENSEREF-SCANCODE-UNKNOWN-SPDX'): friendly_id = re.sub(r'SPDX-License-Identifier:', '', i['matched_text'], flags=re.I).strip() id = friendly_id.upper() if id == '': log.wrn( f'Invalid response from scancode-toolkit, file: {file.file_path}' ) continue file.licenses.add(id) file.detectors.add('scancode-toolkit') if not is_spdx_license(id): if 'name' in i: name = i['name'] elif 'short_name' in i: name = i['short_name'] else: name = None if 'spdx_url' in i: url = i['spdx_url'] elif 'reference_url' in i: url = i['reference_url'] elif 'scancode_text_url' in i: url = i['scancode_text_url'] else: url = None if id in data.licenses: license = data.licenses[id] if license.is_expr: continue else: license = License() data.licenses[id] = license license.id = id license.friendly_id = friendly_id if license.name is None: license.name = name if license.url is None: license.url = url license.detectors.add('scancode-toolkit')
def TM(self, request, context): logging.debug(f'Toss Message received from {request.node_address}') if request.message_type == t.join_node: # 만약 join일 시, finger table 에서의 insert 위치를 찾아본다. # 1. 본인의 key값보다 크고, successor (finger_table[0]) 의 key 값보다 작은 경우는, 내가 추가한다. if self.node_table.cur_node.key < request.node_key < self.node_table.finger_table.entries[n.successor].key or \ self.node_table.finger_table.entries[n.successor].key < self.node_table.cur_node.key < request.node_key: logging.info(f'Now Adding {request.node_address}...') self.notify_new_node_income( new_node=Data(request.node_key, request.node_address)) # 2. 아닐 경우에는, 노드 테이블을 순회하면서 적절히 보낼 위치를 찾는다. # -> 일단 지금은, 바로 successor 에게 넘긴다. (finger table 의 속성을 변경하는 작업이 필요함) else: logging.info( f'Passing {request.node_address}`s message to {self.node_table.finger_table.entries[n.successor].value}' ) threading.Thread( target=toss_message, args=(Data(request.node_key, request.node_address), self.node_table.finger_table.entries[n.successor], request.message_type)).start() return chord_pb2.HealthReply(pong=0) # 만약에 메시지 타입이 finger table을 업데이트하는 메시지라면 if request.message_type == t.finger_table_setting: logging.debug( f'received finger table update message : {request.node_key}. {request.node_address}, {request.message}' ) # 만약 받은 요청의 node key와 자신의 key가 같다면 (순회를 마쳤다면) if request.node_key == self.node_table.cur_node.key: logging.debug("finished receiving update message") # 현재 네트워크의 노드 수를 갱신해준 후 종료 self.node_table.node_network_num = request.message return chord_pb2.HealthReply(pong=0) # 만약 받은 요청의 node_type가 join_node 라면 (새로운 node가 join되었으면) if request.node_type == t.join_node: # 현재 노드의 네트워크에 존재하는 노드개수 변수를 1 증가시킴 self.node_table.node_network_num += 1 # 만약 받은 요청의 node_type가 left_node 라면 (노드가 나간다면) if request.node_type == t.left_node: # 현재 노드의 네트워크에 존재하는 노드개수 변수를 1 감소시킴 self.node_table.node_network_num -= 1 logging.debug( "sending update message complete, pass to successor") threading.Thread( target=toss_message, args=(Data(request.node_key, request.node_address), self.node_table.finger_table.entries[n.successor], request.message_type, request.message)).start() return chord_pb2.HealthReply(pong=0) cur_node_num = int(request.message) cur_finger_table_num = math.log2(cur_node_num) # 만약 현재 메시지 수가 2의 배수라면 (1 포함) if cur_finger_table_num - int(cur_finger_table_num) == 0: # 원본에게 finger table을 업데이트하도록 설정 # 이 요청이 끝나야 계속 가도록 설정 is_starter_node_alive = notify_node_info( self.node_table.cur_node, Data(request.node_key, request.node_address), int(cur_finger_table_num)) logging.debug(f"send res : {is_starter_node_alive}") # 만약 원본 노드가 응답이 없으면 (연결이 끊겼으면), 메시지를 끊음 if is_starter_node_alive is False: logging.debug( f"starter node network error, will end toss message here" ) return chord_pb2.HealthReply(pong=0) # 만약 어떤 사유로 노드 네트워크를 4번 이상 순회했는데도 여전히 돈다면, 네트워크가 끊어짐을 알림 if cur_node_num > 4 * self.node_table.node_network_num: logging.info( "CRITICAL! network is corrupted. end this toss message") return chord_pb2.HealthReply(pong=0) # 자신이 처리할 일이 끝났으면, 이 요청을 그대로 자신의 successor에게 전송 logging.debug("sending update message complete, pass to successor") threading.Thread( target=toss_message, args=(Data(request.node_key, request.node_address), self.node_table.finger_table.entries[n.successor], request.message_type, request.message + 1)).start() return chord_pb2.HealthReply(pong=0)
def command_handler(self, command): commands = command.split() if commands[0] == 'get': key = commands[1] try: value = self.data_table.get(key) logging.info( f"request key:{key[:10]}'s value is {value}, stored in {self.address}" ) except ValueError: # 먼저, 해당하는 finger table이 살아있는지, 죽었으면 그 밑에 노드로 계속 보내는 health check 작업이 필요하다. nearest_node = self.node_table.find_nearest_alive_node(key) data_request(self.node_table.cur_node, nearest_node, Data(key, ""), d.get) elif commands[0] == 'set': key, value = commands[1].split(":") key = generate_hash(key) # 만약 자기 자신에 넣어야 하면 cur_key = self.node_table.cur_node.key successor_key = self.node_table.finger_table.entries[ n.successor].key # 만약 자기 자신에 넣을 수 있으면 자기 자신에 넣음 if cur_key <= key < successor_key or successor_key < cur_key <= key or key < successor_key < cur_key: self.data_table.set(key, value) logging.info( f"request key:{key[:10]}'s value is set to {value}, stored in {self.address}" ) # 아닐 경우 살아있는 가장 가까운 노드를 찾아서 넣음 else: nearest_node = self.node_table.find_nearest_alive_node(key) data_request(self.node_table.cur_node, nearest_node, Data(key, value), d.set) elif commands[0] == 'delete': key = commands[1] try: self.data_table.delete(key) logging.info( f"request key:{key[:10]} is deleted from {self.address}") except ValueError: nearest_node = self.node_table.find_nearest_alive_node(key) data_request(self.node_table.cur_node, nearest_node, Data(key, ""), d.delete) elif commands[0] == 'join': toss_message(self.node_table.cur_node, Data("", commands[1]), t.join_node) logging.info(f"finishing join node, will update finger table...") toss_message(self.node_table.cur_node, self.node_table.finger_table.entries[n.successor], t.finger_table_setting, 1, t.join_node) elif commands[0] == 'disjoin': self.server.stop(0) # HealthCheck를 못 받게 모든 서버 종료 self.node_table.stop_flag = True # health check 송신 종료 logging.info( 'Waiting for other nodes to update their finger tables') time.sleep(10) # 다른 Node들이 FingerTable을 업데이트할때까지 대기 for entry in self.data_table.entries: threading.Thread(target=data_request, args=(self.node_table.cur_node, self.node_table.predecessor, entry, d.set)).start() toss_message(self.node_table.cur_node, self.node_table.finger_table.entries[n.successor], t.finger_table_setting, 1, t.left_node) elif commands[0] == 'show': # 노드 테이블 정보 출력하는 기능 추가 self.node_table.log_nodes() elif commands[0] == 'summary': self.data_table.summary() elif commands[0] == 'ft_update': toss_message(self.node_table.cur_node, self.node_table.finger_table.entries[0], t.finger_table_setting, 1)
def pre_process(data: Data): '''Do pre-processing of data for simpler usage by the output modules.''' # Sort files data.files.sort(key=lambda f: f.file_path) # Convert list of licenses to license expression for each file for file in data.files: licenses = file.licenses if len(file.licenses) > 0 else [''] simple_expr_items = set() or_expr_items = set() repeated_expr_items = set() for license in licenses: license = license.upper() info = get_spdx_license_expr_info(license) if info.valid and not info.is_id_only and len(info.licenses) > 1: repeated_expr_items.update(info.licenses) if not info.valid or info.or_present: or_expr_items.add(license) else: simple_expr_items.add(license) simple_expr_items -= repeated_expr_items if len(or_expr_items) > 1 or len(simple_expr_items) > 0: or_expr_items = { f'({x})' for x in or_expr_items } file.license_expr = ' AND '.join(sorted(simple_expr_items.union(or_expr_items))) # Collect all used detectors for file in data.files: data.detectors.update(file.detectors) # Collect all used licenses and license expressions and put them into data.licenses used_licenses = dict() for file in data.files: if file.license_expr in used_licenses: continue info = get_spdx_license_expr_info(file.license_expr) if not info.valid or not info.is_id_only: expr = LicenseExpr() expr.valid = info.valid expr.id = file.license_expr expr.friendly_id = info.friendly_expr expr.licenses = sorted(info.licenses) expr.custom = not info.valid for id in expr.licenses: if not is_spdx_license(id): expr.custom = True break used_licenses[file.license_expr] = expr for id in info.licenses: if id in used_licenses: continue elif is_spdx_license(id): used_licenses[id] = get_license(id) elif id in data.licenses: used_licenses[id] = data.licenses[id] else: lic = get_license(id) if lic is None: lic = License() lic.id = id lic.friendly_id = id used_licenses[id] = lic data.licenses = used_licenses # Group files by license id or expression for file in data.files: if file.license_expr not in data.files_by_license: data.files_by_license[file.license_expr] = list() data.files_by_license[file.license_expr].append(file) # Sort licenses def lic_reorder(id: str): lic = data.licenses[id] lic: 'License|LicenseExpr' if id == '': return 'A' elif lic.is_expr: if lic.custom: return 'B' + id else: return 'E' + id else: if id.startswith('LicenseRef-'): return 'D' + id elif lic.custom: return 'C' + id else: return 'F' + id data.licenses_sorted = sorted(data.licenses.keys(), key=lic_reorder)