diff --git a/README.md b/README.md index 747781d..bf0272e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ConoHa CLI -[ConoHa API](https://www.conoha.jp/docs/) を CLI で良しなに扱うための何か。 +[ConoHa VPS Ver.3.0 の公開 API](https://doc.conoha.jp/reference/api-vps3/) を CLI で良しなに扱うための何か。 自分が使うために作ったものなので、使わない機能は実装していません。 @@ -11,28 +11,30 @@ ```json { "endpoint": { - "identity": "https://identity.tyo1.conoha.io/v2.0", - "compute": "https://compute.tyo1.conoha.io/v2/{tenant_id}", - "network": "https://networking.tyo1.conoha.io/v2.0" + "identity": "https://identity.c3j1.conoha.io/v3", + "compute": "https://compute.c3j1.conoha.io/v2.1", + "network": "https://networking.c3j1.conoha.io/v2.0", + "image": "https://image-service.c3j1.conoha.io/v2", + "volume": "https://block-storage.c3j1.conoha.io/v3/{テナントID}" } } ``` エンドポイントの設定をここに記述します。 ConoHa のコンソール画面に表示されているものを使って作成してください。 -`identity`, `compute`, `network` の3つが必要です。 +`identity`, `compute`, `network`, `image`, `volume` が必要です。 ### `~/.conoha/credential.json` ```json { "user_name": "{user_name}", - "password": "{password}", - "tenant_id": "{tenant_id}" + "tenant_name": "{tenant_name}", + "password": "{password}" } ``` -API ユーザのユーザ名・パスワードとテナント ID をここに記述します。 +API ユーザのユーザ名、テナント名、パスワードをここに記述します。 ファイルが無ければ `conoha auth login` コマンド実行時に入力を求められます。 入力された内容は `credential.json` に保存されます。 diff --git a/conoha/api/compute.py b/conoha/api/compute.py index 04a0d89..692b442 100644 --- a/conoha/api/compute.py +++ b/conoha/api/compute.py @@ -1,80 +1,49 @@ -""" -Compute API の呼び出し部分 -""" - import base64 from conoha import config from conoha.util import http endpoint = config.get_config()["endpoint"]["compute"] +token = config.get_token() def list_flavors(): - """ - https://www.conoha.jp/docs/compute-get_flavors_list.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/flavors", headers) -########################################################################### - - -def list_images(): - """ - https://www.conoha.jp/docs/compute-get_images_list.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} - return http.get(f"{endpoint}/images", headers) - - -########################################################################### - - def list_servers(): - """ - 通常: https://www.conoha.jp/docs/compute-get_vms_list.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/servers", headers) def list_servers_detail(): - """ - 詳細表示: https://www.conoha.jp/docs/compute-get_vms_detail.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/servers/detail", headers) def describe_server(server_id): - """ - https://www.conoha.jp/docs/compute-get_vms_detail_specified.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/servers/{server_id}", headers) def create_server( - image_ref, + volume_id, flavor_ref, admin_pass=None, key_name=None, security_groups=None, instance_name_tag=None, - volume_id=None, - vnc_keymap=None, user_data=None, ): - """ - https://www.conoha.jp/docs/compute-create_vm.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} - + headers = {"Accept": "application/json", "X-Auth-Token": token} # 必須項目 - data = {"server": {"imageRef": image_ref, "flavorRef": flavor_ref}} - + data = { + "server": { + "block_device_mapping_v2": [{"uuid": volume_id}], + "flavorRef": flavor_ref, + } + } # Optional 項目 if admin_pass is not None: data["server"]["adminPass"] = admin_pass @@ -86,10 +55,6 @@ def create_server( data["server"]["security_groups"].append({"name": security_group}) if instance_name_tag is not None: data["server"]["metadata"] = {"instance_name_tag": instance_name_tag} - if volume_id is not None: - data["server"]["block_device_mapping"] = {"volume_id": volume_id} - if vnc_keymap is not None: - data["server"]["vncKeymap"] = vnc_keymap if user_data is not None: # 生の文字列を BASE64 エンコードに変換する data["server"]["user_data"] = base64.b64encode( @@ -99,59 +64,37 @@ def create_server( def start_server(server_id): - """ - https://www.conoha.jp/docs/compute-power_on_vm.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} data = {"os-start": None} return http.post(f"{endpoint}/servers/{server_id}/action", data, headers) def stop_server(server_id, force): - """ - 通常停止: https://www.conoha.jp/docs/compute-stop_cleanly_vm.php - 強制停止: https://www.conoha.jp/docs/compute-stop_forcibly_vm.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} data = {"os-stop": None} if force: - data["os-stop"] = {"force_shutdown": True} + data["os-stop"] = {"force_shutdown": True} # type: ignore return http.post(f"{endpoint}/servers/{server_id}/action", data, headers) def delete_server(server_id): - """ - https://www.conoha.jp/docs/compute-delete_vm.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.delete(f"{endpoint}/servers/{server_id}", headers) -########################################################################### - - def attach_port(server_id, port_id): - """ - https://www.conoha.jp/docs/compute-attach_port.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} data = {"interfaceAttachment": {"port_id": port_id}} return http.post(f"{endpoint}/servers/{server_id}/os-interface", data, headers) def detach_port(server_id, port_id): - """ - https://www.conoha.jp/docs/compute-dettach_port.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.delete( f"{endpoint}/servers/{server_id}/os-interface/{port_id}", headers ) def list_ports(server_id): - """ - https://www.conoha.jp/docs/compute-get_attached_ports_list.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/servers/{server_id}/os-interface", headers) diff --git a/conoha/api/identity.py b/conoha/api/identity.py index 8f1b437..224e488 100644 --- a/conoha/api/identity.py +++ b/conoha/api/identity.py @@ -1,22 +1,18 @@ -""" -Identity API の呼び出し部分 -""" - from conoha import config from conoha.util import http endpoint = config.get_config()["endpoint"]["identity"] -def get_token(user_name, password, tenant_id): - """ - https://www.conoha.jp/docs/identity-post_tokens.php - """ +def get_token(user_name, password, tenant_name): headers = {"Accept": "application/json"} data = { "auth": { - "passwordCredentials": {"username": user_name, "password": password}, - "tenantId": tenant_id, + "identity": { + "methods": ["password"], + "password": {"user": {"name": user_name, "password": password}}, + }, + "scope": {"project": {"name": tenant_name}}, } } - return http.post(f"{endpoint}/tokens", data, headers) + return http.post_for_token(f"{endpoint}/auth/tokens", data, headers) diff --git a/conoha/api/image.py b/conoha/api/image.py new file mode 100644 index 0000000..26a0799 --- /dev/null +++ b/conoha/api/image.py @@ -0,0 +1,11 @@ +from conoha import config +from conoha.util import http + +endpoint = config.get_config()["endpoint"]["image"] +token = config.get_token() + + +def list_images(): + headers = {"Accept": "application/json", "X-Auth-Token": token} + # TODO: クエリパラメータでいい感じに検索できるようにしたい + return http.get(f"{endpoint}/images?limit=200", headers) diff --git a/conoha/api/network.py b/conoha/api/network.py index 4c209e4..7618b9d 100644 --- a/conoha/api/network.py +++ b/conoha/api/network.py @@ -1,54 +1,32 @@ -""" -Network API の呼び出し部分 -""" - from conoha import config from conoha.util import http endpoint = config.get_config()["endpoint"]["network"] +token = config.get_token() def list_networks(): - """ - https://www.conoha.jp/docs/neutron-get_networks_list.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/networks", headers) def create_network(): - """ - https://www.conoha.jp/docs/neutron-add_network.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.post(f"{endpoint}/networks", None, headers) def delete_network(network_id): - """ - https://www.conoha.jp/docs/neutron-remove_network.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.delete(f"{endpoint}/networks/{network_id}", headers) def describe_network(network_id): - """ - https://www.conoha.jp/docs/neutron-get_networks_detail_specified.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/networks/{network_id}", headers) -########################################################################### - - def create_port(network_id, ip_address, subnet_id, security_group_ids=None): - """ - https://www.conoha.jp/docs/neutron-add_port.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} - + headers = {"Accept": "application/json", "X-Auth-Token": token} # 必須項目 data = { "port": { @@ -56,129 +34,79 @@ def create_port(network_id, ip_address, subnet_id, security_group_ids=None): "fixed_ips": [{"ip_address": ip_address, "subnet_id": subnet_id}], } } - # Optional 項目 if security_group_ids is not None: data["port"]["security_groups"] = security_group_ids - return http.post(f"{endpoint}/ports", data, headers) def update_port(port_id, security_group_ids): - """ - https://www.conoha.jp/docs/neutron-update_port.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} data = {"port": {"security_groups": security_group_ids}} return http.put(f"{endpoint}/ports/{port_id}", data, headers) def delete_port(port_id): - """ - https://www.conoha.jp/docs/neutron-remove_port.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.delete(f"{endpoint}/ports/{port_id}", headers) def list_ports(): - """ - https://www.conoha.jp/docs/neutron-get_ports_list.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/ports", headers) def describe_port(port_id): - """ - https://www.conoha.jp/docs/neutron-get_ports_detail_specified.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/ports/{port_id}", headers) -########################################################################### - - def create_subnet(network_id, cidr): - """ - https://www.conoha.jp/docs/neutron-add_subnet.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} data = {"subnet": {"network_id": network_id, "cidr": cidr}} return http.post(f"{endpoint}/subnets", data, headers) def delete_subnet(subnet_id): - """ - https://www.conoha.jp/docs/neutron-remove_subnet.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.delete(f"{endpoint}/subnets/{subnet_id}", headers) def list_subnets(): - """ - https://www.conoha.jp/docs/neutron-get_subnets_list.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/subnets", headers) def describe_subnet(subnet_id): - """ - https://www.conoha.jp/docs/neutron-get_subnets_detail_specified.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/subnets/{subnet_id}", headers) -########################################################################### - - def create_security_group(name, description=None): - """ - https://www.conoha.jp/docs/neutron-create_secgroup.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} - + headers = {"Accept": "application/json", "X-Auth-Token": token} # 必須項目 data = {"security_group": {"name": name}} - # Optional 項目 if description is not None: data["security_group"]["description"] = description - return http.post(f"{endpoint}/security-groups", data, headers) def delete_security_group(security_group_id): - """ - https://www.conoha.jp/docs/neutron-delete_secgroup.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.delete(f"{endpoint}/security-groups/{security_group_id}", headers) def list_security_groups(): - """ - https://www.conoha.jp/docs/neutron-get_secgroups_list.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/security-groups", headers) def describe_security_group(security_group_id): - """ - https://www.conoha.jp/docs/neutron-get_secgroups_detail_specified.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/security-groups/{security_group_id}", headers) -########################################################################### - - def create_security_group_rule( direction, ether_type, @@ -189,11 +117,7 @@ def create_security_group_rule( remote_group_id=None, remote_ip_prefix=None, ): - """ - https://www.conoha.jp/docs/neutron-create_rule_on_secgroup.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} - + headers = {"Accept": "application/json", "X-Auth-Token": token} # 必須項目 data = { "security_group_rule": { @@ -202,7 +126,6 @@ def create_security_group_rule( "security_group_id": security_group_id, } } - # Optional 項目 if port_range_min is not None: data["security_group_rule"]["port_range_min"] = port_range_min @@ -214,29 +137,19 @@ def create_security_group_rule( data["security_group_rule"]["remote_group_id"] = remote_group_id if remote_ip_prefix is not None: data["security_group_rule"]["remote_ip_prefix"] = remote_ip_prefix - return http.post(f"{endpoint}/security-group-rules", data, headers) def delete_security_group_rule(rule_id): - """ - https://www.conoha.jp/docs/neutron-delete_rule_on_secgroup.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.delete(f"{endpoint}/security-group-rules/{rule_id}", headers) def list_security_group_rules(): - """ - https://www.conoha.jp/docs/neutron-get_rules_on_secgroup.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/security-group-rules", headers) def describe_security_group_rule(rule_id): - """ - https://www.conoha.jp/docs/neutron-get_rules_detail_specified.php - """ - headers = {"Accept": "application/json", "X-Auth-Token": config.get_token()["id"]} + headers = {"Accept": "application/json", "X-Auth-Token": token} return http.get(f"{endpoint}/security-group-rules/{rule_id}", headers) diff --git a/conoha/api/volume.py b/conoha/api/volume.py new file mode 100644 index 0000000..f061f4d --- /dev/null +++ b/conoha/api/volume.py @@ -0,0 +1,39 @@ +from conoha import config +from conoha.util import http + +endpoint = config.get_config()["endpoint"]["volume"] +token = config.get_token() + + +def list_types(): + headers = {"Accept": "application/json", "X-Auth-Token": token} + return http.get(f"{endpoint}/types", headers) + + +def list_volumes(): + headers = {"Accept": "application/json", "X-Auth-Token": token} + return http.get(f"{endpoint}/volumes", headers) + + +def create_volume(size, description, name, image_ref): + headers = {"Accept": "application/json", "X-Auth-Token": token} + data = { + "volume": { + "size": size, + "description": description, + "name": name, + "imageRef": image_ref, + # ブートストレージ用ボリュームは c3j1-ds02-boot 固定 + # ref: https://doc.conoha.jp/reference/api-vps3/api-blockstorage-vps3/volume-get_types_list-v3/ + "volume_type": "c3j1-ds02-boot", + } + } + return http.post(f"{endpoint}/volumes", data, headers) + + +def delete_volume(volume_id, force): + headers = {"Accept": "application/json", "X-Auth-Token": token} + if force: + return http.delete(f"{endpoint}/volumes/{volume_id}?force=true", headers) + else: + return http.delete(f"{endpoint}/volumes/{volume_id}", headers) diff --git a/conoha/cli.py b/conoha/cli.py index 50f8ca9..e9cf9d4 100644 --- a/conoha/cli.py +++ b/conoha/cli.py @@ -9,6 +9,7 @@ security_group, server, subnet, + volume, ) @@ -87,12 +88,57 @@ def image_command(command): ).set_handler(image.image_search) +def volume_command(command): + # conoha volume list-types + command.subcommand(name="volume").subcommand( + name="list-types", description="ボリュームタイプの一覧を表示する" + ).set_handler(volume.volume_list_types) + + # conoha volume list + command.subcommand(name="volume").subcommand( + name="list", description="ボリュームの一覧を表示する" + ).set_handler(volume.volume_list) + + # conoha volume create ... + command.subcommand(name="volume").subcommand( + name="create", description="ブートストレージ用のボリュームを作成する" + ).add_argument( + "--size", + help="ボリュームのサイズ (512MB プランは 30、それ以外は 100 固定)", + type=int, + choices=[30, 100], + required=True, + ).add_argument( + "--description", help="ボリュームの概要" + ).add_argument( + "--name", help="ボリューム名", required=True + ).add_argument( + "--image-ref", help="使用するイメージの UUID を指定", required=True + ).set_handler( + volume.volume_create + ) + + # conoha volume delete --volume-id VOLUME_ID + command.subcommand(name="volume").subcommand( + name="delete", description="ボリュームを削除する" + ).add_argument("--volume-id", help="ボリュームID", required=True).add_argument( + "-f", + "--force", + action="store_true", + help="エラーステータスのボリュームを強制的に削除する", + ).set_handler( + volume.volume_delete + ) + + def server_command(command): # conoha server create ... command.subcommand(name="server").subcommand( name="create", description="VM を作成する" ).add_argument( - "--image-ref", help="使用するイメージの UUID を指定", required=True + "--volume-id", + help="使用するブートストレージ用ボリュームの ID を指定", + required=True, ).add_argument( "--flavor-ref", help="VM プラン(flavor)の UUID を指定", required=True ).add_argument( @@ -109,13 +155,7 @@ def server_command(command): nargs="+", ).add_argument( "--instance-name-tag", - help="ネームタグを入れる際に利用する。文字種:半角英数字、「 - 」、「 _ 」のみを許可。文字数:255文字以下, Default:VMに紐づくGlobalIPアドレス", - ).add_argument( - # API の仕様で一つしか指定できない - "--volume-id", - help="アタッチする Volume の ID を指定", - ).add_argument( - "--vnc-keymap", choices=["en-us", "ja"], help="キーマップを指定" + help="ネームタグ。コントロールパネルのネームタグに反映される。指定なしだと null になるので注意。", ).add_argument( # ファイル指定でも良いかもしれない "--user-data", @@ -230,7 +270,14 @@ def subnet_command(command): # conoha subnet list command.subcommand(name="subnet").subcommand( name="list", description="サブネットの一覧を表示する" - ).set_handler(subnet.subnet_list) + ).add_argument( + "-l", + "--local-only", + action="store_true", + help="ローカルサブネットのみを表示する", + ).set_handler( + subnet.subnet_list + ) # conoha subnet describe --subnet-id SUBNET_ID command.subcommand(name="subnet").subcommand( @@ -427,6 +474,7 @@ def main(): auth_command(command) flavor_command(command) image_command(command) + volume_command(command) server_command(command) subnet_command(command) security_group_command(command) diff --git a/conoha/command/auth.py b/conoha/command/auth.py index cbef71a..09ccb1f 100644 --- a/conoha/command/auth.py +++ b/conoha/command/auth.py @@ -14,19 +14,14 @@ def auth_login(): except FileNotFoundError: credential = { "user_name": input("Enter user name: "), + "tenant_name": input("Enter tenant name: "), "password": getpass("Enter password: "), - "tenant_id": input("Enter tenant id: "), } config.save_credential(credential) - res = identity.get_token( - credential["user_name"], credential["password"], credential["tenant_id"] - ) - config.save_token( - { - "id": res["access"]["token"]["id"], - "expires": res["access"]["token"]["expires"], - } + token = identity.get_token( + credential["user_name"], credential["password"], credential["tenant_name"] ) + config.save_token(token) def auth_logout(): diff --git a/conoha/command/flavor.py b/conoha/command/flavor.py index c78ad65..d829a10 100644 --- a/conoha/command/flavor.py +++ b/conoha/command/flavor.py @@ -1,7 +1,3 @@ -""" -conoha flavor コマンドの処理部分 -""" - from conoha.api import compute from conoha.util.misc import print_json diff --git a/conoha/command/image.py b/conoha/command/image.py index 9580a7a..0f7f7e0 100644 --- a/conoha/command/image.py +++ b/conoha/command/image.py @@ -1,13 +1,9 @@ -""" -conoha image コマンドの処理部分 -""" - -from conoha.api import compute +from conoha.api import image from conoha.util.misc import print_json def image_list(): - print_json(compute.list_images()) + print_json(image.list_images()) def image_search(keyword): @@ -16,7 +12,7 @@ def image_search(keyword): "images": list( filter( lambda x: keyword in x.get("name", ""), - compute.list_images().get("images", []), + image.list_images().get("images", []), ) ) } diff --git a/conoha/command/network.py b/conoha/command/network.py index 92c34c8..a50e79c 100644 --- a/conoha/command/network.py +++ b/conoha/command/network.py @@ -1,7 +1,3 @@ -""" -conoha network コマンドの処理部分 -""" - from conoha.api import network from conoha.util.misc import print_json diff --git a/conoha/command/port.py b/conoha/command/port.py index de11eed..08e20a4 100644 --- a/conoha/command/port.py +++ b/conoha/command/port.py @@ -1,7 +1,3 @@ -""" -conoha port コマンドの処理部分 -""" - from conoha.api import network from conoha.util.misc import print_json diff --git a/conoha/command/security_group.py b/conoha/command/security_group.py index e1423c2..f69f240 100644 --- a/conoha/command/security_group.py +++ b/conoha/command/security_group.py @@ -1,7 +1,3 @@ -""" -conoha subnet コマンドの処理部分 -""" - from conoha.api import network from conoha.util.misc import print_json @@ -22,9 +18,6 @@ def security_group_describe(security_group_id): print_json(network.describe_security_group(security_group_id)) -########################################################################### - - def secutiry_group_create_rule( direction, ether_type, diff --git a/conoha/command/server.py b/conoha/command/server.py index 58746b7..f00b7da 100644 --- a/conoha/command/server.py +++ b/conoha/command/server.py @@ -1,7 +1,3 @@ -""" -conoha server コマンドの処理部分 -""" - from conoha.api import compute from conoha.util.misc import print_json @@ -68,14 +64,12 @@ def server_describe(server_id): def server_create( - image_ref, + volume_id, flavor_ref, admin_pass=None, key_name=None, security_groups=None, instance_name_tag=None, - volume_id=None, - vnc_keymap=None, user_data=None, ): """ @@ -84,8 +78,8 @@ def server_create( Paramters --------- - image_ref: str - 【必須項目】使用するイメージの UUID + volume_id: str + 使用するブートストレージ用ボリュームの ID flavor_ref: str 【必須項目】VM プランの UUID admin_pass: str @@ -101,10 +95,6 @@ def server_create( 多分デフォルトで作成されるポートに適用されるやつ instance_name_tag: str VM に設定するネームタグ - volume_id: str - アタッチする Volume の ID - vnc_keymap: str - キーマップ(en-us, ja のいずれか) user_data: str スタートアップスクリプト ※ ファイル名指定でもよいかも @@ -115,14 +105,12 @@ def server_create( """ print_json( compute.create_server( - image_ref, + volume_id, flavor_ref, admin_pass, key_name, security_groups, instance_name_tag, - volume_id, - vnc_keymap, user_data, ) ) @@ -192,9 +180,6 @@ def server_delete(server_id, force): print_json(compute.delete_server(server_id)) -########################################################################### - - def server_attach_port(server_id, port_id): print_json(compute.attach_port(server_id, port_id)) diff --git a/conoha/command/subnet.py b/conoha/command/subnet.py index 8617ef9..68994bf 100644 --- a/conoha/command/subnet.py +++ b/conoha/command/subnet.py @@ -1,7 +1,3 @@ -""" -conoha subnet コマンドの処理部分 -""" - from conoha.api import network from conoha.util.misc import print_json @@ -14,8 +10,21 @@ def subnet_delete(subnet_id): print_json(network.delete_subnet(subnet_id)) -def subnet_list(): - print_json(network.list_subnets()) +def subnet_list(local_only): + if local_only: + # local で始まる subnet のみを表示する + print_json( + { + "subnets": list( + filter( + lambda x: x.get("name", "").startswith("local"), + network.list_subnets().get("subnets", []), + ) + ) + } + ) + else: + print_json(network.list_subnets()) def subnet_describe(subnet_id): diff --git a/conoha/command/volume.py b/conoha/command/volume.py new file mode 100644 index 0000000..19aa550 --- /dev/null +++ b/conoha/command/volume.py @@ -0,0 +1,18 @@ +from conoha.api import volume +from conoha.util.misc import print_json + + +def volume_list_types(): + print_json(volume.list_types()) + + +def volume_list(): + print_json(volume.list_volumes()) + + +def volume_create(size, description, name, image_ref): + print_json(volume.create_volume(size, description, name, image_ref)) + + +def volume_delete(volume_id, force): + print_json(volume.delete_volume(volume_id, force)) diff --git a/conoha/config.py b/conoha/config.py index 7040c93..18967be 100644 --- a/conoha/config.py +++ b/conoha/config.py @@ -28,9 +28,9 @@ def save_credential(credential): def get_token(): with open(token_path, mode="r", encoding="utf-8") as f: - return json.load(f) + return json.load(f)["token"] def save_token(token): with open(token_path, mode="w", encoding="utf-8") as f: - json.dump(token, f) + json.dump({"token": token}, f) diff --git a/conoha/util/http.py b/conoha/util/http.py index 4f1f280..5e1ea89 100644 --- a/conoha/util/http.py +++ b/conoha/util/http.py @@ -15,6 +15,14 @@ def post(url, data, headers): return body +def post_for_token(url, data, headers): + req = urllib.request.Request( + url, data=json.dumps(data).encode("utf-8"), headers=headers + ) + with urllib.request.urlopen(req) as res: + return res.getheader("x-subject-token") + + def get(url, headers): req = urllib.request.Request(url, headers=headers) with urllib.request.urlopen(req) as res: