# 실제 Pulp 연동 가이드

이 콘솔은 **BFF**로서 실제 **Pulp 3** 서버의 REST API(`/pulp/api/v3/`)에 붙어 동작한다.
지금까지 본 화면은 `PULP_DEMO=true`(가짜 인메모리 데이터)였고, **실연동하려면 Pulp 서버 +
환경변수**가 필요하다. 이 문서는 그 절차와, 실서버에서 흔히 보정이 필요한 지점을 정리한다.

---

## 0. 준비물

- **Pulp 3 서버** (RPM 플러그인 `pulp_rpm` 설치; DEB면 `pulp_deb`)
- Pulp **admin 계정**(또는 API 권한 계정) — 사용자/비밀번호
- 콘솔이 Pulp 주소에 **네트워크 도달 가능**할 것
- (선택) **Postgres** — 배포 감사 로그(`deploy_audit`) 저장용 `DATABASE_URL`
- 사내 HTTPS Pulp면 **사내 CA(.pem)** 또는 검증 끄기 옵션

---

## 1. (테스트용) Pulp 서버 빠르게 띄우기

실서버가 없으면 컨테이너로 올인원 Pulp를 띄워 테스트할 수 있다(podman/docker 동일).

```bash
mkdir -p ~/pulp/{settings,pgsql,storage}
podman run -d --name pulp -p 8080:80 \
  -v ~/pulp/settings:/etc/pulp \
  -v ~/pulp/pgsql:/var/lib/pgsql \
  -v ~/pulp/storage:/var/lib/pulp \
  docker.io/pulp/pulp

# 기동까지 1~2분. admin 비밀번호 설정:
podman exec -it pulp pulpcore-manager reset-admin-password
```

- API 주소: `http://localhost:8080/pulp/api/v3/`
- 상태 확인: `curl -u admin:<pw> http://localhost:8080/pulp/api/v3/status/`

> 폐쇄망 운영 Pulp는 인프라팀이 구축한 주소/계정을 그대로 쓰면 된다(위 컨테이너는 개발 검증용).

---

## 2. 화면에 보일 콘텐츠 만들기 (Remote → Repository → Distribution)

대시보드에 저장소가 보이려면 Pulp에 **Repository**가 있어야 하고, 동기화하려면 **Remote**가,
배포하려면 **Distribution**이 있어야 한다. `pulp` CLI(`pip install pulp-cli`)로 RPM 예시:

```bash
# pulp CLI 설정 (한 번)
pulp config create --base-url http://localhost:8080 --username admin --password <pw>

# 1) Remote (외부 미러 소스 정의) — 검증을 켜려면 gpgkey/tls_validation 설정
pulp rpm remote create --name rocky9-baseos \
  --url https://dl.rockylinux.org/pub/rocky/9/BaseOS/x86_64/os/

# 2) Repository (그릇) + remote 연결
pulp rpm repository create --name rocky9-baseos --remote rocky9-baseos \
  --autopublish      # 동기화 후 자동 publication (배포 단계 단순화에 도움)

# 3) (콘솔에서 동기화해도 되고) CLI 동기화로 첫 스냅샷 생성
pulp rpm repository sync --name rocky9-baseos

# 4) Distribution (운영이 보는 공개 URL) — 배포 확정이 PATCH 할 대상
pulp rpm distribution create --name rocky9-baseos \
  --base-path rocky9-baseos --repository rocky9-baseos
```

- 이렇게 하면 콘솔 대시보드에 `rocky9-baseos`가 뜨고, **동기화/버전 목록/배포 확정**을 UI에서 시험할 수 있다.
- **배포 확정**은 Distribution을 특정 publication으로 교체하므로, distribution이 미리 있어야 한다.
  `--autopublish` + distribution을 repository에 연결해두면 우리 콘솔의 역추적(publication→version)이 잘 맞는다.

---

## 3. 콘솔 환경변수 설정

`.env`(루트, git 미추적) 또는 실행 환경에 설정. **`PULP_DEMO`는 빼거나 false.**

```bash
PULP_BASE_URL=http://localhost:8080        # 실제 Pulp 주소
PULP_USERNAME=admin
PULP_PASSWORD=********                      # 비밀번호 (커밋 금지)
PULP_VERIFY_TLS=true                        # 사내 HTTPS+CA면 PULP_CA_FILE 사용
PULP_CA_FILE=/path/boknet-ca.pem            # 사내 self-signed CA 경로(있을 때만)
DATABASE_URL=postgresql://...               # 배포 감사 로그용(없으면 배포는 되나 기록 실패 경고)
# PULP_DEMO 미설정
```

> 비밀번호/`DATABASE_URL`은 코드/깃에 두지 않는다. Coolify 배포 시엔 Environment Variables에 넣는다.

---

## 4. 실행 & 확인

```bash
.venv/Scripts/python.exe -m uvicorn app.main:app --reload    # Windows
```

| 확인 | 기대 |
|---|---|
| `GET /healthz` | `{"ok": true}` (앱 생존, Pulp와 무관) |
| `GET /pulp-status` | 🟢 "Pulp 연결됨" (실패 시 사유 표시) |
| 대시보드 `/` | 실제 저장소 목록·검증 배지·패키지 수 |
| 동기화 버튼 | sync task 시작 → 진행률 폴링 → 새 버전 |
| 버전 페이지 | 스냅샷 목록 + 현재 배포 버전 배지 |
| 배포 확정 | publication 생성 → distribution 교체 → 감사 로그 |

---

## 5. 실서버 첫 연동 시 보정 체크리스트

스펙/일반적 Pulp 구조 기준으로 구현했으므로, 실제 응답 형태에 따라 아래가 안 맞을 수 있다.
각 항목이 이상하면 해당 코드를 실제 JSON에 맞춰 조정한다.

| 증상 | 확인할 Pulp 필드 | 고칠 곳 |
|---|---|---|
| 검증 배지가 항상 ⚪/⚠️ | `repository.repo_config`의 `gpgcheck` / `repo-gpgcheck` 키 형태 | `app/views.py` `gpg_status()` |
| 패키지 수·증감이 0 | `version.content_summary.present/added/removed` 구조 | `app/views.py` `_content_count()` |
| "현재 배포 버전" 배지가 안 뜸 | `distribution.publication` 유무 / `publication.repository_version` 경로, 또는 distribution이 `repository` 직접 배포(최신 추종) | `app/routes/versions.py` `_deployed_version_number()`, `app/routes/deploy.py` `_distribution_for_repo()` |
| 동기화 진행률/완료 안 잡힘 | task의 `progress_reports[]`, `created_resources[]`, `state` | `app/views.py` `task_progress()` |
| 배포가 distribution을 못 찾음 | repo↔distribution 매핑 규칙 | `app/routes/deploy.py` `_distribution_for_repo()` |

> 실서버 응답을 한 번 떠보면 빠르다: `curl -u admin:<pw> http://<pulp>/pulp/api/v3/repositories/rpm/rpm/ | jq`.

---

## 6. 트러블슈팅

- **`/pulp-status` 연결 실패** → 주소/포트/방화벽, HTTPS면 CA(`PULP_CA_FILE`) 또는 임시로 `PULP_VERIFY_TLS=false`.
- **401 Unauthorized** → `PULP_USERNAME`/`PULP_PASSWORD` 확인.
- **대시보드가 비어 있음** → Pulp에 Repository가 없거나 RPM 플러그인 미설치. §2로 콘텐츠 생성.
- **배포 버튼 비활성** → 해당 저장소가 검증(pass) 상태가 아님(= remote에 gpgkey/tls_validation 미설정 → `repo_config`에 gpgcheck 없음). 의도된 안전장치.
- **"감사 로그 기록 실패"** → `DATABASE_URL` 미설정/접속 불가. 배포 자체는 성공.

---

## 7. DEB(Ubuntu/Debian) 저장소

현재 라우트는 RPM(`/repositories/rpm/rpm/` 등) 경로에 맞춰져 있다. DEB는 `rpm/rpm` 자리를
`deb/apt`로 바꾸면 된다 — `app/pulp_client.py`의 경로를 콘텐츠 타입으로 파라미터화하면 양쪽을
지원할 수 있다(1차 MVP는 RPM 집중).
