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
Exemplo n.º 5
0
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"
Exemplo n.º 6
0
 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)),
                 }
             )
Exemplo n.º 7
0
 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,
         ])
     ]
Exemplo n.º 8
0
 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
Exemplo n.º 10
0
 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,
     )
Exemplo n.º 11
0
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 {}))
Exemplo n.º 13
0
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