Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ jobs:
box:
- centos/stream9
- centos/stream10
iop:
- enabled
exclude:
- certificate_source: installer
box: centos/stream10
Expand All @@ -64,7 +66,7 @@ jobs:
runs-on: ubuntu-24.04
env:
FOREMANCTL_BASE_BOX: ${{ matrix.box }}
name: "Tests (certificates: ${{ matrix.certificate_source }}, database: ${{ matrix.database }}, security: ${{ matrix.security }}, box: ${{ matrix.box }})"
name: "Tests (certificates: ${{ matrix.certificate_source }}, database: ${{ matrix.database }}, security: ${{ matrix.security }}, box: ${{ matrix.box }}, iop: ${{ matrix.iop }})"
steps:
- name: generate artifact suffix
run: echo "ARTIFACT_SUFFIX=$(echo '${{ matrix.certificate_source }}-${{ matrix.security }}-${{ matrix.database }}-${{ matrix.box }}' | tr -cd '[:alnum:]-')" >> "${GITHUB_ENV}"
Expand Down Expand Up @@ -120,6 +122,10 @@ jobs:
- name: Add optional features - azure-rm, google and remote-execution
run: |
./foremanctl deploy --add-feature azure-rm --add-feature google --add-feature remote-execution
- name: Enable iop
if: matrix.iop == 'enabled'
run: |
./foremanctl deploy --add-feature iop
Comment on lines +125 to +128
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calls to foremanctl deploy are expensive (adds ca 2 minutes to the execution), so I wonder if it'd be smarter to have fewer of those "add optional feature" steps and use something like {{ matrix.iop == 'enabled' && '--add-feature iop' || '' }} inside an existing step

- name: Run tests
run: |
./forge test --pytest-args="--certificate-source=${{ matrix.certificate_source }} --database-mode=${{ matrix.database }}"
Expand Down
2 changes: 1 addition & 1 deletion development/roles/foreman_installer_certs/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@

# utilize https://github.com/theforeman/foreman-installer/pull/935
- name: Generate certs
ansible.builtin.command: foreman-certs --apache true --foreman true --candlepin true
ansible.builtin.command: foreman-certs --apache true --foreman true --candlepin true --iop true
changed_when: false
10 changes: 10 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ These base features control which plugins are enabled when a feature is requeste

A deployment can have multiple base features enabled.

### Enabling IOP

IOP (Insights Operating Platform) deploys on-premise Insights services for advisor, vulnerability, and remediation. It requires internal database mode and depends on the `rh-cloud` and `katello` features.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI garbage aside, I'd prefer this be styled properly as IoP everywhere, and not IOP


```bash
./foremanctl deploy --add-feature iop
```

See [IOP Architecture](iop.md) for details on the services deployed and configuration options.

### Authenticated Registry Handling

If you need to pull images from private or authenticated container registries, you can configure registry authentication using Podman's auth file.
Expand Down
139 changes: 139 additions & 0 deletions docs/iop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# IOP (Insights Operating Platform)

IOP deploys the on-premise Insights services that provide advisor, vulnerability, and remediation capabilities integrated with Foreman.

## Enabling IOP

Add `iop` to `enabled_features` in your flavor configuration. IOP requires internal database mode (`database_mode: internal`).

The `iop` feature depends on `rh-cloud`, which installs the `foreman_rh_cloud` plugin into Foreman and `katello` as a transitive dependency.

## Architecture

IOP runs as a set of containerized services managed via podman quadlets on the `iop-core-network` (bridge, `10.130.0.0/24`). The gateway is registered as a Foreman smart proxy at `https://localhost:24443`.

```mermaid
graph TB
subgraph Host["Host System"]
Foreman["Foreman<br/>(foreman_rh_cloud)"]
Apache["Apache httpd"]
PG[(PostgreSQL)]

subgraph Network["iop-core-network (10.130.0.0/24)"]
Kafka[Kafka]

subgraph Core["Core Pipeline"]
Ingress[Ingress]
Puptoo[Puptoo]
Yuptoo[Yuptoo]
Engine[Engine]
end

Gateway["Gateway<br/>:24443"]

subgraph Services["Application Services"]
Inventory["Inventory API<br/>:8081"]
Advisor["Advisor API<br/>:8000"]
Remediation["Remediation API<br/>:3000"]
VMAAS["VMAAS<br/>(reposcan + webapp)"]
Vuln["Vulnerability<br/>(8 containers)"]
end
end

subgraph Frontends["Frontend Assets (/var/www/iop)"]
AdvisorFE[Advisor Frontend]
VulnFE[Vulnerability Frontend]
end
end

Foreman -- "smart proxy<br/>relay" --> Gateway
Gateway --> Kafka
Apache -- "Alias" --> Frontends

Ingress --> Kafka
Puptoo --> Kafka
Yuptoo --> Kafka
Engine --> Kafka

Inventory --> Kafka
Inventory --> PG
Advisor --> Kafka
Advisor --> Inventory
Advisor -. "FDW" .-> PG
Remediation --> Advisor
Remediation --> Inventory
VMAAS --> PG
VMAAS --> Gateway
Vuln --> Kafka
Vuln --> Inventory
Vuln --> VMAAS
Vuln -. "FDW" .-> PG
```

### Services

| Service | Container(s) | Port | Description |
|---------|-------------|------|-------------|
| kafka | `iop-core-kafka` | 9092 (internal) | Message broker (KRaft mode) |
| ingress | `iop-core-ingress` | 8080 (internal) | Upload ingestion endpoint |
| puptoo | `iop-core-puptoo` | - | Puppet/system facts processor |
| yuptoo | `iop-core-yuptoo` | - | Yum/package data processor |
| engine | `iop-core-engine` | - | Insights rules engine |
| gateway | `iop-core-gateway` | 127.0.0.1:24443 | nginx proxy, smart proxy relay to Foreman |
| inventory | `iop-core-host-inventory`, `iop-core-host-inventory-api` | 8081 (internal) | Host inventory with MQ consumer and REST API |
| advisor | `iop-service-advisor-backend-api`, `iop-service-advisor-backend-service` | 8000 (internal) | Advisor recommendations |
| remediation | `iop-service-remediations-api` | 3000 (host network) | Remediation playbook generation |
| vmaas | `iop-service-vmaas-reposcan`, `iop-service-vmaas-webapp-go` | - | Vulnerability metadata and advisory sync |
| vulnerability | 8 containers (manager, taskomatic, grouper, listener, evaluators, vmaas-sync) | 8443 (internal) | Vulnerability assessment pipeline |

### Frontend Assets

Advisor and vulnerability frontend assets are extracted from container images and served by Apache:

- Assets are deployed to `/var/www/iop/assets/apps/{advisor,vulnerability}`
- Apache serves them via `Alias` directives in `/etc/httpd/conf.d/05-foreman-ssl.d/`
- Assets include gzip precompression support and 1-year cache headers

### Databases

IOP creates five PostgreSQL databases, all accessible to containers via `host.containers.internal:5432`:

| Database | User |
|----------|------|
| `inventory_db` | `inventory_admin` |
| `advisor_db` | `advisor_user` |
| `remediations_db` | `remediations_user` |
| `vmaas_db` | `vmaas_admin` |
| `vulnerability_db` | `vulnerability_admin` |

Advisor and vulnerability services use PostgreSQL foreign data wrappers (FDW) to query the inventory database directly.

## Configuration

### Foreman Connection

Set in the playbook vars or inventory to match your Foreman deployment:

| Variable | Default | Description |
|----------|---------|-------------|
| `iop_core_foreman_url` | `https://{{ ansible_facts['fqdn'] }}` | Foreman server URL |
| `iop_core_foreman_admin_username` | `admin` | Foreman admin username |
| `iop_core_foreman_admin_password` | `changeme` | Foreman admin password |

### Certificates

Gateway certificates are configured per certificate source:

**Default certificates** (`certificate_source: default`):
- Server: `/root/certificates/certs/localhost.crt`
- Client: `/root/certificates/certs/localhost-client.crt`
- CA: `/root/certificates/certs/ca.crt`

**Installer certificates** (`certificate_source: installer`):
- Server: `/root/ssl-build/localhost/localhost-iop-core-gateway-server.crt`
- Client: `/root/ssl-build/localhost/localhost-iop-core-gateway-client.crt`
- CA: `/root/ssl-build/katello-default-ca.crt`

### Container Images

All IOP images default to `quay.io/iop/<service>:foreman-3.16`. Each role exposes `iop_<role>_container_image` and `iop_<role>_container_tag` variables to override.
11 changes: 11 additions & 0 deletions src/features.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,14 @@ dynflow:
internal: true
foreman_proxy:
plugin_name: dynflow
rh-cloud:
description: Connection to Red Hat Cloud
foreman:
plugin_name: foreman_rh_cloud
hammer: foreman_rh_cloud
dependencies:
- katello
iop:
description: iop services
dependencies:
- rh-cloud
18 changes: 18 additions & 0 deletions src/playbooks/deploy/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@
- "../../vars/database.yml"
- "../../vars/foreman.yml"
- "../../vars/base.yaml"
pre_tasks:
- name: Add iop databases
when:
- "'iop' in enabled_features"
- database_mode == 'internal'
block:
- name: Include iop databases
ansible.builtin.include_vars:
file: "../../vars/database_iop.yml"

- name: Combine lists
ansible.builtin.set_fact:
postgresql_databases: "{{ postgresql_databases + iop_postgresql_databases }}"
postgresql_users: "{{ postgresql_users + iop_postgresql_users }}"
roles:
- role: pre_install
- role: checks
Expand All @@ -31,6 +45,10 @@
- pulp
- foreman
- role: systemd_target
- role: iop_core
when:
- "'iop' in enabled_features"
- database_mode == 'internal'
- role: foreman_proxy
when:
- "'foreman-proxy' in enabled_features"
Expand Down
1 change: 1 addition & 0 deletions src/requirements.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
collections:
- community.general
- community.postgresql
- community.crypto
- community.general
Expand Down
9 changes: 9 additions & 0 deletions src/roles/iop_advisor/defaults/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
iop_advisor_container_image: "quay.io/iop/advisor-backend"
iop_advisor_container_tag: "foreman-3.16"

iop_advisor_database_name: advisor_db
iop_advisor_database_user: advisor_user
iop_advisor_database_password: CHANGEME
iop_advisor_database_host: host.containers.internal
iop_advisor_database_port: 5432
28 changes: 28 additions & 0 deletions src/roles/iop_advisor/handlers/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
- name: Check if advisor backend api service exists
ansible.builtin.systemd:
name: iop-service-advisor-backend-api
register: iop_advisor_api_service_status
failed_when: false
listen: restart advisor

- name: Restart advisor backend api service if it exists
ansible.builtin.systemd:
name: iop-service-advisor-backend-api
state: restarted
when: iop_advisor_api_service_status.status is defined and iop_advisor_api_service_status.status.LoadState != "not-found"
listen: restart advisor

- name: Check if advisor backend service exists
ansible.builtin.systemd:
name: iop-service-advisor-backend-service
register: iop_advisor_service_status
failed_when: false
listen: restart advisor

- name: Restart advisor backend service if it exists
ansible.builtin.systemd:
name: iop-service-advisor-backend-service
state: restarted
when: iop_advisor_service_status.status is defined and iop_advisor_service_status.status.LoadState != "not-found"
listen: restart advisor
Loading
Loading