vcpsdk.vcpsdk のソースコード

# -*- coding: utf-8 -*-
#
# VCP API SDK
#
import logging
import time
import pandas as pd
import json

from vcplib import occtr
from vcplib.occtr import vcp_df_color
from vcplib.occtr import set_privilege_mode
from vcplib.occtr import unset_privilege_mode
from vcpsdk.vcp_tools import merge_xxx_addresses, VcpSDKError
from vcpsdk.vcp_config_yaml import VcpConfigYaml
from vcpsdk.vcpsdk_config import VCP_SDK_VERSION

# plugins
from vcpsdk.plugins.aws import VcpSpecResourceAws
from vcpsdk.plugins.aws_disk import VcpSpecResourceAwsDisk
from vcpsdk.plugins.aws_spot import VcpSpecResourceAwsSpot
from vcpsdk.plugins.sakura import VcpSpecResourceSakura
from vcpsdk.plugins.sakura_disk import VcpSpecResourceSakuraDisk
from vcpsdk.plugins.oracle import VcpSpecResourceOracle
from vcpsdk.plugins.oracle_disk import VcpSpecResourceOracleDisk
from vcpsdk.plugins.proxmox import VcpSpecResourceProxmox
from vcpsdk.plugins.azure import VcpSpecResourceAzure
from vcpsdk.plugins.azure_disk import VcpSpecResourceAzureDisk
from vcpsdk.plugins.vmware import VcpSpecResourceVmware
from vcpsdk.plugins.aic import VcpSpecResourceAic
from vcpsdk.plugins.abc import VcpSpecResourceAbc
from vcpsdk.plugins.hokudai import VcpSpecResourceHokudai
from vcpsdk.plugins.mdx2 import VcpSpecResourceMdx2
from vcpsdk.plugins.mdx2_disk import VcpSpecResourceMdx2Disk
from vcpsdk.plugins.gcp import VcpSpecResourceGcp
from vcpsdk.plugins.onpremises import VcpSpecResourceOnpremises
from vcpsdk.plugins.chameleon import VcpSpecResourceChameleon
from vcpsdk.plugins.chameleon_ext import (  # noqa
    VcpExtResourceChameleonNetwork,
    VcpExtResourceChameleonHostLeaseInfo,
    VcpExtResourceChameleon,
)

logger = logging.getLogger("vcp.sdk")
VCP_VAULT_SCHEME = "https"

#
# VCP SDK Spec Class
#


[ドキュメント] class VcpSpecClass: """ VCP 各Cloud毎のResource(spec) 情報管理用 """ def __init__(self, config_dir): """ Spec情報の初期化 :param config_dir: vcp_config.yml、vcp_flavor.yml ファイルの保存場所 :return: スペックリソースobject """ self._config_dir = config_dir def class_(self, class_name): return globals()[class_name]
[ドキュメント] def find_spec(self, provider_name, flavor): """ プロバイダ名と、flavorからspec情報を生成 :param provider_name: real cloud provider名 :param flavor: フレーバー名(ex small, medium, large) :return: スペックリソースobject """ spec = None # CloudProvider名のSNAKE -> CHAMEL words = provider_name.split("_") resource_class_name = "".join(x.capitalize() for x in words) class_name = "VcpSpecResource{}".format(resource_class_name) if class_name in globals(): spec = self.class_(class_name)(provider_name, flavor, self._config_dir) else: # 存在しないflavor VcpSDKError( "no flavor provider_name[{}] flavor[{}]".format(provider_name, flavor) ) return spec
# # VCP SDK Ext Class #
[ドキュメント] class VcpExtClass: """ VCP 各Cloud毎のExt 情報管理用 """ def __init__(self, config_dir, vcc_access_token): """ Ext情報の初期化 :param config_dir: vcp_config.yml、vcp_flavor.yml ファイルの保存場所 :param vcc_access_token: VC Controller/ Vault 用アクセストークン :return: スペックリソースobject """ self._config_dir = config_dir self._vcc_access_token = vcc_access_token def class_(self, class_name): return globals()[class_name]
[ドキュメント] def find_extension(self, provider_name): """ プロバイダ名からextension情報を生成 :param provider_name: real cloud provider名 :return: VcpExtResource Object """ extension = None # CloudProvider名のSNAKE -> CHAMEL words = provider_name.split("_") resource_class_name = "".join(x.capitalize() for x in words) class_name = "VcpExtResource{}".format(resource_class_name) if class_name in globals(): extension = self.class_(class_name)( provider_name, self._config_dir, self._vcc_access_token ) else: # 存在しないextension VcpSDKError("no extension provider_name[{}]".format(provider_name)) return extension
# # VCP SDK unit&node Class(vcplib::VcUnit & vcplib::VcNode相当) #
[ドキュメント] class VcpUnitClass: """ VcpUnitクラス(VCP Lib::VcUnit & VCP Lib::VcNode相当) サンプルコード .. code-block:: python ... ugroup = sdk.create_ugroup('UnitGroup名', 'compute|storage') unit = ugroup.create_unit('Unit名', spec) # Unit内のnodeをpower off unit.power_off_nodes() # Unit内のnodeをpower on unit.power_on_nodes() # Node追加 unit.add_nodes(ノード数) # Node削除 unit.delete_nodes(ノード数) # Node情報出力 unit.df_nodes() # Node情報取得 ips = unit.find_ip_adresses() nodes = unit.find_nodes() """ def __init__(self, ugroup, unit): """ VcpUnit :param vc: 既存VCP Lib::Vc情報 """ self._unit = unit self._wait_timeout_sec = ugroup._wait_timeout_sec @property def name(self): """ VCP Lib::VcUnit の name """ return self._unit.name @property def state(self): """ VCP Lib::VcUnit の state """ return self._unit.state
[ドキュメント] def watch(self, wait_for=True): """ Unit監視開始 :param wait_for: nodeの削除待ち条件(True: 待つ) .. note:: power_on_nodes() の利用を推奨 """ self._unit.watch() # waiting wakeup if wait_for is True: self.wait_nodes_applied() logger.info("watching successe.")
[ドキュメント] def unwatch(self): """ Unit監視停止 .. note:: power_off_nodes() の利用を推奨 """ self._unit.unwatch()
[ドキュメント] def df_nodes(self, privileged=False): """ node一覧(DataFrame形式) :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) """ set_privilege_mode(privileged) # 自分のunit情報更新 self._unit.config() # DataFrame出力 dfs = self._unit.nodes_df() unset_privilege_mode(privileged=privileged) return vcp_df_color(dfs)
[ドキュメント] def find_nodes( self, node_id="", node_state="", node_no="", ip_addresses=[], ip_address=None, cloud_instance_id=None, mapper=None, privileged=False, ): """ 検索条件にマッチするnode検索 :param node_id: 検索条件node_id :param node_state: 検索条件node_state :param node_no: 検索条件node_no :param ip_addresses: 検索条件cloud_instance_addresses :param ip_address: 検索条件cloud_instance_address :param cloud_instance_id: 検索条件cloud_instance_id :param mapper: 検索結果のnodeに適用する関数 :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: node情報(vcplib::VcNode配列) .. note:: * ip_address と ip_addresses を両方指定すると和集合として扱う * 検索条件指定が複数あれば、AND条件とする * 複数nodeの場合、node_no の昇順にsortした結果を返す """ set_privilege_mode(privileged) # 自分のunit情報更新 self._unit.config() # ip_addresses 指定をmergeしておく ip_addr_conditions = merge_xxx_addresses(ip_address, ip_addresses) # 条件に一致するnode を検索 nodes = [ node if mapper is None else mapper(node) for node in self._unit.nodes if (node_id == "" or node.id == node_id) and (node_state == "" or node.state == node_state) and (node_no == "" or node.no == node_no) and ( len(ip_addr_conditions) == 0 or node.cloud_instance_address in ip_addr_conditions ) and ( cloud_instance_id is None or node.cloud_instance_id == cloud_instance_id ) ] unset_privilege_mode(privileged=privileged) # node_no 順にsort return sorted(nodes, key=lambda x: x.no)
def find_ip_addresses(self, privileged=False, **conditions): """ 検索条件にマッチするnodeのIPアドレスリストを返す :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: IPアドレス(配列) .. note:: * パラメータは、find_nodes() からmapperを除いたもの """ set_privilege_mode(privileged) nodes = self.find_nodes(privileged=privileged, **conditions) unset_privilege_mode(privileged=privileged) return list(map(lambda node: node.cloud_instance_address, nodes))
[ドキュメント] def add_nodes( self, num_add_nodes=1, ip_addresses=[], ip_address=None, mac_addresses=[], mac_address=None, wait_for=True, verbose=0, privileged=False, ): """ Nodeの追加 :param num_add_nodes: 追加起動Node数 :param ip_addresses: 追加起動するNodeのIPアドレス(配列) :param ip_address: 追加起動するNodeのIPアドレス :param mac_addresses: 追加起動するNodeのMACアドレス(配列) :param mac_address: 追加起動するNodeのMACアドレス :param wait_for: nodeの起動待ち条件(True: 待つ) :param verbose: verbose=0 でverboseなし :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: node情報(vcplib::VcNode配列) .. note:: * ip_address と ip_addresses を両方指定すると和集合として扱う * ip_address と ip_addresses を storageタイプのunitに指定するとエラーとする * ip_addresses, ip_address のいずれかを指定した場合、num_add_nodes を無視する """ # 引数チェック if isinstance(ip_addresses, list) is False: VcpSDKError("ip_addresses is not list") if isinstance(mac_addresses, list) is False: VcpSDKError("mac_addresses is not list") set_privilege_mode(privileged) # 自分のunit情報更新 self._unit.config() # vc_typeのチェック vc_type = self._unit.vc.type if vc_type == "storage" and (len(ip_addresses) != 0 and ip_address is not None): VcpSDKError("can't set ip_address(es) to storage") # node追加 ip_address_list = merge_xxx_addresses(ip_address, ip_addresses) mac_address_list = merge_xxx_addresses(mac_address, mac_addresses) self._unit.add_node(num_add_nodes, ip_address_list, mac_address_list) # node追加完了待ち if wait_for is True: self.wait_nodes_applied() logger.info("add_node completed.") new_nodes = self.find_nodes(privileged=None) unset_privilege_mode(privileged=privileged) return new_nodes
def check_search_cond_( self, num_nodes, node_no, cloud_instance_id, ip_addresses, ip_address, wait_for ): """ Node の検索条件指定チェック """ vals = [num_nodes, node_no, cloud_instance_id, ip_addresses, ip_address] none_num = vals.count(None) valid_arg_num = len(vals) - none_num # 検索条件が2個以上かチェック if valid_arg_num != 0 and valid_arg_num != 1: VcpSDKError("invalid argment, one condition parameter allowed") # 検索条件がない場合、num_nodes=1 if valid_arg_num == 0: num_nodes = 1 if wait_for is not True: # 複数nodeを削除するのにwait_for=False ならエラー # (power off自体は1個ずつ) if (num_nodes is not None and num_nodes > 1) or ( ip_addresses is not None and len(ip_addresses) > 1 ): VcpSDKError("invalid argment, delete multi-node must be wait_for=True") # 対象VcNode個数 return num_nodes
[ドキュメント] def delete_nodes( self, num_delete_nodes=None, node_no=None, cloud_instance_id=None, ip_addresses=None, ip_address=None, wait_for=True, verbose=0, privileged=False, ): """ 検索条件にマッチするNode削除 :param num_delete_nodes: 削除対象Node最大数 :param node_no: 検索条件node_no :param cloud_instance_id: 検索条件cloud_instance_id :param ip_addresses: 検索条件cloud_instance_address(配列) :param ip_address: 検索条件cloud_instance_address :param wait_for: nodeの削除待ち条件(True: 待つ) :param verbose: verbose=0 でverboseなし :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: node情報(vcplib::VcNode配列) .. note:: * 検索条件は、最大1個のみ指定可能 * 検索条件未指定の場合は、num_delete_nodes=1 のみ指定と同様 * wait_for=False の場合、複数nodeの削除はできない。(node削除は1個ずつ) """ # 引数チェック num_delete_nodes = self.check_search_cond_( num_delete_nodes, node_no, cloud_instance_id, ip_addresses, ip_address, wait_for, ) set_privilege_mode(privileged) # 自分のunit情報更新 self._unit.config() # 検索条件にマッチしたnodeを返す ip_addr_conditions = merge_xxx_addresses(ip_address, ip_addresses) # 対象となるnodeを削除 deleted_num = 0 for node in self._unit.nodes: if num_delete_nodes is not None and deleted_num >= num_delete_nodes: break if ( (node_no is None or node.no == node_no) and ( cloud_instance_id is None or node.cloud_instance_id == cloud_instance_id ) and ( len(ip_addr_conditions) == 0 or node.cloud_instance_address in ip_addr_conditions ) ): # nodeを削除 node.delete() # node削除待ち self.wait_nodes_applied() logger.info("a node deleted.") deleted_num += 1 if deleted_num > 0: logger.info("deleted node(s) completed.") new_nodes = self.find_nodes(privileged=None) unset_privilege_mode(privileged=privileged) return new_nodes
[ドキュメント] def watch_nodes( self, num_watch_nodes=None, node_no=None, cloud_instance_id=None, ip_addresses=None, ip_address=None, wait_for=True, privileged=False, verbose=0, ): """ 検索条件にマッチするNodeの監視開始 :param num_watch_nodes: watch対象Node最大数 :param node_no: 検索条件node_no :param cloud_instance_id: 検索条件cloud_instance_id :param ip_addresses: 検索条件cloud_instance_address(配列) :param ip_address: 検索条件cloud_instance_address :param wait_for: nodeの監視開始待ち条件(True: 待つ) :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :param verbose: verbose=0 でverboseなし :return: node情報(vcplib::VcNode配列) .. note:: * power_off_nodes の利用を推奨 """ # 引数チェック num_watch_nodes = self.check_search_cond_( num_watch_nodes, node_no, cloud_instance_id, ip_addresses, ip_address, wait_for, ) set_privilege_mode(privileged) # 自分のunit情報更新 self._unit.config() # 検索条件にマッチしたnodeを返す ip_addr_conditions = merge_xxx_addresses(ip_address, ip_addresses) # 対象となるnodeを監視開始 watched_num = 0 for node in self._unit.nodes: if num_watch_nodes is not None and watched_num >= num_watch_nodes: break if ( (node_no is None or node.no == node_no) and ( cloud_instance_id is None or node.cloud_instance_id == cloud_instance_id ) and ( len(ip_addr_conditions) == 0 or node.cloud_instance_address in ip_addr_conditions ) ): # nodeを監視開始 node.watch() # nodeのRUNNING待ち self.wait_nodes_applied() logger.info("a node watching start.") watched_num += 1 if watched_num > 0: logger.info("watching node(s) has started.") new_nodes = self.find_nodes(privileged=None) unset_privilege_mode(privileged=privileged) return new_nodes
[ドキュメント] def unwatch_nodes( self, num_watch_nodes=None, node_no=None, cloud_instance_id=None, ip_addresses=None, ip_address=None, privileged=False, verbose=0, ): """ 検索条件にマッチするNodeの監視停止 :param num_watch_nodes: unwatch対象Node最大数 :param node_no: 検索条件node_no :param cloud_instance_id: 検索条件cloud_instance_id :param ip_addresses: 検索条件cloud_instance_address(配列) :param ip_address: 検索条件cloud_instance_address :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :param verbose: verbose=0 でverboseなし :return: node情報(vcplib::VcNode配列) .. note:: * power_on_nodes の利用を推奨 """ # 引数チェック num_watch_nodes = self.check_search_cond_( num_watch_nodes, node_no, cloud_instance_id, ip_addresses, ip_address, False ) set_privilege_mode(privileged) # 自分のunit情報更新 self._unit.config() # 検索条件にマッチしたnodeを返す ip_addr_conditions = merge_xxx_addresses(ip_address, ip_addresses) # 対象となるnodeを監視停止 watched_num = 0 for node in self._unit.nodes: if num_watch_nodes is not None and watched_num >= num_watch_nodes: break if ( (node_no is None or node.no == node_no) and ( cloud_instance_id is None or node.cloud_instance_id == cloud_instance_id ) and ( len(ip_addr_conditions) == 0 or node.cloud_instance_address in ip_addr_conditions ) ): # nodeを監視停止 node.unwatch() watched_num += 1 if watched_num > 0: logger.info("unwatch node(s) completed.") new_nodes = self.find_nodes(privileged=None) unset_privilege_mode(privileged=privileged) return new_nodes
[ドキュメント] def power_off_nodes( self, num_power_off_nodes=None, node_no=None, cloud_instance_id=None, ip_addresses=None, ip_address=None, wait_for=True, privileged=False, verbose=0, ): """ 検索条件にマッチするNodeのInstanceのpower off :param num_power_off_nodes: power off対象Node最大数 :param node_no: 検索条件node_no :param cloud_instance_id: 検索条件cloud_instance_id :param ip_addresses: 検索条件cloud_instance_address(配列) :param ip_address: 検索条件cloud_instance_address :param wait_for: nodeの監視開始待ち条件(True: 待つ) :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :param verbose: verbose=0 でverboseなし :return: node情報(vcplib::VcNode配列) .. note:: * 検索条件は、最大1個のみ指定可能 * 検索条件未指定の場合は、num_power_off_nodes=1 のみ指定と同様 * wait_for=False の場合、複数nodeのpower offはできない。(node power offは1個ずつ) """ # 引数チェック num_power_off_nodes = self.check_search_cond_( num_power_off_nodes, node_no, cloud_instance_id, ip_addresses, ip_address, wait_for, ) set_privilege_mode(privileged) # 自分のunit情報更新 self._unit.config() # 検索条件にマッチしたnodeを返す ip_addr_conditions = merge_xxx_addresses(ip_address, ip_addresses) # 対象となるnodeを監視開始 power_off_num = 0 for node in self._unit.nodes: if num_power_off_nodes is not None and power_off_num >= num_power_off_nodes: break if ( (node_no is None or node.no == node_no) and ( cloud_instance_id is None or node.cloud_instance_id == cloud_instance_id ) and ( len(ip_addr_conditions) == 0 or node.cloud_instance_address in ip_addr_conditions ) ): # nodeをpower off node.power_off() # nodeのRUNNING待ち self.wait_nodes_applied() logger.info("a node power off start.") power_off_num += 1 if power_off_num > 0: logger.info("power off node(s) has started.") new_nodes = self.find_nodes(privileged=None) unset_privilege_mode(privileged=privileged) return new_nodes
[ドキュメント] def power_on_nodes( self, num_power_on_nodes=None, node_no=None, cloud_instance_id=None, ip_addresses=None, ip_address=None, wait_for=True, privileged=False, verbose=0, ): """ 検索条件にマッチするNodeのInstanceのpower on :param num_power_on_nodes: power on対象Node最大数 :param node_no: 検索条件node_no :param cloud_instance_id: 検索条件cloud_instance_id :param ip_addresses: 検索条件cloud_instance_address(配列) :param ip_address: 検索条件cloud_instance_address :param wait_for: nodeの監視開始待ち条件(True: 待つ) :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :param verbose: verbose=0 でverboseなし :return: node情報(vcplib::VcNode配列) .. note:: * 検索条件は、最大1個のみ指定可能 * 検索条件未指定の場合は、num_power_on_nodes=1 のみ指定と同様 * wait_for=False の場合、複数nodeのpower onはできない。(node power onは1個ずつ) """ # 引数チェック num_power_on_nodes = self.check_search_cond_( num_power_on_nodes, node_no, cloud_instance_id, ip_addresses, ip_address, wait_for, ) set_privilege_mode(privileged) # 自分のunit情報更新 self._unit.config() # 検索条件にマッチしたnodeを返す ip_addr_conditions = merge_xxx_addresses(ip_address, ip_addresses) # 対象となるnodeを監視開始 power_on_num = 0 for node in self._unit.nodes: if num_power_on_nodes is not None and power_on_num >= num_power_on_nodes: break if ( (node_no is None or node.no == node_no) and ( cloud_instance_id is None or node.cloud_instance_id == cloud_instance_id ) and ( len(ip_addr_conditions) == 0 or node.cloud_instance_address in ip_addr_conditions ) ): # nodeをpower on node.power_on() # nodeのRUNNING待ち self.wait_nodes_applied() logger.info("a node power on start.") power_on_num += 1 if power_on_num > 0: logger.info("power on node(s) has started.") new_nodes = self.find_nodes(privileged=None) unset_privilege_mode(privileged=privileged) return new_nodes
def wait_nodes_applied(self): """ 自unit内のnodeへの操作が終わるまで待つ """ state = None is_complete = False num_of_retry = int(self._wait_timeout_sec / 5) for retry_no in range(num_of_retry): # 自分のunit情報更新 self._unit.config() is_stability = True if self._unit.state in [ "BOOTING", "STOPPING", "SUSPENDING", "RESUMING", "DELETING", "SHUTTING_DOWN", ]: is_stability = False if self._unit.state == "INDEFINITE": # unit 内のnodeの状態が安定しているかチェック for node in self.find_nodes(privileged=None): if node.state in [ "BOOTING", "STOPPING", "SUSPENDING", "RESUMING", "DELETING", "SHUTTING_DOWN", ]: is_stability = False break if is_stability is False: logger.info("%s ... %d sec" % (self._unit.state, retry_no * 5)) time.sleep(5) continue is_complete = True state = self._unit.state break logger.info("unit {} is {}".format(self._unit.name, self._unit.state)) if state == "ERROR": # エラー表示にVC情報を出力 logger.error(self._unit.error()) elif is_complete is False: # 待ち時間いっぱい VcpSDKError("Full of waiting time") def __str__(self): """ Unit情報(Unit) """ return str(self._unit)
# # VCP UnitGroup Class #
[ドキュメント] class VcpUnitGroupClass: """ VcpUnitGroupClassクラス(VCLIB::Vc相当) サンプルコード .. code-block:: python # 初期化 sdk = VcpSDK('アクセストークン', config_dir="vcp_config.yml, vcp_flavor.yml のdirectory") spec = sdk.get_spec('プロバイダ名', 'flavor名') # UnitGroup作成 ugroup = sdk.create_ugroup('UnitGroup名', 'compute|storage') # Unit作成 unit = ugroup.create_unit('Unit名', spec) # Unit削除 ugroup.delete_units('Unit名') # 各種情報出力 ugroup.df_units() ugroup.df_nodes() # 各種情報取得 ips = ugroup.find_ip_address() units = ugroup.find_units() unit = ugroup.get_unit('Unit名') nodes = ugroup.find_nodes() # UnitGroup削除 ugroup.cleanup() # UnitGroupの所有者変更 ugroup.change_owner("new_owner") """ def __init__(self, vc=None, vcp_config=""): """ VcpUnitGroupClass :param vc: 既存vcplib::Vc情報 :param config_dir: vcp_config.yml のdirname """ self._vc = vc # VcNodeの起動、操作待ち時間の調整 self._wait_timeout_sec = 1000 # 1000sec = 15minutes self._vcp_config = vcp_config if "wait_timeout_sec" in self._vcp_config["vcc"]: self._wait_timeout_sec = self._vcp_config["vcc"]["wait_timeout_sec"] @property def state(self): """ vcplib::Vcの state """ return self._vc.state @property def owner(self): """ vcplib::Vcの owner """ return self._vc.owner @property def name(self): """ Unit groupの名前を取得する """ # 必要な場合は外側で_vc.config() を呼び出しているという前提 return self._vc.name @name.setter def name(self, v): """ Unit groupの名前を更新する :param v: Unit groupの名前 """ # 現在の名前と異なる場合のみ変更処理を行う self._vc.config() if self.name != v: self._update_name(v)
[ドキュメント] def create_unit(self, unit_name, spec, wait_for=True, privileged=False, verbose=-1): """ Unit作成 :param unit_name: 起動Unit名 :param spec: 起動spec情報 :param wait_for: nodeの起動待ち条件(True: 待つ) :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :param verbose: verbose=0 でverboseなし :return: Unit情報(vcpsdk::VcpUnit) """ if self._vc is None: VcpSDKError("no yet setup unit_group") set_privilege_mode(privileged) # unit_name(unit名) が既存かチェック vcp_units = self.find_units(unit_name=unit_name) if len(vcp_units) > 0: VcpSDKError("already exist unit[{}]".format(unit_name)) # unit の type と spec の typeが合致するかチェック compute|storage if self._vc.type != spec.unit_type: VcpSDKError( "not much ugroup_type vc[{}] and spec[{}]".format( self._vc.type, spec.unit_type ) ) # CCIの生成 my_cci = spec.cci(unit_name) # Unit追加 result = self._vc.add_unit(unit_name, my_cci) if result is False: VcpSDKError("can't create unit") # VC情報更新 self._vc.config() # node追加完了待ち if wait_for is True: self.wait_unit_applied(unit_name=unit_name) # 作成したunitを返す vcp_units = self.find_units(unit_name=unit_name) unset_privilege_mode(privileged=privileged) # 1回1個なので先頭の1個を返す return vcp_units[0]
[ドキュメント] def delete_units( self, unit_name, wait_for=True, force=False, privileged=False, verbose=0 ): """ 検索条件にマッチするUnit削除 :param name: 検索条件Unit名 :param wait_for: nodeの削除待ち条件(True: 待つ) :param force: force=Trueで、配下にnodeが存在してもnode毎削除する :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :param verbose: verbose=0 でverboseなし """ set_privilege_mode(privileged) # VC情報更新 self._vc.config() # 指定unit名に対応するunitがなければなにもしない vcp_units = self.find_units(unit_name=unit_name) if len(vcp_units) == 0: VcpSDKError("no unit unit_name[{}]".format(unit_name)) # 対象となる Unitを削除 vcp_units[0]._unit.delete(force=force) # unit削除待ち if wait_for is True: self.wait_unit_applied(unit_name) logger.info("delete_unit completed.") unset_privilege_mode(privileged=privileged)
def wait_unit_applied(self, unit_name): """ 指定unitがbooting以外になるまで待つ :param unit_name: Unit名 """ state = None is_complete = False num_of_retry = int(self._wait_timeout_sec / 5) for retry_no in range(num_of_retry): # 処理中のサーバをチェック vcp_units = self.find_units(unit_name) if len(vcp_units) == 0: is_complete = True break # unitは、1つのunit_group内でuniq unit = vcp_units[0]._unit if unit.state in [ "BOOTING", "STOPPING", "SUSPENDING", "RESUMING", "DELETING", "SHUTTING_DOWN", "INDEFINITE", ]: logger.info("%s ... %d sec" % (unit.state, retry_no * 5)) time.sleep(5) continue state = unit.state is_complete = True break if state != "ERROR": # 連続起動の待ち time.sleep(6) logger.info("unit %s is %s" % (unit_name, state)) if state == "ERROR": # エラー表示にVC情報を出力 logger.error(self._vc) VcpSDKError("failed ({})".format(unit_name)) elif is_complete is False: # 待ち時間いっぱい VcpSDKError("Full of waiting time ({})".format(unit_name))
[ドキュメント] def df_units(self, privileged=False): """ unit一覧(DataFrame形式) :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) """ set_privilege_mode(privileged) # VC情報更新 self._vc.config() unset_privilege_mode(privileged=privileged) return self._vc.units_df()
[ドキュメント] def df_nodes(self, privileged=False): """ node一覧(DataFrame形式) :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) """ set_privilege_mode(privileged) # VC情報更新 self._vc.config() # DataFrame出力 dfs = [] for vcp_unit in self._vc.units: if len(vcp_unit.nodes) > 0: dfs.append(vcp_unit.nodes_df()) unset_privilege_mode(privileged=privileged) return vcp_df_color(dfs)
[ドキュメント] def find_units(self, unit_name="", privileged=False): """ 検索条件にマッチするunit検索 :param unit_name: 検索条件Unit名 :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: VcpUnit情報 .. note:: * 検索条件指定がない場合、UnitGroup内の全てのUnitを返す """ set_privilege_mode(privileged) # VC情報更新 self._vc.config() # 対象のUnitGroupを設定 vcp_units = [] for unit in self._vc.units: if unit_name == "" or unit.name == unit_name: vcp_units.append(VcpUnitClass(self, unit)) unset_privilege_mode(privileged=privileged) return vcp_units
[ドキュメント] def get_unit(self, unit_name, privileged=False): """ unit名を指定してunit取得 :param unit_name: ユニット名 :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: Unit情報(vcpsdk::VcpUnitClass) """ set_privilege_mode(privileged) # 既存のunitをunit_nameで検索して、最初に見つかったunit units = self.find_units(unit_name=unit_name) unset_privilege_mode(privileged=privileged) if len(units) > 0: return units[0] else: return None
def create_empty_vc(self, ugroup_name, ugroup_type): """ 空のVCを作成する :param ugroup_name: UnitGroup名 :return: Vc情報 """ # # VC作成
[ドキュメント] def find_nodes( self, unit_name="", node_id="", node_state="", node_no="", ip_addresses=[], ip_address=None, cloud_instance_id=None, mapper=None, privileged=False, ): """ 検索条件にマッチするnode検索 :param unit_name: 検索条件unit名 :param node_id: 検索条件node_id :param node_state: 検索条件node_state :param node_no: 検索条件node_no :param ip_addresses: 検索条件cloud_instance_addresses(配列) :param ip_address: 検索条件cloud_instance_address :param cloud_instance_id: 検索条件cloud_instance_id :param mapper: 検索結果のnodeに適用する関数 :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: node情報(vcplib::VcNode配列) .. note:: * ip_address と ip_addresses を両方指定すると和集合として扱う * 検索条件指定が複数あれば、AND条件とする """ set_privilege_mode(privileged) # 自分のunit情報更新 self._vc.config() # 検索条件にマッチしたnodeを返す ip_addr_conditions = merge_xxx_addresses(ip_address, ip_addresses) unset_privilege_mode(privileged=privileged) return [ node if mapper is None else mapper(node) for unit in self._vc.units for node in unit.nodes if (unit_name == "" or unit.name == unit_name) and (node_id == "" or node.id == node_id) and (node_state == "" or node.state == node_state) and (node_no == "" or node.no == node_no) and ( len(ip_addr_conditions) == 0 or node.cloud_instance_address in ip_addr_conditions ) and ( cloud_instance_id is None or node.cloud_instance_id == cloud_instance_id ) ]
def find_ip_addresses(self, privileged=False, **conditions): """ 検索条件にマッチするnodeのIPアドレスリストを返す :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: IPアドレス(配列) .. note:: * パラメータは、find_nodes() と同じ """ set_privilege_mode(privileged) return self.find_nodes( **conditions, mapper=lambda node: node.cloud_instance_address, privileged=None ) unset_privilege_mode(privileged=privileged)
[ドキュメント] def change_owner(self, new_owner, privileged=False): """ VCの所有者変更 :param new_owner: 新しい所有者 """ set_privilege_mode(privileged) if self._vc: result = self._vc.change_owner(new_owner) if result is False: VcpSDKError( "failed ugroup change owner http status({})".format( self._vc.last_error_http_status ) ) unset_privilege_mode(privileged=privileged)
[ドキュメント] def cleanup(self, wait_for=True, privileged=False): """ VC初期化(Vc配下の全てのUnitとNodeを削除) :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :param wait_for: nodeの削除待ち条件(True: 待つ) """ set_privilege_mode(privileged) if self._vc: result = self._vc.delete(force=True) if result is False: VcpSDKError( "failed ugroup cleanup http status({})".format( self._vc.last_error_http_status ) ) if wait_for is True: self.wait_cleanup() logger.info( "cleanup completed. vc {} is cleanup(no unit)".format(self._vc.name) ) unset_privilege_mode(privileged=privileged) self._vc = None
def wait_cleanup(self): """ 自分のvc内の全てのunitが消えるまで待つ """ if self._vc: is_end = False num_of_retry = int(self._wait_timeout_sec / 5) for retry_no in range(num_of_retry): # VC状態を更新 result = self._vc.config() if result is False: # VCの削除が完了 is_end = True break if len(self._vc.units) == 0: is_end = True break # unit がまだある status_units = [] is_exist_not_error = False for unit in self._vc.units: status_units.append("%s is %s" % (unit.name, unit.state)) # 状態遷移の完了状態 # - エラー # - Instanceがmount済みで削除できないDiskがRUNNING状態になった if unit.state != "ERROR" and not ( self._vc.type == "storage" and unit.state == "RUNNING" ): # まだ処理中のunitがある is_exist_not_error = True logger.info("%s ... %d sec" % ("\n".join(status_units), retry_no * 5)) if is_exist_not_error is True: time.sleep(5) continue break if is_end is False: VcpSDKError("not completed!!!") def _update_name(self, name, group_type="compute"): """ UnitGroup名を変更する :param name: UnitGroup名 :param group_type: compute | storage """ cci = VcpSDK.empty_cci(name, ugroup_type=group_type) self._vc.update(cci) def __str__(self): """ UnitGroup情報(VC) """ return str(self._vc) @staticmethod def empty_cci(ugroup_name, ugroup_type="compute"): """ 空のVC用CCIを作成 :param ugroup_name: unitGroup名 :param ugroup_type: compute | storage :return: CCI文字列 """ my_cci = """ - vc: cci_version: "{cci_version}" type: {ugroup_type} description: "{ugroup_name}" name: {ugroup_name}""".format( ugroup_type=ugroup_type, cci_version=VCP_SDK_VERSION, ugroup_name=ugroup_name, ) return my_cci
[ドキュメント] def update_ugroup_name(self, ugroup_name, ugroup_type="compute", privileged=False): """ UnitGroup名を設定 :param ugroup_name: unitGroup名 :param ugroup_type: compute | storage :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) """ set_privilege_mode(privileged) if self._vc: my_cci = VcpUnitGroupClass.empty_cci(ugroup_name, ugroup_type) self._vc.update(my_cci) unset_privilege_mode(privileged=privileged)
# # VCP SDK BASE Class #
[ドキュメント] class VcpSDK: """ VCP SDKベースクラス サンプルコード .. code-block:: python # 初期化(confi_dir省略時は、 `/notebooks/notebook/vcp_config` ) sdk = VcpSDK('アクセストークン', config_dir="vcp_config.yml, vcp_flavor.yml のdirectory") # バージョン情報 sdk.version() # フレーバー情報 sdk.df_flavors('プロバイダ名') # vaultやdocker registory のurl情報 sdk.vcc_info() # spec作成 spec = sdk.get_spec('プロバイダ名', 'flavor名') # UnitGroup情報出力 sdk.df_ugroups() # UnitGroup情報取得 ugroups = sdk.find_ugroups() ugroup = sdk.get_ugroup('UnitGroup名') # 既存サーバ用 ssh 公開鍵取得 sdk.get_publickey() # UnitGroupの作成 ugroup = sdk.create_ugroup('UnitGroup名', 'compute|storage') """ def __init__(self, vcc_access_token="", config_dir="", verbose=0): self._vcc_access_token = vcc_access_token self._config_dir = config_dir # # vcpsdk の初期パラメータ設定 # - config/vcp_config.yml # - config/vcp_flavor.yml # vcy = VcpConfigYaml(config_dir) self._vcp_config = vcy.load("vcp_config") # VCP Lib初期化 vcc_host = self._vcp_config["vcc"]["host"] if "vcc_port" in self._vcp_config["vcc"]: vcc_host = "{}:{}".format(vcc_host, self._vcp_config["vcc"]["vcc_port"]) # SSL insecure request warning 表示設定 insecure_request_warning = True # 表示 if "insecure_request_warning" in self._vcp_config["vcc"]: insecure_request_warning = self._vcp_config["vcc"][ "insecure_request_warning" ] self._oc = occtr.Occtr( self._vcc_access_token, vcc_host=vcc_host, insecure_request_warning=insecure_request_warning, verbose=verbose, ) if not self._oc: VcpSDKError("initialize occtr failed") # 認証チェック self.authority()
[ドキュメント] def authority(self): """ authority 情報の取得 結果サンプル .. code-block:: none { 'role': 'fullaccess', 'user_name': 'nobody', 'user_role': 'regular' } :return: authority情報 """ return json.loads(self._oc.authority())
@property def verbose(self): """ VCP Lib:verbose """ return self._oc.verbose @verbose.setter def verbose(self, verbose): """ VCP Lib:verbose 設定 """ self._oc.verbose = verbose @property def config_dir(self): """ config ファイルのディレクトリ """ return self._config_dir @config_dir.setter def config_dir(self, config_dir): """ config ファイルのディレクトリ設定 VCP Lib:verbose 設定 """ self._config_dir = config_dir
[ドキュメント] def get_spec(self, provider_name, flavor): """ Spec情報の取得 :param provider_name: プロバイダ名 :param flavor: small, medium, large などのfalvor文字列 :return: SPECのリソース情報(vcpsdk::VcpSpecResource) """ spec = VcpSpecClass(self._config_dir) return spec.find_spec(provider_name, flavor)
[ドキュメント] def get_extension(self, provider_name): """ extension(plugin拡張項目)情報の取得 :param provider_name: プロバイダ名 :return: extensionのリソース情報(vcpsdk::VcpExtResource) """ ext = VcpExtClass(self._config_dir, self._vcc_access_token) return ext.find_extension(provider_name)
[ドキュメント] def create_ugroup(self, ugroup_name, ugroup_type="compute", privileged=False): """ UnitGroupの作成 :param ugroup_name: vc名 :param ugroup_type: vcタイプ compute|storage :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: UnitGroup情報(vcpsdk::VcpUnitGroupClass) """ set_privilege_mode(privileged) # 既存のvcをugroup_nameで検索 ugs = self.find_ugroups(ugroup_name=ugroup_name) if len(ugs) > 0: # 既存エラー VcpSDKError("aleady exist UnitGroup. change name or cleanup first!") # 新規UnitGroupの作成 vc = self.create_empty_vc(ugroup_name, ugroup_type) ug = VcpUnitGroupClass(vc, vcp_config=self._vcp_config) unset_privilege_mode(privileged=privileged) return ug
[ドキュメント] def df_ugroups(self, privileged=False): """ UnitGroup 一覧(DataFrame) :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) """ set_privilege_mode(privileged) self._oc.config() unset_privilege_mode(privileged=privileged) return self._oc.vcs_df()
[ドキュメント] def df_nodes(self, privileged=False): """ All node一覧(DataFrame形式) :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) """ set_privilege_mode(privileged) self._oc.config() dfs = [] for vc in self._oc.vcs: for unit in vc.units: if len(unit.nodes) > 0: dfs.append(unit.nodes_df()) unset_privilege_mode(privileged=privileged) return vcp_df_color(dfs)
[ドキュメント] def find_ugroups( self, ugroup_name="", vcid="", vcno="", state=None, ugroup_type="", privileged=False, ): """ 検索条件にマッチするVC検索 :param ugroup_name: 検索条件Vc名 :param vcid: 検索条件vcid :param vcno: 検索条件vcno :param ugroup_type: 検索条件UnitGroupタイプ :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: UnitGroup情報(vcpsdk::VcpUnitGroupClass) .. note:: * 検索条件指定が複数あれば、AND条件とする """ set_privilege_mode(privileged) # 自分のVC(全UnitGroup)情報更新 self._oc.config() ugs = [] for vc in self._oc.vcs: if ( (ugroup_name == "" or vc.name == ugroup_name) and (vcid == "" or vc.vcid == vcid) and (vcno == "" or vc.vcno == vcno) and (ugroup_type == "" or vc.type == ugroup_type) and (state is None or vc.state == state) ): ugs.append(VcpUnitGroupClass(vc, vcp_config=self._vcp_config)) unset_privilege_mode(privileged=privileged) return ugs
[ドキュメント] def get_ugroup(self, ugroup_name, privileged=False): """ unit group名を指定して、UnitGroup取得 :param ugroup_name: vc名 :param privileged: 特権モードを指定する場合は True、指定しない場合は False (デフォルト) :return: UnitGroup情報(vcpsdk::VcpUnitGroupClass) """ set_privilege_mode(privileged) # 既存のunit group をugroup_nameで検索して、最初に見つかったunit group ugs = self.find_ugroups(ugroup_name=ugroup_name) unset_privilege_mode(privileged=privileged) if len(ugs) > 0: return ugs[0] else: return None
def create_empty_vc(self, ugroup_name, ugroup_type): """ 空のVCを作成する :param ugroup_name: UnitGroup名 :return: Vc情報 """ # # VC作成 # cci = VcpUnitGroupClass.empty_cci(ugroup_name, ugroup_type) vc = self._oc.create_vc(cci) return vc def __str__(self): """ VCP SDK 自体は VC配下の情報をもたない stdoutに、version出力 """ self.version() return ""
[ドキュメント] def version(self): """ VCP Libのバージョン出力 """ # VCP Libのバージョン self._oc.version() # VCP SDKのバージョン print( """ vcpsdk: filename: {filename} version: {version}""".format( filename=__file__, version=VCP_SDK_VERSION ) ) # plugin のバージョン print( """ plugin: aws: {aws} aws_disk: {aws_disk} aws_spot: {aws_spot} azure: {azure} vmware: {vmware} azure_disk: {azure_disk} sakura: {sakura} sakura_disk: {sakura_disk} oracle: {oracle} oracle_disk: {oracle_disk} proxmox: {proxmox} mdx2: {mdx2} mdx2_disk: {mdx2_disk} aic: {aic} abc: {abc} hokudai: {hokudai} chameleon: {chameleon} chameleon_ext: {chameleon_ext} gcp: {gcp} onpremises: {onpremises}""".format( aws=VcpSpecResourceAws.version, aws_disk=VcpSpecResourceAwsDisk.version, aws_spot=VcpSpecResourceAwsSpot.version, azure=VcpSpecResourceAzure.version, azure_disk=VcpSpecResourceAzureDisk.version, vmware=VcpSpecResourceVmware.version, sakura=VcpSpecResourceSakura.version, sakura_disk=VcpSpecResourceSakuraDisk.version, oracle=VcpSpecResourceOracle.version, oracle_disk=VcpSpecResourceOracleDisk.version, proxmox=VcpSpecResourceProxmox.version, aic=VcpSpecResourceAic.version, abc=VcpSpecResourceAbc.version, hokudai=VcpSpecResourceHokudai.version, mdx2=VcpSpecResourceMdx2.version, mdx2_disk=VcpSpecResourceMdx2Disk.version, gcp=VcpSpecResourceGcp.version, onpremises=VcpSpecResourceOnpremises.version, chameleon=VcpSpecResourceChameleon.version, chameleon_ext=VcpExtResourceChameleon.version, ) ) # VCC情報 wait_timeout_sec = "1000(default 15min)" if "wait_timeout_sec" in self._vcp_config["vcc"]: wait_timeout_sec = self._vcp_config["vcc"]["wait_timeout_sec"] print( """ vc_controller: host: {host} name: {name} wait_timeout_sec: {wait_timeout_sec}""".format( host=self._vcp_config["vcc"]["host"], name=self._vcp_config["vcc"]["name"], wait_timeout_sec=wait_timeout_sec, ), end="", ) # VC Controllerのバージョン occtr_version = self._oc.occtr_version() print( """ vc_controller: {occtr_version} vc_controller_git_tag: {git_tag}""".format( occtr_version=occtr_version["version"], git_tag=occtr_version["git_tag"] ) ) # VC Controllerのpluginバージョン print( """ plugin:""", end="", ) for name, version in occtr_version["plugin"].items(): print( """ {name}: {version}""".format( name=name, version=version ), end="", )
[ドキュメント] def version_dict(self) -> dict: """ VCP Libのバージョン出力(dict) """ sdk_plugins = dict( aws=VcpSpecResourceAws.version, aws_disk=VcpSpecResourceAwsDisk.version, aws_spot=VcpSpecResourceAwsSpot.version, azure=VcpSpecResourceAzure.version, azure_disk=VcpSpecResourceAzureDisk.version, vmware=VcpSpecResourceVmware.version, sakura=VcpSpecResourceSakura.version, sakura_disk=VcpSpecResourceSakuraDisk.version, oracle=VcpSpecResourceOracle.version, oracle_disk=VcpSpecResourceOracleDisk.version, proxmox=VcpSpecResourceProxmox.version, aic=VcpSpecResourceAic.version, abc=VcpSpecResourceAbc.version, hokudai=VcpSpecResourceHokudai.version, mdx2=VcpSpecResourceMdx2.version, mdx2_disk=VcpSpecResourceMdx2Disk.version, gcp=VcpSpecResourceGcp.version, onpremises=VcpSpecResourceOnpremises.version, chameleon=VcpSpecResourceChameleon.version, chameleon_ext=VcpExtResourceChameleon.version, ) vcpsdk = dict( filename=__file__, version=VCP_SDK_VERSION, plugin=sdk_plugins, ) occtr_version = self._oc.occtr_version() vc_controller = dict( host=self._vcp_config["vcc"]["host"], name=self._vcp_config["vcc"]["name"], wait_timeout_sec=self._vcp_config["vcc"].get("wait_timeout_sec", "1000(default 15min)"), version=occtr_version["version"], git_tag=occtr_version["git_tag"], plugin=occtr_version["plugin"], ) return dict( vcplib=self._oc.version(output=False), vcpsdk=vcpsdk, vc_controller=vc_controller, )
[ドキュメント] def df_flavors(self, provider_name): """ flavor定義の一覧(DataFrame形式) :param provider_name: 表示対象とするプロバイダ名 """ LABEL_FLAVOR = "flavor" flavors = VcpConfigYaml(self._config_dir).load_config("vcp_flavor") df = pd.json_normalize( [ {LABEL_FLAVOR: flavor, **params} for flavor, params in flavors[provider_name].items() ] ) columns = df.columns.tolist() columns.remove(LABEL_FLAVOR) columns.insert(0, LABEL_FLAVOR) return df.loc[:, columns]
[ドキュメント] def vcc_info(self): """ VC Controllerに関する情報の取得 :return: VCCに関する情報 結果サンプル .. code-block:: none { { "host": "10.0.0.1:443" }, { "vault_url": "https://10.0.0.1:8443" }, { "docker_registry": { "official": "10.0.0.1:5000", "user": "10.0.0.1:5001" } } """ loader = VcpConfigYaml(self._config_dir) config = loader.load("vcp_config") # VCコントローラ vcc_host = config["vcc"]["host"] vcc_port = 443 # default if "vcc_port" in config["vcc"]: vcc_port = "{}:{}".format(vcc_host, config["vcc"]["vcc_port"]) # Vault vault_port = 8443 # default if "vault_port" in config["vcc"]: vault_port = config["vcc"]["vault_port"] # docker registry private_ip = vcc_host # default if "private_ip" in config["vcc"]: private_ip = config["vcc"]["private_ip"] # 必要な情報は随時追加する return { "host": "{}:{}".format(vcc_host, vcc_port), "vault_url": "{}://{}:{}".format(VCP_VAULT_SCHEME, vcc_host, vault_port), "docker_registry": { "official": "{}:5000".format(private_ip), "user": "{}:5001".format(private_ip), }, }
[ドキュメント] def get_vpn_catalog(self, provider=None, vpn_catalog_name="default"): """ VC Controller からVPNカタログ情報を取得する :param provider: プロバイダ名 :param vpn_catalog_name: VPNカタログ名 :return: vpnカタログ情報 """ return self._oc.vpn_catalog(provider, vpn_catalog_name=vpn_catalog_name)
[ドキュメント] def get_publickey(self): """ 既存サーバ用 ssh 公開鍵取得 :return: ssh 公開鍵文字列 """ return self._oc.publickey()