- 과제: test_cache /
openstack cached image [ list | queue | delete | clear ]까지 호출되는 과정, CLI 사용법 이해하기
목차
===Step1. CLI 개념 & 환경 이해===
CLI의 동작 흐름
python-openstackclient 구조
환경변수와 clouds.yaml
기본 명령 실행 흐름
===Step2. 인증&세션 관리====
Keystone 인증 구조
서비스 카탈로그와 엔드포인트 선택
세션 관리
보안요소
===Step3. API 요청 & 응답 구조===
REST API 구조
리소스조회 명령 흐름
===Step4. 내부코드 & 플러그인 분석===
- python-openstackclient 코드 구조 분석
===Step5.
openstack cached image분석===
openstack cached image [ list | queue | delete | clear ]분석
===Step1. CLI 개념 & 환경 이해===
-
CLI의 동작 흐름
-
사용자 입력
-
CLI가 명령어 구조 분석 (argparse, cliff 프레임워크)
-
openstack입력받으면? →python-openstackclient의pyproject.toml에 정의된[project.scripts]의 정의에 따라openstackclient.shell:main이 실행된다. -
파일을 타고 들어가보면,
main()함수는OpenStackShell().run(argv)를 실행하고 있고, -
OpenStackShell()클래스는run()을 실행하지만run()을 가지고 있지 않으며, 다만shell.OpenStackShell를 부모클래스로 상속받고있기때문에 부모클래스인shell의run()이 실행된다. -
shell은 import 구문에 따르면
*from* osc_lib *import* shell이므로,osc_lib를 찾아가보면 -
osc_lib.shell.run()은app.App.run을 실행하는 구조임을 알 수 있었다.super().run(argv)는 app.App.run(argv)이고,
from cliff import app 이므로
cliff.app.App.run(argv)를 결론적으로 호출하게 된다.-
cliff는 명령파싱(
argparse사용)과 서브커맨드 매핑을 담당한다. -
cliff.commandmanager.CommandManager를 통해server list같은 커맨드 클래스가 바인딩된다.
그리고 플러그인 로딩이 일어나는데,
-
osc_lib.shell.OpenStackShell은 초기화 과정에서 CommandManager를 만들고, -
stevedore entry point(예:
openstack.cli.base)를 통해 서비스 플러그인들을 로드한다. -
각 서비스/버전 그룹(
openstack.compute.v2등)에서 실제 명령들 로딩 -
키 이름 server_list → cli로 표시 “server list” 등…
-
이 덕분에
server,image,network같은 네임스페이스 명령이 붙는다.
-
-
-
인증 정보 확인 (환경변수, clouds.yaml)
OpenStackShell.initialize_app(argv)안에서 이뤄진다.(
osc_lib.clientmanager.ClientManager를 구성하고, 환경변수/cloud.yaml반영) -
Keystone에 인증 요청 → 토큰 발급 및 서비스카탈로그 제공
-
서비스 카탈로그에서 엔드포인트 선택
-
해당 서비스 API 호출(REST)
-
JSON 응답 수신 → 포맷 변환 (table/json/yaml)
-
터미널에 출력
-
-
python-openstackclient 구조
-
python-openstackclient란?
-
OpenStack CLI의 본체
-
Python으로 작성된 명령어 프레임워크 +각 서비스 플러그인 로더
-
단독으로는 인증/명령 해석/출력 포맷팅만 제공
-
실제 서비스 기능(Nova, Neutron, Glance 등)은 서비스별 클라이언트 라이브러리에서 제공
-
-
CLI 실행 진입점
-
설치하면
openstack라는 실행 파일이 path에 등록됨 -
실제 실행 파일은 Python entry point로 등록됨 (
setup.cfg혹은setup.py혹은pyproject.toml에 있는데, 현재 python-openstackclient는 project.toml에서 확인할 수 있었다.#project.toml [project.scripts] openstack = "openstackclient.shell:main"
-
-
-
환경변수와 clouds.yaml
-
openrc를 통한 export
-
clouds.yaml방식
-
사용자 홈디렉토리:
~/.config/openstack/clouds.yaml -
시스템 전역:
/etc/openstack/clouds.yaml
-
사용방법
-
openstack --os-cloud mylab server list
-
OS_CLOUD지정
export OS_CLOUD=mylab openstack server list
-
-
기본 명령 실행 흐름
-
CLI가
osc_lib.clientmanager.ClientManager생성 -
내부에서
keystoneauth1.loading모듈을 사용하여 Auth Plugin 로드 -
Auth Plugin이 받은 값
-
auth_url -
username/password(혹은 application credential, token) -
project_name/domain_name
-
-
Keystone API 호출
POST /v3/auth/tokens Content-Type: application/json { "auth": { "identity": { "methods": ["password"], "password": { "user": { "name": "demo", "domain": {"name": "Default"}, "password": "secret" } } }, "scope": { "project": { "name": "demo", "domain": {"name": "Default"} } } } } -
Keystone 응답
HTTP/1.1 201 Created X-Subject-Token: gAAAAABl... Content-Type: application/json { "token": { "methods": ["password"], "expires_at": "2025-08-12T12:34:56.000000Z", "project": { "id": "12345", "name": "demo" }, "catalog": [ { "name": "nova", "type": "compute", "endpoints": [ { "interface": "public", "region": "RegionOne", "url": "<https://nova.example.com/v2.1>" } ] }, ... ] } } -
서비스 카탈로그 처리
-
catalog배열 안에 Keystone이 제공하는 모든 서비스 엔드포인트가 담겨 있음. -
CLI는
-
service_type(compute/image/network/volume 등) -
interface(public/internal/admin) -
region_name
을 기준으로 맞는 URL 선택
예:
nova→https://nova.example.com/v2.1 -
-
-
실제 서비스 API호출
-
출력 포맷을 JSON에서 cliff의 formatter를 통해 table,json,yaml 등으로 변환 후 터미널 출력
-
===Step2. 인증&세션 관리====
-
Keystone 인증 흐름
-
인증 방식 결정
- password / token / application credential / federated login 등
-
스코프 결정
-
project scope
-
domain scoped
-
unscoped
-
-
Keystone이 인증 성공시
X-Subject-Token헤더 발급 -
토큰 안에 서비스 카탈로그 포함
-
-
서비스 카탈로그 엔드포인트 선택
엔드포인트 선택 규칙
-
CLI 옵션 또는 환경 변수
-
--os-interface/OS_INTERFACE(public/internal/admin) -
--os-region-name/OS_REGION_NAME
-
-
SDK(keystoneauth1.session.Session)에서
session.get_endpoint( service_type="compute", interface="public", region_name="RegionOne" ) -
선택 로직
-
카탈로그에서
service_type필터 -
region_name필터 -
interface필터 -
일치항목 URL 반환
-
-
-
세션 관리
OpenStack CLI의 세션 관리는
keystoneauth1.session.Session이 관리한다.-
세션의 역할
-
토큰 캐싱: 한 번 인증하면 재사용
-
엔드포인트 선택:
get_endpoint()메서드 -
HTTP 요청 래핑
-
자동으로
X-Auth-Token헤더 추가 -
TLS 검증, 인증서 지정
-
리트라이, 타임아웃 제어
-
-
-
CLI에서 세션 생성 흐름
-
osc_lib.clientmanager.ClientManager가 인증정보(Auth Plugin)와 세션 생성 -
세션이 Keystone 인증 후 토큰 + 카탈로그 저장
-
이후 모든 서비스 클라이언트(Nova, Glance, Neutron)는 세션을 공유해서 API 호출
-
-
-
보안 요소
-
토큰 보안
-
유효기간: 보통 수분~수시간
-
재발급: 세션이 만료되면 재인증
-
-
자격 증명 보호
-
환경변수 : 편하지만 비밀번호 노출 위험
-
clouds.yaml: 파일접근권한 600 필수
-
application credential
-
프로젝트에 발급되는 제한된 권한의 인증키
-
비밀번호 대신 안전하게 사용 가능
-
-
-
API 통신 보호
-
HTTPS/TLS 권장
-
사설 CA환경이면
--os-cacert옵션으로 신뢰 루트 지정 -
인터페이스 선택에서 internal/admin은 외부 노출 방지용
-
-
===Step3. API 요청 & 응답 구조===
-
REST API 구조
OpenStack 서비슫르은 모두 HTTP REST API 기반!
-
URL 패턴
https://<endpoint>/<version>/<resource>/<id> # 예: `https://nova.example.com/v2.1/{project_id}/servers` -
인증 :
X-Auth-Token헤더 필수 -
응답 형식
-
기본 JOSN
-
일부 API는 바이너리/파일 응답 가능(이미지 다운로드 등)
-
-
-
리소스조회 명령 흐름
예를들어
openstack server list가 입력되면, 앞선 osc_lib.app.App.run()이 ClientManager까지 호출하여-
cliff가
server list명령을ListServer클래스와 매핑 -
ClientManager.compute클라이언트 생성 -
API 호출 준비
- URL, 메서드, 쿼리파라미터 등
-
세션을 통해 호출
-
응답 처리
-
출력 포맷 변환
-
터미널 출력
-
===Step4. 내부코드 & 플러그인 분석===
-
python-openstackclient 코드 구조 분석
python-openstackclient/ │ ├─ openstackclient/ # CLI 메인 패키지 │ ├─ shell.py # 진입점(main), OpenStackShell 정의 │ ├─ __init__.py │ │ │ ├─ common/ # 모든 서비스에서 공용으로 쓰는 커맨드/유틸 │ │ ├─ availability_zone.py # AZ 조회 같은 공통 리소스 │ │ ├─ configuration.py # OSC/SDK/라이브러리 설정 확인 │ │ ├─ extension.py # 확장 목록 조회(플러그인 가시화) │ │ ├─ limits.py # 공통 limit(쿼터 상한 등) 표시 │ │ ├─ module.py # 로드된 모듈/커맨드 나열(디버깅에 유용) │ │ ├─ project_cleanup.py # 대량 정리 워크플로(보조 커맨드) │ │ ├─ quota.py # 공통 쿼터 조회/설정(서비스별 위임 포함) │ │ ├─ versions.py # 서비스 버전 가시화(엔드포인트별) │ │ └─ ... │ │ │ ├─ compute/ # Nova │ │ ├─ __init__.py │ │ └─ v2/ │ │ ├─ server.py # server list/show/create 등 핵심 │ │ ├─ flavor.py # flavor 목록/생성/삭제 │ │ ├─ keypair.py # 키페어 관리 │ │ ├─ hypervisor.py # 하이퍼바이저 정보 │ │ ├─ host.py, usage.py ... # 기타 컴퓨트 리소스 │ │ │ ├─ identity/ # Keystone │ │ ├─ v2_0/ # 레거시 v2.0 지원(남아있을 수 있음) │ │ └─ v3/ # 표준 v3 (도메인/프로젝트/사용자/토큰 등) │ │ ├─ user.py, project.py, │ │ ├─ role.py, domain.py, │ │ └─ token.py, endpoint.py ... │ │ │ ├─ image/ # Glance │ │ ├─ v1/ # v1(과거 호환) │ │ └─ v2/ # v2(현행): image.py, cache.py, metadef_*.py ... │ │ │ ├─ network/ # Neutron │ │ └─ v2/ │ │ ├─ network.py, port.py, router.py, │ │ ├─ security_group*.py, floating_ip*.py, │ │ └─ trunk.py, qos_*.py, segment*.py ... │ │ │ ├─ object/ # Swift │ │ └─ v1/ (account/container/object 단위) │ │ │ ├─ volume/ # Cinder( │ │ ├─ v2/ # 일부 배포에서 여전히 사용 │ │ └─ v3/ # 현행: volume/backup/snapshot/type/cluster 등 │ │ │ └─ tests/ # 단위 테스트 (커맨드 파서/액션/출력 포맷 검증) │ ├─ pyproject.toml # 엔트리포인트/메타데이터(콘솔 스크립트 & 커맨드 등록) ├─ README.rst └─ (setup.cfg/setup.py 있을 수도)-
진입점과 앱 초기화
-
pyproject.toml에서 shell.py의 main 호출 이후, -
OpenStackShell클래스가initialize_app(argv)를 통해 인증/세션/ClientManager를 준비하고 -
CommandManager생성 및 로딩을 한다.
-
-
cliff
커맨드 클래스의 공통 베이스.
-
cliff가제공하는 3형제 베이스를 주로 상속받는다.
-
Command: 액션만 하는 단순 커맨드(출력 자유) -
Lister: 표 형태(헤더,행들) 반환 -
ShowOne: 단일 리소스 Key-Value 출력
-
-
각 커맨드 클래스는
-
get_parser(self, prog_name): 옵션 정의 -
take_action(self, parsed_args): 실제 동작 구현 -
(Lister,ShowOne의 경우 return 형식이 정해짐)
-
Lister: (columns, data_iterable)
-
ShowOne: (columns, data_row)
-
-
-
===Step5.
openstack cached image분석===-
openstack cached image [ list | queue | delete | clear ]분석위 정리를 기반으로 접근하면,
openstack cached image [ list | queue | delete | clear ]를 입력하면→ cliff가 “cached image list” 파싱
→ CommandManager가 엔트리포인트(stevedore)에서 매핑을 찾고,
→ pyproject.tomal에서는 실제로
[project.entry-points."openstack.image.v2"] ... ... cached_image_list = "openstackclient.image.v2.cache:ListCachedImage" cached_image_queue = "openstackclient.image.v2.cache:QueueCachedImage" cached_image_delete = "openstackclient.image.v2.cache:DeleteCachedImage" cached_image_clear = "openstackclient.image.v2.cache:ClearCachedImage"처럼 구성되어 있는 것을 확인할 수 있다.
→ 따라서 아래 클래스로 인스턴스가 생성되고,
-
ListCachedImage
-
QueueCachedImage
-
DeleteCachedImage
-
ClearCachedImage
→
get_parser()로 옵션이 파싱되고→
take_action()에서 실제 동작-
self.app.client_manager.image를 통해 이미지 클라이언트 획득
-
Glance v2 “image cache” 관리 API 호출
→ 응답/결과를 cliff 포맷터로 출력하게 된다.
-
실제 get_parser와 take_action은 아래와 같이 찾을 수 있다.
-
ListCachedImage
-
QueueCachedImage
-
DeleteCachedImage
-
ClearCachedImage
-




