def process_request(headers: dict, body: str, form: dict) -> Response: """ Perform the actual processing of a request """ deploy_config = file_paths.load_yaml_from_file("deploy.yaml") if not api.validate_message(deploy_config, body, headers["x-hub-signature-256"]): print("Unauthorized request!") raise HTTPException(status_code=404, detail="Invalid body hash") access_token = api.get_access_token(api.get_jwt(deploy_config)) print("Got event {0} with action {1}".format(headers["x-github-event"], form.get("action", ""))) if headers["x-github-event"] == "check_suite": checks.handle_check_suite(form, access_token) elif headers["x-github-event"] == "check_run": checks.process_check_run(deploy_config, form, access_token) elif headers["x-github-event"] == "push": push.check_push_for_deployment(deploy_config, form, access_token) elif headers["x-github-event"] == "deployment": deployment.handle_deployment(form, deploy_config, access_token) else: print("Skipping event - no handler registered!")
def get_external_addresses(config_path: str) -> ExternalAddresses: """ Gets the yaml external address definitions """ return ExternalAddresses( file_paths.load_yaml_from_file( file_paths.get_path( [config_path, file_paths.EXTERNAL_ADDRESSES_CONFIG])) or [])
def run_listener(): """ Runs the listener """ deploy_config = file_paths.load_yaml_from_file("deploy.yaml") uvicorn.run("webhook_listener:app", port=deploy_config["git"]["webhook-port"], reload=True)
def get_port_groups(config_path: str) -> List[PortGroup]: """ Gets the yaml port group definitions """ port_groups = [] for port_group in file_paths.get_config_files( [config_path, file_paths.PORT_GROUPS_FOLDER]): group_name = path.basename(port_group).replace(".yaml", "") port_groups.append( PortGroup(group_name, **file_paths.load_yaml_from_file(port_group) or {})) return port_groups
def test_load_yaml_file(): """ Test the yaml file loader """ result_obj = file_paths.load_yaml_from_file( "tests/unit/test_yaml/test.yaml") assert result_obj == { "value": 1, "a-list": ["apple", "orange"], "nested": { "foo": "bar", "baz": ["ipsum", "lorem"] }, }, "Yaml loaded correctly"
def _load_rules(self): """ Load rules for this firewall """ for rule_path in file_paths.get_config_files( [self.config_path, file_paths.NAT_FOLDER,] ): if type_checker.is_number(rule_path.split(path.sep)[-1].rstrip(".yaml")): self.add_rule( { "number": rule_path.split(path.sep)[-1].rstrip(".yaml"), "config_path": self.config_path, **(file_paths.load_yaml_from_file(rule_path)), } )
def _load_hosts(self) -> None: """ Load hosts for this network """ self.hosts = [ Host( host_path.split(path.sep)[-1][:-5], self, self.config_path, **(file_paths.load_yaml_from_file(host_path))) for host_path in file_paths.get_config_files([ self.config_path, file_paths.NETWORK_FOLDER, self.name, file_paths.HOSTS_FOLDER, ]) ]
def _load_firewalls(self) -> None: """ Load firewalls for this network """ self.firewalls = [ Firewall(firewall_path.split(path.sep)[-2], network_name=self.name, config_path=self.config_path, **(file_paths.load_yaml_from_file(firewall_path))) for firewall_path in file_paths.get_folders_with_config([ self.config_path, file_paths.NETWORK_FOLDER, self.name, file_paths.FIREWALL_FOLDER, ]) ]
def authenticate(credentials: HTTPBasicCredentials = Depends(security)): """ Checks the current user for authentication """ logging_config = file_paths.load_yaml_from_file("deploy.yaml")["logging"] correct_user = secrets.compare_digest(credentials.username, logging_config["user"]) correct_pass = secrets.compare_digest(credentials.password, logging_config["pass"]) if not (correct_user and correct_pass): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Basic"}, ) return credentials.username
def create_from_configs(cls, config_path: str): """ Load configuration from files """ nat = NAT(config_path) return cls( secondary_configs.get_global_configuration(config_path), secondary_configs.get_port_groups(config_path), secondary_configs.get_external_addresses(config_path), [ Network( network_folder.split(path.sep)[-2], nat, config_path, **(file_paths.load_yaml_from_file(network_folder)) ) for network_folder in file_paths.get_folders_with_config( [config_path, file_paths.NETWORK_FOLDER] ) ], nat, )
def check_trigger_deploy(form: dict, access_token: str): """ Checks if a deploy should be attempted, namely, the check suite was successful and we can detect the ref for which the check suite was run """ if form["check_suite"]["conclusion"] == "success": print("Preparing to reattempt deployment for branch " f"{form['check_suite']['head_branch']}") metadata = DeployMetadata( form["check_suite"]["before"], form["check_suite"]["after"], None, None, file_paths.load_yaml_from_file("deploy.yaml"), ) push.create_deployment( access_token, form["check_suite"]["head_branch"], form["repository"]["deployments_url"], metadata, ) else: print( "Not attempting to schedule deployment due to check suite failure")
def get_global_configuration(config_path: str) -> GlobalSettings: """ Gets the yaml global configuration content """ return GlobalSettings(**(file_paths.load_yaml_from_file( file_paths.get_path([config_path, file_paths.GLOBAL_CONFIG])) or {}))
def get_commands_to_run(current_config_path: str, previous_config_path: str, only_return_diff: bool = False) -> List[List[str]]: """ Given two sets of configurations, returns the ordered command sets to execute """ deploy_config = file_paths.load_yaml_from_file("deploy.yaml") current_config = root_parser.RootNode.create_from_configs( current_config_path) previous_config = root_parser.RootNode.create_from_configs( previous_config_path) current_ordered_commands, current_command_list = current_config.get_commands( ) # The previous ordered commands are unused, but need the list # pylint: disable=unused-variable previous_ordered_commands, previous_command_list = previous_config.get_commands( ) difference = diff_configurations(current_command_list, previous_command_list) apply_diff_only = only_return_diff or deploy_config["apply-difference-only"] run_commands = [[]] # Run deletes in a single batch first, since that _shouldn't_ cause any issues for key, value in difference.removed.items(): if isinstance(value, list): for each_value in value: run_commands[0].append(" ".join( ["delete", key, shlex.quote(each_value)])) else: run_commands[0].append(" ".join( ["delete", key, shlex.quote(value)])) # If applying whole diff, ensure nat and firewalls get cleared, since # rule re-ordering could mean something from a previous rule gets merged # e.g. before: # rule 20: source <addr> port 80 # after preserves source, ADDING destination instead of overwriting the original: # rule 20 :destination <addr2> source <addr> if not apply_diff_only: # First get every firewall in the previous config previous_firewall_names = [ firewall.name for network in previous_config.networks for firewall in network.firewalls ] # And then restrict the current ones to those in the previous, since # won't need to reset a net-new firewall configuration current_firewall_names = [ firewall.name for network in current_config.networks for firewall in network.firewalls if firewall.name in previous_firewall_names ] run_commands[0].extend([ "delete service nat", *[ f"delete firewall name {firewall_name} rule" for firewall_name in current_firewall_names ], ]) # Can have multiple DHCP networks set, but on updates # this will likely overlap (e.g. if shrinking or extending) address pool # need to delete any that are in both previous and current configs previous_dhcp_networks = [ network.name for network in previous_config.networks if hasattr(network, "stop") and network.stop ] current_dhcp_networks = [ network for network in current_config.networks if hasattr(network, "stop") and network.stop and network.name in previous_dhcp_networks ] run_commands[0].extend([ f"delete service dhcp-server shared-network-name {network.name} " f"subnet {network.cidr} start" for network in current_dhcp_networks ]) for command_set in current_ordered_commands: run_commands.append([]) for command in command_set: command_prefix = (command if not apply_diff_only else get_command_key(command)) # Include commands only if applying the entire config should_include = not apply_diff_only if isinstance(difference.changed.get( command_prefix, None), list) or isinstance( difference.added.get(command_prefix, None), list): command_value = shlex.split(command)[-1] should_include = should_include or ( command_value in difference.added.get(command_prefix, []) or command_value in difference.changed.get( command_prefix, [])) else: # or the command's value is new or changed should_include = should_include or ( command_prefix in difference.changed or command_prefix in difference.added) # the command's value changed if should_include: run_commands[-1].append("set " + command) if not run_commands[-1]: del run_commands[-1] return run_commands