pyfsr.cli.appliance.integrations

pyfsr appliance integrations – the connector runtime’s pip index.

When a connector is installed the platform pip-installs its requirements.txt into the integrations environment, using that environment’s own pip.conf. Out of the box the file names only Fortinet’s content mirror as index-url, so a connector that depends on a package the mirror does not carry (anything published only to PyPI) installs with its dependency missing. Some appliances carry PyPI as extra-index-url; others do not, and no REST API or UI setting writes the file – it has to be edited on the box.

The file ships immutable (chattr +i), so a plain write fails with “Operation not permitted”. ensure_extra_index() clears the flag, writes, and puts the flag back in a finally so a failed write never leaves the file unlocked. It is idempotent: a URL already listed is a no-op that touches nothing.

The new content is passed as a command argument, never on stdin: the transports put the sudo password on stdin, and with passwordless sudo nothing consumes it, so it would land in the file.

Attributes

Classes

PipIndex

The index settings in the integrations pip.conf.

IndexChange

Outcome of ensure_extra_index().

Functions

parse(→ PipIndex)

Read index-url / extra-index-url from pip.conf text ([global] or bare keys).

add_extra_index(→ str)

Return pip.conf text with url added as an extra index.

pip_index(→ PipIndex)

Read the integrations pip index settings and the file's immutable flag. Read-only.

ensure_extra_index(→ IndexChange)

Add url as an extra pip index for the connector runtime. Gated by yes.

Module Contents

pyfsr.cli.appliance.integrations.PIP_CONF = '/opt/cyops/configs/integrations/packages/integrations_env/pip.conf'[source]
pyfsr.cli.appliance.integrations.PYPI_SIMPLE = 'https://pypi.org/simple/'[source]
class pyfsr.cli.appliance.integrations.PipIndex(/, **data: Any)[source]

Bases: pydantic.BaseModel

The index settings in the integrations pip.conf.

path: str[source]
index_url: str | None = None[source]
extra_index_urls: list[str] = None[source]
immutable: bool = False[source]
text: str = ''[source]
class pyfsr.cli.appliance.integrations.IndexChange(/, **data: Any)[source]

Bases: pydantic.BaseModel

Outcome of ensure_extra_index().

url: str[source]
changed: bool[source]
before: PipIndex[source]
after: PipIndex[source]
backup: str | None = None[source]
property ok: bool[source]

The URL is listed now, and the immutable flag is as it was before.

pyfsr.cli.appliance.integrations.parse(text: str, *, path: str = PIP_CONF, immutable: bool = False) → PipIndex[source]

Read index-url / extra-index-url from pip.conf text ([global] or bare keys).

pyfsr.cli.appliance.integrations.add_extra_index(text: str, url: str) → str[source]

Return pip.conf text with url added as an extra index.

pip reads a whitespace-separated list, so an existing extra-index-url line is extended in place; otherwise a new line goes at the end of [global] (or the end of the file when there are no sections).

pyfsr.cli.appliance.integrations.pip_index(transport: pyfsr.cli.appliance.transport.Transport, *, path: str = PIP_CONF) → PipIndex[source]

Read the integrations pip index settings and the file’s immutable flag. Read-only.

pyfsr.cli.appliance.integrations.ensure_extra_index(transport: pyfsr.cli.appliance.transport.Transport, url: str = PYPI_SIMPLE, *, path: str = PIP_CONF, yes: bool = False) → IndexChange[source]

Add url as an extra pip index for the connector runtime. Gated by yes.

A no-op (no yes needed, nothing run but reads) when url is already listed. Otherwise it backs the file up to <path>.bak, clears the immutable flag if set, writes, restores the flag in a finally, then re-reads the file so the result reports what is actually on disk.