# 4주차 과제 - 호세헌

**URL:** <https://forum.openinfra-kr.org/t/topic/192>\
**Category:** 컨트리뷰션\
**Tags:** 2025컨트리뷰션, 컨트리뷰션\
**Created:** [8월 9, 2025, 5:58오전 UTC](https://forum.openinfra-kr.org/t/topic/192 "2025-08-09T05:58:49Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![seheon](https://forum.openinfra-kr.org/letter_avatar_proxy/v4/letter/s/a9a28c/32.png) [@seheon](https://forum.openinfra-kr.org/u/seheon)\
**Post date:** [8월 9, 2025, 5:58오전 UTC](https://forum.openinfra-kr.org/t/topic/192/1 "2025-08-09T05:58:49Z")

</div>

# 필수 과제

> 이번 3주차 과제는 아직 미구현된 functional test를 구현하는게 과제입니다.
> 
> 이미 많이 쓰이고 있는 CLI지만 아직 functional test가 없는게 많습니다!
> 
> **[필수 과제]**
> 
> 1. 아래 게시글 참고하여 functional test를 구현할 openstack cli 선택하기 ( 본문에 이름 없으신분들은 댓글로 어떤 CLI 할지 댓글 남겨주세요)
> 
> 2. CLI 사용법 정리 하기 `( 먼저 진행 )`
> 
> 3. CLI에 대한 functional test 코드 구현하기 **( 추후에 공지 후 진행 )**

## v2/test\_volume\_host / openstack volume host set

### 참고자료

[https://docs.openstack.org/python-openstackclient/pike/cli/command-objects/volume-host.html](https://docs.openstack.org/python-openstackclient/pike/cli/command-objects/volume-host.html)

### openstack volume host set란?

`openstack volume host set`은 cinder-volume 호스트를 동결(Freeze)하여 새 볼륨 작업 수락을 중단하거나, 해제(Thaw)하여 다시 수락하도록 허용하는 관리자용 명령어입니다.

```auto
openstack volume host set
    [--enable | --disable]
    <host-name>

```

- `--enable` : 지정한 볼륨 호스트를 동결 해제(Thaw)하고 새 볼륨 작업 수락을 활성화

- `--disable` : 지정한 볼륨 호스트를 동결(Freeze)하고 새 볼륨 작업 수락을 비활성화

- `<host-name>` : 볼륨 호스트 이름

## 코드 분석

### 1. **CLI 입력 → main 진입**

`openstack volume host set --enable <host-name>` 입력 시의 진입 흐름은

이전 2주 차 과제에서 분석한 `main()` 실행 구조와 동일합니다.

[2주차 과제 - 호세헌](https://forum.openinfra-kr.org/t/topic/140)

해당 명령은

`python-openstackclient/openstackclient/volume/v2/volume_host.py`에 정의된

`SetVolumeHost` 클래스가 처리합니다.

```auto
class SetVolumeHost(command.Command):
    _description = _("Set volume host properties")

    def get_parser(self, prog_name):
        parser = super().get_parser(prog_name)
        parser.add_argument(
            "host", metavar="<host-name>", help=_("Name of volume host")
        )
        enabled_group = parser.add_mutually_exclusive_group()
        enabled_group.add_argument(
            "--disable",
            action="store_true",
            help=_("Freeze and disable the specified volume host"),
        )
        enabled_group.add_argument(
            "--enable",
            action="store_true",
            help=_("Thaw and enable the specified volume host"),
        )
        return parser

    def take_action(self, parsed_args):
        service_client = self.app.client_manager.volume
        if parsed_args.enable:
            service_client.services.thaw_host(parsed_args.host)
        if parsed_args.disable:
            service_client.services.freeze_host(parsed_args.host)

```

### 2. **SetVolumeHost.get\_parser() 동작**

사용자가 `openstack volume host set --enable <host-name>`처럼 명령을 입력하면,

우선 `SetVolumeHost.get_parser()` 메서드가 호출되어 인자를 해석합니다.

- host는 필수 인자 `--enable`, `--disable` 두 옵션을 `상호 배타 옵션 그룹`으로 묶음 (두 옵션이 동시에 호출되지 않도록)

```auto
def get_parser(self, prog_name):
        parser = super().get_parser(prog_name)
        parser.add_argument(
            "host", metavar="<host-name>", help=_("Name of volume host")
        )
        enabled_group = parser.add_mutually_exclusive_group()
        enabled_group.add_argument(
            "--disable",
            action="store_true",
            help=_("Freeze and disable the specified volume host"),
        )
        enabled_group.add_argument(
            "--enable",
            action="store_true",
            help=_("Thaw and enable the specified volume host"),
        )
        return parser

```

### **3. SetVolumeHost.take\_action() 실행**

```auto
  def take_action(self, parsed_args):
        service_client = self.app.client_manager.volume
        if parsed_args.enable:
            service_client.services.thaw_host(parsed_args.host)
        if parsed_args.disable:
            service_client.services.freeze_host(parsed_args.host)

```

인자 파싱이 끝나면 `SetVolumeHost.take_action()`이 실행됩니다.

먼저 `self.app.client_manager.volume`을 통해 **cinderclient 인스턴스** 를 가져오고 옵션에 따라 처리합니다.

- `--enable` : `thaw_host(<host-name>)`를 호출하여 호스트를 동결 해제하고 작업 권한 활성화

- `--disable` : `freeze_host(<host-name>)`를 호출해 호스트를 동결시키고 새로운 작업 권한 비활성화

### 4. **cinderclient 호출 흐름**

`service_client.services`는 내부적으로 `cinderclient.v2.services.ServiceManager` 객체를 참조합니다. 여기서 각 메서드(`thaw_host`, `freeze_host`)는 Cinder REST API를 직접 호출합니다.

`PUT /os-services/{action}`

- `--enable` → `PUT /os-services/thaw`

- `--disable` → `PUT /os-services/freeze`

### **5. Cinder API 동작**

- `thaw_host`: 호스트 동결 해제 + 작업 수락 활성화

- `freeze_host`: 호스트 동결 + 작업 수락 비활성화

실제 동작은 `OpenStackClient`가 직접 수행하는 것이 아니라, `Cinder 서비스 API`가 처리합니다. OpenStackClient는 `cinderclient` 라이브러리를 호출해 API 요청을 전달하는 **클라이언트 래퍼(Client Wrapper)** 역할을 합니다.

`메서드명`과 `API`는 1:1로 대응하며,

`thaw_host` ↔ Thaw(+Enable), `freeze_host` ↔ Freeze(+Disable)로 매핑됩니다.
