3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オルトプラスAdvent Calendar 2023

Day 5

オルトプラスに入社してやったこと!!その1(PythonでTOMLを使うための仕組み)

Last updated at Posted at 2023-12-04

本記事は オルトプラス Advent Calendar 2023 の12/05の記事です。

はじめに

どうも!!オルトプラスの浦谷(urachooooooo)です

所属は技術部SREでテックスペシャリストとして横断的にデータベースを見ています!!
肩書きはエンジニアマネージャーですが生粋のDBAです!!

本記事ではPythonについて書いていきます。
それでは5日目のアドベントカレンダー開始しますー!!

概要

アジェンダとしては「PythonでTOMLを使うための仕組み」についてです。
こちらについてはサンプルスクリプトを使用して解説していきます。

詳細

オルトプラスに入社してからPythonを使用して色々と自動化したりツールを作成したりしているのですが、自分はPythonのコンフィグファイルにTOMLを使用することにしました!!

まずはじめにやったこととして「TOMLを読むための共通モジュールを作る」です。

この共通モジュールを使用することで以降作成するツールで使用することが可能です(楽したいですし💦)

TOMLを使用するためのシンプルなスクリプトを使用して解説していきます!!

その前にTOMLについて

TOMLは「Tom's Obvious Minimal Language」の略で、TOMLは設定ファイルのフォーマットの1つです。

TOMLのサイトでは下記の様に記載されています。

  • 人間用の設定ファイル形式(A config file format for humans.)
  • トムの明瞭で最小の言語(Tom's Obvious, Minimal Language.)

簡単に説明するとTOMLは

可読性が高く、様々なネイティブ型(Key/Value PairsやArrays)があり、様々な言語(PHPやPython)に対応しています

ソースコードについて

サンプルの「ソースコード構成」及び、「ソースコード内容」についてこちらに記載していきます。

ソースコード構成

「toml-config-display」はTOMLを実行するためのプロジェクト(ROOT)です。
下記の構成通りにサンプルスクリプトを配置することで今回説明する内容を再現することができます

  • ├── tcd_setup.py
    │
    └── toml-config-display
        ├── config
        │   ├── common.toml
        │   ├── tcd_general.toml
        │   └── tcd_tidb.toml
        ├── requirements.txt
        └── tomlcd
            ├── __init__.py
            ├── __main__.py
            ├── display_general_toml.py
            ├── display_tidb_toml.py
            └── libs
                ├── __init__.py
                ├── display_toolkit.py
                ├── tcd_config.py
                └── toml_toolkit.py
    

ソースコード内容

セットアップスクリプトは「tcd_setup.py」と「requirements.txt」になります

サンプルスクリプトは「config」・「libs」・「tomlcd」で構成されています。
尚、「tomlcd」がプロジェクトになります

setup

tcd_setup_py
  • tcd_setup.py
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    """
    GLOBAL変数初期化
    """
    # ライブラリインポート
    import os             # OS
    import sys            # SYS
    import textwrap       # ヒアドキュメント
    import inspect        # ファンクション名取得
    import pathlib        # touch
    
    # コンスタント
    TCD_BASE_PATH = os.path.abspath(".")
    TCD_PROJECT_PATH = os.path.join(TCD_BASE_PATH, "toml-config-display")
    TCD_CONFIG_PATH = os.path.join(TCD_PROJECT_PATH, "config")
    TCD_TOMLCD_PATH = os.path.join(TCD_PROJECT_PATH, "tomlcd")
    TCD_LIBS_PATH = os.path.join(TCD_TOMLCD_PATH, "libs")
    
    """
    tcd_setup.py
    --------------------------------------------------------
    toml-config-display(tcd)環境セットアップモジュール
    """
    
    def f_mkdir(in_args_dir_info):
        try:
            f_display_division("mkdir", "start")
            for dir_info in in_args_dir_info:
                print(dir_info)
                os.makedirs(dir_info, exist_ok=True)
            f_display_division("mkdir", "end")
            return True
    
        except:
            function_name = inspect.currentframe().f_code.co_name
            error_type, error_value, error_stacktrace = sys.exc_info()
            f_display_error(function_name, error_type, error_value, error_stacktrace)
            return False
    
    def f_file_touch(in_args_file_info):
        try:
            f_display_division("touch", "start")
            for file_fullpath in in_args_file_info:
                print(file_fullpath)
                file_info = pathlib.Path(file_fullpath)
                file_info.touch()
            f_display_division("touch", "end")
            return True
    
        except:
            function_name = inspect.currentframe().f_code.co_name
            error_type, error_value, error_stacktrace = sys.exc_info()
            f_display_error(function_name, error_type, error_value, error_stacktrace)
            return False
    
    def f_execute_confirmation(in_execute_message):
        # メッセージ設定
        enter_support_message = textwrap.dedent('''
        {execute_message}
        Please enter 'yes' or 'no' [y/N]: 
        ''').format(execute_message=in_execute_message).strip()
    
        try:
            while True:
                choice = input(enter_support_message).lower()
                if choice in ["y", "yes"]:
                    return True
                elif choice in ["n", "no"]:
                    return False
        except:
            function_name = inspect.currentframe().f_code.co_name
            error_type, error_value, error_stacktrace = sys.exc_info()
            f_display_error(function_name, error_type, error_value, error_stacktrace)
            return False
    
    def f_display_division(in_action_type, in_division_type):
        if in_division_type == "start":
            start_message = textwrap.dedent('''
            [{action_type}]
            +---------------------------------------------------------------------------------+
            ''').format(action_type=in_action_type).strip()
            print(start_message)
        
        elif in_division_type == "end":
            end_message = textwrap.dedent('''
            +---------------------------------------------------------------------------------+
            ''').strip()
            print("{} {}".format(end_message, "\n"))
    
    def f_display_error(in_function_name, in_error_type, in_error_value, in_error_stacktrace):
        # エラー情報設定
        error_message = textwrap.dedent('''
        [{function_name}]
        +---------------------------------------------------------------------------------+
            error_type  :
              {error_type}
        
            error_value :
              {error_value}
    
            error_stacktrace :
              {error_stacktrace}
        +---------------------------------------------------------------------------------+
        ''').format(function_name=in_function_name, error_type=in_error_type, error_value=in_error_value, error_stacktrace=in_error_stacktrace).strip()
    
        # エラー情報表示
        print("{} {}".format(error_message, "\n"))
    
    def f_display_finish_message(in_message):
        # メッセージ設定
        finish_message = textwrap.dedent('''
        ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆
            {message} have been completed !!!
        ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆
        ''').format(message=in_message)
        print("{}".format(finish_message, "\n"))
    
    def f_create_template():
        ########################
        # ディレクトリ作成
        ########################
        args_dir_info = []
        args_dir_info.extend([TCD_CONFIG_PATH, TCD_LIBS_PATH])
        """ f_mkdir """
        result = f_mkdir(args_dir_info)
        if result == True:
            ########################
            # 空ファイル作成
            ########################
            args_file_info = []
            args_file_info.extend([os.path.join(TCD_CONFIG_PATH, "common.toml"), 
                                   os.path.join(TCD_CONFIG_PATH, "tcd_general.toml"),
                                   os.path.join(TCD_CONFIG_PATH, "tcd_tidb.toml"),
                                   os.path.join(TCD_TOMLCD_PATH, "__init__.py"),
                                   os.path.join(TCD_TOMLCD_PATH, "__main__.py"),
                                   os.path.join(TCD_TOMLCD_PATH, "display_general_toml.py"),
                                   os.path.join(TCD_TOMLCD_PATH, "display_tidb_toml.py"),
                                   os.path.join(TCD_LIBS_PATH, "__init__.py"),
                                   os.path.join(TCD_LIBS_PATH, "display_toolkit.py"),
                                   os.path.join(TCD_LIBS_PATH, "tcd_config.py"),
                                   os.path.join(TCD_LIBS_PATH, "toml_toolkit.py"),
                                   os.path.join(TCD_PROJECT_PATH, "requirements.txt")])
    
            """ f_file_touch """
            result = f_file_touch(args_file_info)
            if result == True:
                """ f_display_finish_message """
                f_display_finish_message("{}".format("tcd_setup"))
    
    def f_main():
        tcd_setup_message = textwrap.dedent('''
        +---------------------------------------------------------------------------------+
          スクリプト実行パス「{tcd_base_path}」配下に
          TOML動作確認用の環境を構築します
          よろしいでしょうか?                                           
          
          ※パーミッションが有効でない場合はエラーになります
        +---------------------------------------------------------------------------------+
        ''').format(tcd_base_path=TCD_BASE_PATH).strip()
        result = f_execute_confirmation(tcd_setup_message)
        if result == True:
            """ f_create_template """
            f_create_template()
    
    """
    main
    """
    if __name__ == '__main__':
        f_main()
    
requirements_txt
  • requirements.txt
    toml==0.10.2
    

config

TOMLフォーマットの設定ファイルです

  • common.toml
    • 便宜上分けています(今回のプロジェクト以外でも使用可能なパラメータのため)
    • 表示では使用しません(判定で使用)
        
  • tcd_general.toml
    • Key-Valueの最もシンプルな構成
    • このTOMLの内容を表示します
        
  • tcd_tidb.toml
    • TiDBの「Server recommendations」をベースとした階層と配列を含んだ構成
    • このTOMLの内容を表示します

TOMLの記述について

  • テーブル(TABLE)
    • パラメータのカテゴリーとして分けている「[]」で囲われている値は「テーブル」と呼ばれています
      • 例えば「common.toml」の「[environment_info]」はテーブルであり、「tcd_general.toml」の「[setup_info]」もテーブルです
          
  • キー(KEY)
    • 値を検索するためのキー
      • 例えば「common.toml」の「ENVIRONMENT_LIST」はキーであり、「tcd_general.toml」の「TCD_ROOT_DIR」や「TCD_CONFIG_DIR」もキーです
          
  • 値(VALUE)
    • キーに対する値
      • 例えば、「common.toml」の「['development', 'production']」は値で、「tcd_general.toml」の「"toml-config-display"」や「"config"」も値です
common_toml
  • common.toml
    [environment_info]
    ENVIRONMENT_LIST  = ['development', 'production']
    
tcd_general_toml
  • tcd_general.toml
    [setup_info]
    TCD_ROOT_DIR = "toml-config-display"
    TCD_CONFIG_DIR = "config"
    TCD_SCRIPT_DIR = "tomlcd"
    TCD_LIBS_DIR = "libs"
    
    [config_info]
    TCD_GENERAL_TOML = "tcd_general.toml"
    TCD_TIDB_TOML = "tcd_tidb.toml"
    
    [libs_info]
    TCD_CONFIG_PY = "tcd_config.py"
    TOML_TOOLKIT_PY = "toml_toolkit.py"
    DISPLAY_TOOLKIT_PY = "display_toolkit.py"
    
    [script_info]
    DISPLAY_GENERAL_TOML_PY = "display_general_toml.py"
    DISPLAY_TIDB_TOML_PY = "display_tidb_toml.py"
    
tcd_tidb_toml
  • tcd_tidb.toml
    [development]
        [development.tidb_cluster]
        INSTANCE_TYPE = "t4g.2xlarge"
        RESOURCE.CPU = "8 core+"
        RESOURCE.MEMORY = "16 GB+"
        RESOURCE.STORAGE = "No special requirements"
        RESOURCE.NETWORK = "Gigabit network card"
        RESOURCE.MINIMUM_REQUIREMENT = 1
        SERVER_LIST = [
            "tidb-server-01"
        ]
    
        [development.pd_cluster]
        INSTANCE_TYPE = "t4g.xlarge"
        RESOURCE.CPU = "4 core+"
        RESOURCE.MEMORY = "8 GB+"
        RESOURCE.STORAGE = "SAS, 200 GB+"
        RESOURCE.NETWORK = "Gigabit network card"
        RESOURCE.MINIMUM_REQUIREMENT = 1
        SERVER_LIST = [
            "pd-server-01"
        ]
    
        [development.tikv_cluster]
        INSTANCE_TYPE = "i4g.2xlarge"
        RESOURCE.CPU = "8 core+"
        RESOURCE.MEMORY = "32 GB+"
        RESOURCE.STORAGE = "SAS, 200 GB+"
        RESOURCE.NETWORK = "Gigabit network card"
        RESOURCE.MINIMUM_REQUIREMENT = 3
        SERVER_LIST = [
            "tikv-server-01", 
            "tikv-server-02",
            "tikv-server-03"
        ]
        
    [production]
        [production.tidb_cluster]
        INSTANCE_TYPE = "Im4gn.4xlarge"
        RESOURCE.CPU = "16 core+"
        RESOURCE.MEMORY = "48 GB+"
        RESOURCE.STORAGE = "SSD"
        RESOURCE.NETWORK = "10 Gigabit network card (2 preferred)"
        RESOURCE.MINIMUM_REQUIREMENT = 2
        SERVER_LIST = [
            "tidb-server-01", 
            "tidb-server-02"
        ]
    
        [production.pd_cluster]
        INSTANCE_TYPE = "Im4gn.2xlarge"
        RESOURCE.CPU = "8 core+"
        RESOURCE.MEMORY = "16 GB+"
        RESOURCE.STORAGE = "SSD"
        RESOURCE.NETWORK = "10 Gigabit network card (2 preferred)"
        RESOURCE.MINIMUM_REQUIREMENT = 3
        SERVER_LIST = [
            "pd-server-01", 
            "pd-server-02",
            "pd-server-03"
        ]
    
        [production.tikv_cluster]
        INSTANCE_TYPE = "i4g.4xlarge"
        RESOURCE.CPU = "16 core+"
        RESOURCE.MEMORY = "64 GB+"
        RESOURCE.STORAGE = "SSD"
        RESOURCE.NETWORK = "10 Gigabit network card (2 preferred)"
        RESOURCE.MINIMUM_REQUIREMENT = 3
        SERVER_LIST = [
            "tikv-server-01", 
            "tikv-server-02",
            "tikv-server-03"
        ]
    
        [production.tiflash_cluster]
        INSTANCE_TYPE = "i4g.16xlarge"
        RESOURCE.CPU = "48 core+"
        RESOURCE.MEMORY = "128 GB+"
        RESOURCE.STORAGE = "1 or more SSDs"
        RESOURCE.NETWORK = "10 Gigabit network card (2 preferred)"
        RESOURCE.MINIMUM_REQUIREMENT = 2
        SERVER_LIST = [
            "tiflash-server-01", 
            "tiflash-server-02"
        ]
    
        [production.monitor]
        INSTANCE_TYPE = "t4g.2xlarge"
        RESOURCE.CPU = "8 core+"
        RESOURCE.MEMORY = "16 GB+"
        RESOURCE.STORAGE = "SAS"
        RESOURCE.NETWORK = "Gigabit network card"
        RESOURCE.MINIMUM_REQUIREMENT = 1
        SERVER_LIST = [
            "monitor-server-01"
        ]
    

libs

toml-config-displayで使用するPythonのモジュールです

  • toml_toolkit.py
    • TOMLを読み込むための共通モジュール
        
  • tcd_config.py
    • 「toml_toolkit.py」を使用してTOMLファイルの読み込み及び、設定ファイル用に加工するためのモジュール
        
  • display_toolkit.py
    • 表示用の共通モジュール
toml_toolkit_py
  • toml_toolkit.py
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    """
    GLOBAL変数初期化
    """
    # ライブラリインポート
    import toml           # TOML
    
    """
    toml_toolkit.py
    --------------------------------------------------------
    TOML共通モジュール
    """
    def f_read_toml(in_toml_path, in_key):
        with open(in_toml_path, "r") as file:
            ret_value = toml.load(file)
            if in_key != None:
                ret_value = ret_value[in_key]
        return ret_value
    
    def f_get_toml_table(in_toml_path, in_key):
        toml_object = f_read_toml(in_toml_path, in_key)
        ret_value = []
        for key in toml_object.keys():
            if isinstance(toml_object[key], dict):
                ret_value.append(key)
        return ret_value
    
    def f_search_toml(in_toml_object, in_toml_table, in_toml_key):
        ret_value = in_toml_object[in_toml_table][in_toml_key]
        return ret_value
    
tcd_config_py
  • tcd_config.py
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    """
    GLOBAL変数初期化
    """
    # ライブラリインポート
    import os                # OS
    import libs.toml_toolkit as toml_toolkit
    
    # コンスタント
    TCD_BASE_PATH = os.path.abspath("..")
    TCD_CONFIG_PATH = os.path.join(TCD_BASE_PATH, "config")
    COMMON_TOML_PATH = os.path.join(TCD_CONFIG_PATH, "common.toml")
    TCD_GENERAL_TOML_PATH = os.path.join(TCD_CONFIG_PATH, "tcd_general.toml")
    TCD_TIDB_TOML_PATH = os.path.join(TCD_CONFIG_PATH, "tcd_tidb.toml")
    
    """
    tcd_config.py
    --------------------------------------------------------
    tomlパラメータ設定モジュール
    """
    
    class CommonToml:
        def __init__(self):
            self.environment_list = None
    
        def read_toml(self):
            common_toml = toml_toolkit.f_read_toml(COMMON_TOML_PATH, None)
            # [environment_info]
            self.environment_list = toml_toolkit.f_search_toml(common_toml, "environment_info", "ENVIRONMENT_LIST")
    
    class GeneralToml:
        def __init__(self):
            self.tcd_root_dir = None
            self.tcd_config_dir = None
            self.tcd_script_dir = None
            self.tcd_libs_dir = None
            self.tcd_general_toml = None
            self.tcd_tidb_toml = None
            self.display_general_toml_py = None
            self.display_tidb_toml_py = None
            self.tcd_config_py = None
            self.toml_toolkit_py = None
            self.display_toolkit_py = None
    
        def read_toml(self):
            self.tcd_base_path = TCD_BASE_PATH
            tcd_general_toml = toml_toolkit.f_read_toml(TCD_GENERAL_TOML_PATH, None)
    
            # [setup_info]
            self.tcd_root_dir = toml_toolkit.f_search_toml(tcd_general_toml, "setup_info", "TCD_ROOT_DIR")
            self.tcd_config_dir = toml_toolkit.f_search_toml(tcd_general_toml, "setup_info", "TCD_CONFIG_DIR")
            self.tcd_script_dir = toml_toolkit.f_search_toml(tcd_general_toml, "setup_info", "TCD_SCRIPT_DIR")
            self.tcd_libs_dir = toml_toolkit.f_search_toml(tcd_general_toml, "setup_info", "TCD_LIBS_DIR")
    
            # [config_info]
            self.tcd_general_toml = toml_toolkit.f_search_toml(tcd_general_toml, "config_info", "TCD_GENERAL_TOML")
            self.tcd_tidb_toml = toml_toolkit.f_search_toml(tcd_general_toml, "config_info", "TCD_TIDB_TOML")
    
            # [script_info]
            self.display_general_toml_py = toml_toolkit.f_search_toml(tcd_general_toml, "script_info", "DISPLAY_GENERAL_TOML_PY")
            self.display_tidb_toml_py = toml_toolkit.f_search_toml(tcd_general_toml, "script_info", "DISPLAY_TIDB_TOML_PY")
    
            # [libs_info]
            self.tcd_config_py = toml_toolkit.f_search_toml(tcd_general_toml, "libs_info", "TCD_CONFIG_PY")
            self.toml_toolkit_py = toml_toolkit.f_search_toml(tcd_general_toml, "libs_info", "TOML_TOOLKIT_PY")
            self.display_toolkit_py = toml_toolkit.f_search_toml(tcd_general_toml, "libs_info", "DISPLAY_TOOLKIT_PY")
    
            ##############################
            # カスタム設定
            ##############################
            self.args_path_list = []
            # configパス設定
            self.config_path = os.path.join(self.tcd_base_path, self.tcd_config_dir)
            self.tcd_general_toml_fullpath = os.path.join(self.config_path, self.tcd_general_toml)
            self.tcd_tidb_toml_fullpath = os.path.join(self.config_path, self.tcd_tidb_toml)
            self.args_path_list.append([self.tcd_config_dir, self.tcd_general_toml_fullpath, self.tcd_tidb_toml_fullpath])
        
            # scriptパス設定
            self.script_path = os.path.join(self.tcd_base_path, self.tcd_script_dir)
            self.display_general_toml_py_fullpath = os.path.join(self.script_path, self.display_general_toml_py)
            self.display_tidb_toml_py_fullpath = os.path.join(self.script_path, self.display_tidb_toml_py)
            self.args_path_list.append([self.tcd_script_dir, self.display_general_toml_py_fullpath, self.display_tidb_toml_py_fullpath])
    
            # libパス設定
            libs_path = os.path.join(self.script_path, self.tcd_libs_dir)
            self.tcd_config_py_fullpath = os.path.join(libs_path, self.tcd_config_py)
            self.toml_toolkit_py_fullpath = os.path.join(libs_path, self.toml_toolkit_py)
            self.display_toolkit_py_fullpath = os.path.join(libs_path, self.display_toolkit_py)
            self.args_path_list.append([self.tcd_libs_dir, self.tcd_config_py_fullpath, self.toml_toolkit_py_fullpath, self.display_toolkit_py_fullpath])
    
    class TidbToml:
        def __init__(self, in_environment_type, in_cluster_type):
            self.environment_type = in_environment_type
            self.cluster_type = in_cluster_type
            self.cpu = None
            self.memory = None
            self.storage = None
            self.network = None
            self.minimum_requirement = None
    
        def read_toml(self):
            tcd_tidb_toml = toml_toolkit.f_read_toml(TCD_TIDB_TOML_PATH, self.environment_type)
            self.instance_type = toml_toolkit.f_search_toml(tcd_tidb_toml, self.cluster_type, "INSTANCE_TYPE")
            result = toml_toolkit.f_search_toml(tcd_tidb_toml, self.cluster_type, "RESOURCE")
            self.cpu = result["CPU"]
            self.memory = result["MEMORY"]
            self.storage = result["STORAGE"]
            self.network = result["NETWORK"]
            self.minimum_requirement = result["MINIMUM_REQUIREMENT"]
    
        def get_toml_table(self):
            result = toml_toolkit.f_get_toml_table(TCD_TIDB_TOML_PATH, self.environment_type)
            return result
    
display_toolkit_py
  • display_toolkit.py
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    """
    GLOBAL変数初期化
    """
    # ライブラリインポート
    import textwrap       # ヒアドキュメント
    
    """
    display_toolkit.py
    --------------------------------------------------------
    表示用共通モジュール
    """
    def f_display_argument_error(in_item_name, in_argument, in_argument_list):
        environment_errorr_message = textwrap.dedent('''
        [{item_name}エラー]
        +---------------------------------------------------------------------------------+
          {item_name}に「{argument}」が設定されています。
          
          パラメータ「{item_name}」は
          {argument_list}
          を設定してください
        +---------------------------------------------------------------------------------+
        ''').format(item_name=in_item_name, argument=in_argument, argument_list=in_argument_list).strip()
        print("{} {}".format(environment_errorr_message, "\n"))
    
    def f_display_division(in_action_type, in_division_type, in_finish):
        if in_division_type == "start":
            start_message = textwrap.dedent('''
            [{action_type}]
            +---------------------------------------------------------------------------------+
            ''').format(action_type=in_action_type).strip()
            print(start_message)
        
        elif in_division_type == "finish":
            finish_message = textwrap.dedent('''
            {finish}
            +---------------------------------------------------------------------------------+
            ''').format(finish=in_finish).strip()
            print("{} {}".format(finish_message, "\n"))
    

tomlcd

TOMLを表示するためのPythonのメインモジュールです

display_general_toml_py
  • display_general_toml.py
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    """
    GLOBAL変数初期化
    """
    # ライブラリインポート
    import inspect           # ファンクション名取得
    import libs.tcd_config as tcd_config
    import libs.display_toolkit as display_toolkit
    
    """
    display_general_toml.py
    --------------------------------------------------------
    「tdc_general.toml」表示モジュール
    """
    
    # config read
    tcd_general_toml = tcd_config.GeneralToml()
    tcd_general_toml.read_toml()
    
    def f_display_general_toml_01():
        function_name = inspect.currentframe().f_code.co_name
        """ f_display_division """
        display_toolkit.f_display_division(function_name, "start", "")
    
        print("[{}]".format(tcd_general_toml.tcd_config_dir))
        print(tcd_general_toml.tcd_general_toml_fullpath)
        print(tcd_general_toml.tcd_tidb_toml_fullpath)
    
        print("[{}]".format(tcd_general_toml.tcd_script_dir))
        print(tcd_general_toml.display_general_toml_py_fullpath)
        print(tcd_general_toml.display_tidb_toml_py_fullpath)
    
        print("[{}]".format(tcd_general_toml.tcd_libs_dir))
        print(tcd_general_toml.tcd_config_py_fullpath)
        print(tcd_general_toml.toml_toolkit_py_fullpath)
        print(tcd_general_toml.display_toolkit_py_fullpath)
    
        """ f_display_division """
        display_toolkit.f_display_division(function_name, "finish", "")
    
    def f_display_general_toml_02():
        function_name = inspect.currentframe().f_code.co_name
        """ f_display_division """
        display_toolkit.f_display_division(function_name, "start", "")
    
        print("{}".format(inspect.currentframe().f_code.co_name))
        for args_path_list in tcd_general_toml.args_path_list:
            print("[{}]".format(args_path_list[0]))
            for path_info in args_path_list[1:]:
                print(path_info)
    
        """ f_display_division """
        display_toolkit.f_display_division(function_name, "finish", "")
    
    def f_main():
        """ f_display_general_toml_01 """
        f_display_general_toml_01()
    
        """ f_display_general_toml_02 """
        f_display_general_toml_02()
    
    """
    main
    """
    if __name__ == '__main__':
        f_main()
    
display_tidb_toml_py
  • display_tidb_toml.py
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    """
    GLOBAL変数初期化
    """
    # ライブラリインポート
    import sys            # SYS
    import textwrap       # ヒアドキュメント
    import libs.tcd_config as tcd_config
    import libs.display_toolkit as display_toolkit
    
    """
    display_tidb_toml.py
    --------------------------------------------------------
    「tdc_tidb.toml」表示モジュール
    """
    
    # config read
    common_toml = tcd_config.CommonToml()
    common_toml.read_toml()
    tcd_general_toml = tcd_config.GeneralToml()
    tcd_general_toml.read_toml()
    
    def f_check_argument(in_environment_list):
        # パラメータ設定
        in_args = sys.argv
        try:
            if len(in_args) == 3:
                return True, str(in_args[1]), str(in_args[2])
            else:
                raise argument_error
        except Exception as argument_error:
            error_message = textwrap.dedent('''
            パラメータの設定は下記の通り設定してください
            +---------------------------------------------------------------------------------+
              第1パラメータに「環境のタイプ」
              第2パラメータに「クラスタータイプ」を設定してください
            
              環境のタイプ    : {nvironment_list}
              クラスタータイプ : 
                「ALL」を入力すると「環境のタイプ」に関連する全てのクラスターが表示されます
            +---------------------------------------------------------------------------------+
            ''').format(nvironment_list=in_environment_list).strip()
            print("{} {}".format(error_message, "\n"))
            return False, None
    
    def f_display_cluster_info(in_environment_type, in_cluster_type):
        tcd_tidb_toml = tcd_config.TidbToml(in_environment_type, in_cluster_type)
        tcd_tidb_toml.read_toml()
    
        environment_message = textwrap.dedent('''
        [{cluster_type}]
        +---------------------------------------------------------------------------------+
          Instance Type: {instance_type}
          CPU     : {cpu}
          Memory  : {memory}
          Storage : {storage}
          Network : {network}                       
          Number of Instances(Minimum Requirement) : {minimum_requirement}
        +---------------------------------------------------------------------------------+
        ''').format(cluster_type=in_cluster_type, instance_type=tcd_tidb_toml.instance_type, 
                    cpu=tcd_tidb_toml.cpu, memory=tcd_tidb_toml.memory, 
                    storage=tcd_tidb_toml.storage, network=tcd_tidb_toml.network, 
                    minimum_requirement=tcd_tidb_toml.minimum_requirement).strip()
        print("{} {}".format(environment_message, "\n"))
    
    def f_main():
        """ f_check_param """
        result = f_check_argument(common_toml.environment_list)
        if result[0] == True:
            environment_type, cluster_type = result[1], result[2]
        else:
            sys.exit()
    
        if environment_type in common_toml.environment_list:
            tcd_tidb_toml = tcd_config.TidbToml(environment_type, None)
            component_list = tcd_tidb_toml.get_toml_table()
    
            if cluster_type in component_list or cluster_type.upper() == "ALL":
         
                if cluster_type.upper() == "ALL":
                    for cluster_name in component_list:
                        """ f_display_cluster_info """
                        f_display_cluster_info(environment_type, cluster_name)
                else:
                    """ f_display_cluster_info """
                    f_display_cluster_info(environment_type, cluster_type)
                    
            else:
                """ f_display_argument_error """
                display_toolkit.f_display_argument_error("cluster_type", cluster_type, component_list)
    
        else:
            """ f_display_argument_error """
            display_toolkit.f_display_argument_error("environment_type", environment_type, common_toml.environment_list)
    
    """
    main
    """
    if __name__ == '__main__':
        f_main()
    

セットアップ手順

上記サンプルスクリプトをセットアップして実行するまでの手順を記載していきます

環境について

スクリプトを確認した環境は下記になります。
尚、今回使用した環境はMacになりますが、環境に依存しない作りにしているため異なる環境(例えばWindows)でもスクリプトは動くかと思います

  • MacBook Pro(Apple M2)
    • macOS Ventura(13.5.2)
  • Pythonのバージョン(3.11.4)

仮想環境準備

必要に応じて下記をインストールしてください
今回の記事で「pyenv」や「virtualenv」のインストール及び、設定に関して記載するかどうか?迷ったのですが、今回はそこまでは記載しないことにします。

  • pyenv
    • Pythonのバージョンを固定する場合
  • virtualenv
    • 環境汚染を防止する場合
    • Pythonモジュールのバージョンを固定する場合

事前準備

ソースコード公開用のGitHubを用意してcloneする方が導入が楽なのですが、お手数ですが各スクリプトをコピーして試していただければと思います。

スクリプトの配置やPythonモジュール(TOML)をセットアップします

  • スクリプトの配置について
    • セットアップスクリプトも準備していますので、手順に沿って実施ください。
        
  • Pythonモジュールのインストールについて
    • requirements.txtには今回使用したバージョンが記載されていますが、必要に応じて最新のバージョンをインストールことも可能です。
      python3 -m pip install toml
      
  1. スクリプトを配置
    下記のステップを実施してください
    a. 環境構築するディレクトリに移動して「tcd_setup.py」を作成
    b. 「tcd_setup.py」モジュールを実行
    python3 -m tcd_setup
    
    c. 「ソースコード構成」と同じ構成であることを確認
    d. 「ソースコード内容」のソースコードを作成ファイルに登録
     
  2. Pythonモジュールをインストール
    a. Pythonモジュールのインストール状況を確認
    pip3 freeze | grep toml
    
    b.「toml-config-display」ディレクトリに移動
    c. Pythonモジュールをインストール
    pip3 install -r requirements.txt
    

スクリプト実行

各スクリプトを実行後にTOMLの情報を取得して表示します

  • display_general_toml.py
    • tcd_general.toml」のデータを表示します
    • テーブルによる階層がないため値の取得方法を変化させました
      出力結果は同じですが実行しているファンクションを分けています
      • f_display_general_toml_01
        • TOMLの値を個別で表示
      • f_display_general_toml_02
        • TOMLの値を配列に格納してLOOPで表示
            
  • display_tidb_toml.py
    • tcd_tidb.toml」のデータを表示します
    • テーブル毎に階層を分けているため入力パラメータによって様々な条件でTOMLの内容を表示しています
      • 例)development、production、tidb_cluster、etc.
    • スクリプトの入力パラメータ
      • 第1パラメータ:development、production
      • 第2パラメータ:tidb_cluster、ALL、etc.
    • スクリプトの入力パラメータがあるため入力チェックを行います
    • スクリプトの入力チェックにはTOMLのテーブルのリストを評価しています。そのため設定パラメータによって評価の対象も動的に変化する仕組みになっています
      • 例)development、productionの階層に「staging、test、etc.」を追加するとチェック対象が自動で増えます
  1. スクリプトのプロジェクトパス(「tomlcd」)へ移動
  2. スクリプト実行
  • display_general_toml.py」を実行
    • コマンド
      python3 -m display_general_toml
      
    • 結果
      [f_display_general_toml_01]
      +---------------------------------------------------------------------------------+
      [config]
      /opt/alt/toml-config-display/config/tcd_general.toml
      /opt/alt/toml-config-display/config/tcd_tidb.toml
      [tomlcd]
      /opt/alt/toml-config-display/tomlcd/display_general_toml.py
      /opt/alt/toml-config-display/tomlcd/display_tidb_toml.py
      [libs]
      /opt/alt/toml-config-display/tomlcd/libs/tcd_config.py
      /opt/alt/toml-config-display/tomlcd/libs/toml_toolkit.py
      /opt/alt/toml-config-display/tomlcd/libs/display_toolkit.py
      +---------------------------------------------------------------------------------+ 
      
      [f_display_general_toml_02]
      +---------------------------------------------------------------------------------+
      f_display_general_toml_02
      [config]
      /opt/alt/toml-config-display/config/tcd_general.toml
      /opt/alt/toml-config-display/config/tcd_tidb.toml
      [tomlcd]
      /opt/alt/toml-config-display/tomlcd/display_general_toml.py
      /opt/alt/toml-config-display/tomlcd/display_tidb_toml.py
      [libs]
      /opt/alt/toml-config-display/tomlcd/libs/tcd_config.py
      /opt/alt/toml-config-display/tomlcd/libs/toml_toolkit.py
      /opt/alt/toml-config-display/tomlcd/libs/display_toolkit.py
      +---------------------------------------------------------------------------------+
      

  

  • display_tidb_toml.py」を実行
    こちらはいくつかのパターンがありますので例を表示します
    • 例)「tcd_tidb.toml」のテーブル「development」を全て表示する場合
      • コマンド
        python3 -m display_tidb_toml development ALL
        
      • 結果
        [tidb_cluster]
        +---------------------------------------------------------------------------------+
          Instance Type: t4g.2xlarge
          CPU     : 8 core+
          Memory  : 16 GB+
          Storage : No special requirements
          Network : Gigabit network card                       
          Number of Instances(Minimum Requirement) : 1
        +---------------------------------------------------------------------------------+ 
        
        [pd_cluster]
        +---------------------------------------------------------------------------------+
          Instance Type: t4g.xlarge
          CPU     : 4 core+
          Memory  : 8 GB+
          Storage : SAS, 200 GB+
          Network : Gigabit network card                       
          Number of Instances(Minimum Requirement) : 1
        +---------------------------------------------------------------------------------+ 
        
        [tikv_cluster]
        +---------------------------------------------------------------------------------+
          Instance Type: i4g.2xlarge
          CPU     : 8 core+
          Memory  : 32 GB+
          Storage : SAS, 200 GB+
          Network : Gigabit network card                       
          Number of Instances(Minimum Requirement) : 3
        +---------------------------------------------------------------------------------+
        
    • 例)「tcd_tidb.toml」のテーブル「development.tidb_cluster」を表示する場合
      • コマンド
        python3 -m display_tidb_toml development tidb_cluster
        
      • 結果
        [tidb_cluster]
        +---------------------------------------------------------------------------------+
          Instance Type: t4g.2xlarge
          CPU     : 8 core+
          Memory  : 16 GB+
          Storage : No special requirements
          Network : Gigabit network card                       
          Number of Instances(Minimum Requirement) : 1
        +---------------------------------------------------------------------------------+ 
        
    • 例)「tcd_tidb.toml」のテーブル「production.tikv_cluster」を表示する場合
      • コマンド
        python3 -m display_tidb_toml production tikv_cluster
        
      • 結果
        [tikv_cluster]
        +---------------------------------------------------------------------------------+
          Instance Type: i4g.4xlarge
          CPU     : 16 core+
          Memory  : 64 GB+
          Storage : SSD
          Network : 10 Gigabit network card (2 preferred)                       
          Number of Instances(Minimum Requirement) : 3
        +---------------------------------------------------------------------------------+
        

仕組みについての解説

tcd_general.toml」のデータを
display_general_toml.pyでどのように取得しているのか?を最後に解説しておきます

尚、取得対象はテーブル「setup_info」のキー「TCD_CONFIG_DIR」で値「"config"」を取得する例になります

データの流れ

display_general_toml実行の流れ.png

  • 上記イメージは「display_general_toml.py」を実行してから結果が表示されるまでの流れになります
    • スクリプトを実行
    • 番号の順番通りに遷移
    • 結果を表示
  • 色によって識別できるようにしています
    • 同色であれば参照先や関係は同じになります

解説

  • 上記スクリプト実行の流れを解説します
    1. display_general_toml.py」を実行
      • tcd_config.py」のClass「GeneralToml」をインスタンス化
    2. インスタンス化した「GeneralToml」の「read_toml」を実行
      • toml_toolkit.py」の「f_read_toml」を使用して
        tcd_general.toml」のデータを全件ロード
      • TABLE(setup_info)、KEY(TCD_CONFIG_DIR)
        からVALUE("config")を取得
    3. 「tcd_general_toml.tcd_root_dir」をprintすると
      値「"config"」が表示されます

まとめ

PythonでTOMLを使うための仕組みについて
どの様にTOMLのデータを取得しているのか?
サンプルスクリプトを使用して解説を行いました!!

今回公開しましたスクリプトは自由にお使いくださいませーー

スクリプトをそのまま使うでもよし!
自分達でもっと使いやすく修正して使うでもよし!!
今回載せたスクリプトが皆さんのお役に立てたら幸いです!!

また、Pythonで使用しないにせよ、
TOMLはシンプルで使いやすいのでお勧めですーー!!
様々な言語に対応していますので、
是非是非お使いくださいーー
(TOMLの回し者ではないですよw)

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?