4주차 과제 - 정지안

  • 과제: test_cache / openstack cached image [ list | queue | delete | clear ] 까지 호출되는 과정, CLI 사용법 이해하기

목차

===Step1. CLI 개념 & 환경 이해===

  1. CLI의 동작 흐름

  2. python-openstackclient 구조

  3. 환경변수와 clouds.yaml

  4. 기본 명령 실행 흐름

===Step2. 인증&세션 관리====

  1. Keystone 인증 구조

  2. 서비스 카탈로그와 엔드포인트 선택

  3. 세션 관리

  4. 보안요소

===Step3. API 요청 & 응답 구조===

  1. REST API 구조

  2. 리소스조회 명령 흐름

===Step4. 내부코드 & 플러그인 분석===

  1. python-openstackclient 코드 구조 분석

===Step5. openstack cached image 분석===

  1. openstack cached image [ list | queue | delete | clear ] 분석

===Step1. CLI 개념 & 환경 이해===

  1. CLI의 동작 흐름

    1. 사용자 입력

    2. CLI가 명령어 구조 분석 (argparse, cliff 프레임워크)

      1. openstack 입력받으면? → python-openstackclientpyproject.toml에 정의된 [project.scripts] 의 정의에 따라 openstackclient.shell:main 이 실행된다.

      2. 파일을 타고 들어가보면, main() 함수는 OpenStackShell().run(argv) 를 실행하고 있고,

      3. OpenStackShell() 클래스는 run()을 실행하지만 run()을 가지고 있지 않으며, 다만 shell.OpenStackShell 를 부모클래스로 상속받고있기때문에 부모클래스인 shellrun()이 실행된다.

      4. shell은 import 구문에 따르면 *from* osc_lib *import* shell 이므로, osc_lib를 찾아가보면

      5. 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 같은 네임스페이스 명령이 붙는다.

    3. 인증 정보 확인 (환경변수, clouds.yaml)

      OpenStackShell.initialize_app(argv) 안에서 이뤄진다.

      (osc_lib.clientmanager.ClientManager 를 구성하고, 환경변수/ cloud.yaml반영)

    4. Keystone에 인증 요청 → 토큰 발급 및 서비스카탈로그 제공

    5. 서비스 카탈로그에서 엔드포인트 선택

    6. 해당 서비스 API 호출(REST)

    7. JSON 응답 수신 → 포맷 변환 (table/json/yaml)

    8. 터미널에 출력

  2. python-openstackclient 구조

    1. python-openstackclient란?

      • OpenStack CLI의 본체

      • Python으로 작성된 명령어 프레임워크 +각 서비스 플러그인 로더

      • 단독으로는 인증/명령 해석/출력 포맷팅만 제공

      • 실제 서비스 기능(Nova, Neutron, Glance 등)은 서비스별 클라이언트 라이브러리에서 제공

    2. CLI 실행 진입점

      • 설치하면 openstack 라는 실행 파일이 path에 등록됨

      • 실제 실행 파일은 Python entry point로 등록됨 (setup.cfg 혹은 setup.py 혹은 pyproject.toml 에 있는데, 현재 python-openstackclient는 project.toml에서 확인할 수 있었다.

        #project.toml
        [project.scripts]
        openstack = "openstackclient.shell:main"
        
        
  3. 환경변수와 clouds.yaml

    1. openrc를 통한 export

    2. clouds.yaml방식

      1. 사용자 홈디렉토리: ~/.config/openstack/clouds.yaml

      2. 시스템 전역: /etc/openstack/clouds.yaml

    사용방법

    1. openstack --os-cloud mylab server list

    2. OS_CLOUD지정

      export OS_CLOUD=mylab
      openstack server list
      
      
  4. 기본 명령 실행 흐름

    1. CLI가 osc_lib.clientmanager.ClientManager 생성

    2. 내부에서 keystoneauth1.loading 모듈을 사용하여 Auth Plugin 로드

    3. Auth Plugin이 받은 값

      • auth_url

      • username / password (혹은 application credential, token)

      • project_name / domain_name

    4. 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"}
            }
          }
        }
      }
      
      
      
    5. 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>"
                }
              ]
            },
            ...
          ]
        }
      }
      
      
      
    6. 서비스 카탈로그 처리

      • catalog 배열 안에 Keystone이 제공하는 모든 서비스 엔드포인트가 담겨 있음.

      • CLI는

        • service_type (compute/image/network/volume 등)

        • interface (public/internal/admin)

        • region_name

        을 기준으로 맞는 URL 선택

        예: novahttps://nova.example.com/v2.1

    7. 실제 서비스 API호출

    8. 출력 포맷을 JSON에서 cliff의 formatter를 통해 table,json,yaml 등으로 변환 후 터미널 출력

===Step2. 인증&세션 관리====

  1. Keystone 인증 흐름

    1. 인증 방식 결정

      • password / token / application credential / federated login 등
    2. 스코프 결정

      • project scope

      • domain scoped

      • unscoped

    3. Keystone이 인증 성공시 X-Subject-Token 헤더 발급

    4. 토큰 안에 서비스 카탈로그 포함

  2. 서비스 카탈로그 엔드포인트 선택

    엔드포인트 선택 규칙

    • 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"
      )
      
      
      
    • 선택 로직

      1. 카탈로그에서 service_type 필터

      2. region_name 필터

      3. interface 필터

      4. 일치항목 URL 반환

  3. 세션 관리

    OpenStack CLI의 세션 관리는 keystoneauth1.session.Session 이 관리한다.

    1. 세션의 역할

      • 토큰 캐싱: 한 번 인증하면 재사용

      • 엔드포인트 선택: get_endpoint() 메서드

      • HTTP 요청 래핑

        • 자동으로 X-Auth-Token 헤더 추가

        • TLS 검증, 인증서 지정

        • 리트라이, 타임아웃 제어

    2. CLI에서 세션 생성 흐름

      1. osc_lib.clientmanager.ClientManager가 인증정보(Auth Plugin)와 세션 생성

      2. 세션이 Keystone 인증 후 토큰 + 카탈로그 저장

      3. 이후 모든 서비스 클라이언트(Nova, Glance, Neutron)는 세션을 공유해서 API 호출

  4. 보안 요소

    1. 토큰 보안

      • 유효기간: 보통 수분~수시간

      • 재발급: 세션이 만료되면 재인증

    2. 자격 증명 보호

      • 환경변수 : 편하지만 비밀번호 노출 위험

      • clouds.yaml: 파일접근권한 600 필수

      • application credential

        • 프로젝트에 발급되는 제한된 권한의 인증키

        • 비밀번호 대신 안전하게 사용 가능

    3. API 통신 보호

      • HTTPS/TLS 권장

      • 사설 CA환경이면 --os-cacert 옵션으로 신뢰 루트 지정

      • 인터페이스 선택에서 internal/admin은 외부 노출 방지용

===Step3. API 요청 & 응답 구조===

  1. 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는 바이너리/파일 응답 가능(이미지 다운로드 등)

  2. 리소스조회 명령 흐름

    예를들어 openstack server list 가 입력되면, 앞선 osc_lib.app.App.run()이 ClientManager까지 호출하여

    1. cliff가 server list 명령을 ListServer 클래스와 매핑

    2. ClientManager.compute 클라이언트 생성

    3. API 호출 준비

      1. URL, 메서드, 쿼리파라미터 등
    4. 세션을 통해 호출

    5. 응답 처리

    6. 출력 포맷 변환

    7. 터미널 출력

===Step4. 내부코드 & 플러그인 분석===

  1. 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 있을 수도)
    
    
    
    1. 진입점과 앱 초기화

      • pyproject.toml 에서 shell.py의 main 호출 이후,

      • OpenStackShell 클래스가 initialize_app(argv) 를 통해 인증/세션/ClientManager를 준비하고

      • CommandManager 생성 및 로딩을 한다.

    2. 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 분석===

    1. 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은 아래와 같이 찾을 수 있다.