Exemple #1
0
 def trigger_data_update(self, update: DataUpdate):
     # make sure the id has a unique id for tracking
     if update.id is None:
         update.id = uuid.uuid4().hex
     logger.info("Triggering data update with id: {id}", update=update, id=update.id)
     asyncio.create_task(self.update_policy_data(
         update, policy_store=self._policy_store, data_fetcher=self._data_fetcher))
Exemple #2
0
 async def _update_policy_data_callback(self, data: dict = None, topic=""):
     """
     Pub/Sub callback - triggering data updates
     will run when we get notifications on the policy_data topic.
     i.e: when new roles are added, changes to permissions, etc.
     """
     if data is not None:
         reason = data.get("reason", "")
     else:
         reason = "Periodic update"
     logger.info("Updating policy data, reason: {reason}", reason=reason)
     update = DataUpdate.parse_obj(data)
     self.trigger_data_update(update)
Exemple #3
0
    async def get_base_policy_data(self, config_url: str = None, data_fetch_reason="Initial load"):
        """
        Load data into the policy store according to the data source's config provided in the config URL

        Args:
            config_url (str, optional): URL to retrive data sources config from. Defaults to None ( self._data_sources_config_url).
            data_fetch_reason (str, optional): Reason to log for the update operation. Defaults to "Initial load".
        """
        logger.info("Performing data configuration, reason: {reason}", reason={data_fetch_reason})
        sources_config = await self.get_policy_data_config(url=config_url)
        # translate config to a data update
        entries = sources_config.entries
        update = DataUpdate(reason=data_fetch_reason, entries=entries)
        self.trigger_data_update(update)
Exemple #4
0
def publish_data_update(
        token: Optional[str] = typer.
    Argument(
        None,
        help=
        "the JWT obtained from the server for authentication (see obtain-token command)",
        envvar="OPAL_CLIENT_TOKEN"),
        server_url: str = typer.Option(
            "http://localhost:7002",
            help="url of the OPAL-server to send the update through"),
        server_route: str = typer.Option(
            "/data/config", help="route in the server for update"),
        reason: str = typer.Option("", help="The reason for the update"),
        entries: str = typer.Option(
            "[]",
            "--entries",
            "-e",
            help="Pass in the the DataUpdate entries as JSON",
            callback=lambda x: json.loads(x)),
        src_url: str = typer.
    Option(
        None,
        help=
        "[SINGLE-ENTRY-UPDATE] url of the data-source this update relates to, which the clients should approach"
    ),
        topics: List[str] = typer.
    Option(
        None,
        "--topic",
        "-t",
        help=
        "[SINGLE-ENTRY-UPDATE] [List] topic (can several) for the published update (to be matched to client subscriptions)"
    ),
        src_config: str = typer.Option(
            "{}",
            help="[SINGLE-ENTRY-UPDATE] Fetching Config as JSON",
            callback=lambda x: json.loads(x)),
        dst_path: str = typer.
    Option(
        "",
        help=
        "[SINGLE-ENTRY-UPDATE] Path the client should set this value in its data-store"
    ),
        save_method: str = typer.
    Option(
        "PUT",
        help=
        "[SINGLE-ENTRY-UPDATE] How the data should be saved into the give dst-path"
    )):
    """
    Publish a DataUpdate through an OPAL-server (indicated by --server_url).

    [SINGLE-ENTRY-UPDATE]
        Send a single update DataSourceEntry via the --src-url, --src-config, --topics, --dst-path, --save-method
        must include --src-url to use this flow.
    [Multiple entries]
        Set DataSourceEntires as JSON (via --entries)
        if you include a single entry as well- it will be merged into the given JSON
    """
    from aiohttp import ClientSession, ClientResponse

    if not isinstance(entries, list):
        typer.secho("Bad input for --entires was ignored", fg="red")
        entries = []

    entries: List[DataSourceEntry]

    # single entry update
    if src_url is not None:
        entry = DataSourceEntry(url=src_url,
                                topics=topics,
                                dst_path=dst_path,
                                save_method=save_method,
                                config=src_config)
        entries.append(entry)

    server_url = f"{server_url}{server_route}"
    update = DataUpdate(entries=entries, reason=reason)

    async def publish_update():
        headers = {}
        if token is not None:
            headers = {"Authorization": f"bearer {token}"}
        async with ClientSession(headers=headers) as session:
            body = update.json()
            res = await session.post(server_url, data=body)
            return res

    async def get_response_text(res: ClientResponse):
        return await res.text()

    typer.echo(f"Publishing event:")
    typer.secho(f"{str(update)}", fg="cyan")
    res = asyncio.run(publish_update())

    if res.status == 200:
        typer.secho("Event Published Successfully", fg="green")
    else:
        typer.secho("Event publishing failed with status-code - {res.status}",
                    fg="red")
        text = asyncio.run(get_response_text(res))
        typer.echo(text)