概要
TDVサーバー1台の中で開発環境と本番環境を運用する方法について説明します。
本番環境は開発環境に追従する形で運用されます。
デバッグ用のフォルダで行った修正を手作業で本番環境に移行すると手間が増え、修正ミスが起こりえます。
本記事ではTDVで標準で公開されているユーザーの作成したビューの一覧を保持するデータサービスとビューのクエリを更新するAPIを用いて機械的に本番環境を更新する方法について説明します。
検証環境
製品 | バージョン | 備考 |
---|---|---|
TDV Server |
8.5.4 |
Windows Server 2019環境で実行 |
TDV Studio | ||
Python |
3.8.0 |
|
前提
本記事における手順は以下を前提とします。
- 本番環境対象のフォルダが用意されている。
- 本番環境対象フォルダと同じ構成の開発用のフォルダが存在する。
- 本番環境への変更の反映は構成はスクリプトベースである。
- 本記事ではPythonを使用しています。APIリクエストとJDBC接続が可能であれば他の言語でも代用可能です
手順
0. 本番運用TDVの構成の確認
デバッグ用のフォルダを「Dev」、本番用のフォルダを「Prod」としています。
「Dev」で変更した内容を「Prod」に反映させます。
1. 本番環境に存在するテーブル情報の取得
TDVは標準で作成したビュー情報を持つテーブルをデータベースとして公開しています。
「コンポジットサービス」→「データサービス」→「system」→「model」→「ALL_TABLES」に公開されています。
このテーブル情報をJDBC接続で取得します。Pythonを用いたJDBC接続の詳しい方法は以下を参照ください。
Javaの実行環境の設定とJDBCドライバの配置は必須です。
本記事でのPythonプロジェクトの構成は以下の通りです。
TDV内で作成された全てのビューを取得します。(get_models_from_data_service.pyは2章に続きます。)
スクリプト内のユーザー名、パスワード、IPアドレスは*でマスクされています。
# get_models_from_data_service.py
import jaydebeapi
import pandas as pd
def get_paths():
#接続情報
url = "jdbc:compositesw:dbapi@**.***.***.****:9401?domain=composite&dataSource=/services/databases/system"
driver = 'cs.jdbc.driver.CompositeDriver'
user = "*****"
password = "******"
jarfile = 'csjdbc.jar'
conn = jaydebeapi.connect(driver, url, [user, password], jarfile)
# テーブル全ての情報を取得
sqlData = "SELECT * from model.ALL_TABLES"
df = pd.io.sql.read_sql(sqlData, conn)
2. 「Dev」フォルダに格納されているビューのみを取得
「Dev」フォルダに格納されているビュー情報のみを選択。また、今回はビューのみを対象とするためデータソースの情報も除外している。(get_models_from_data_service.pyは完成です。)
# get_models_from_data_service.py
import jaydebeapi
import pandas as pd
def get_paths():
#接続情報
url = "jdbc:compositesw:dbapi@**.***.***.****:9401?domain=composite&dataSource=/services/databases/system"
driver = 'cs.jdbc.driver.CompositeDriver'
user = "*****"
password = "******"
jarfile = 'csjdbc.jar'
conn = jaydebeapi.connect(driver, url, [user, password], jarfile)
# テーブル全ての情報を取得
sqlData = "SELECT * from model.ALL_TABLES"
df = pd.io.sql.read_sql(sqlData, conn)
# /dev/をPathに含む行を抽出
tmp = df[df['PARENT_PATH'].str.contains('/Dev/')]
# 「Data Source」を含むものは除外。
result = tmp[~tmp['PARENT_PATH'].str.contains('Data Source')]
return result
3. TDV標準のAPIを用いてビューの詳細情報(SQLのクエリ)を取得
TDVではビューのパスを引数としてビューの詳細情報を取得することができます。
また、TDV Studioの「ヘルプ」タブから「REST APIリファレンス」を開くことでAPIを試し打ちすることもできます。今回使用するAPIは「DataView」欄にあります。
「Dev」で修正したクエリ内容を取得します。(api_from_TDV.pyは4章に続きます。)
# api_from_TDV.py
import requests
import json
import time
def one_model_update(table_path):
## 固定値
table_path = table_path
# TDV認証用のユーザー名とパスワード
user_name = "*****"
password = "********"
url_header = 'http://**.***.**.***:9400/rest/dataview/v1'
# Devの情報を取得
r = requests.get(f'{url_header}?path={table_path}&summary=false', auth=(user_name, password))
dev_table_information_json = r.json()
4. クエリ内容の変更
クエリの中で「Dev」を参照するものは「Prod」に変更します。(api_from_TDV.pyは5章に続きます。)
# api_from_TDV.py
import requests
import json
import time
def one_model_update(table_path):
## 固定値
table_path = table_path
# TDV認証用のユーザー名とパスワード
user_name = "*****"
password = "********"
url_header = 'http://**.***.**.***:9400/rest/dataview/v1'
# Devの情報を取得
r = requests.get(f'{url_header}?path={table_path}&summary=false', auth=(user_name, password))
dev_table_information_json = r.json()
# jsonを一度dict型に直してから/Dev/ -> /Prod/
# 変更される部分は"Parent_Path"とSQLの中身
_tmp_dict = json.dumps(dev_table_information_json)
_modified_dict = _tmp_dict.replace('/Dev/','/Prod/')
modifired_json = json.loads(_modified_dict)
5. 「Prod」のフォルダのビューを更新
4.で取得したクエリ内容でProdフォルダのビューを変更します。(api_from_TDV.pyは完成です。)
# api_from_TDV.py
import requests
import json
import time
def one_model_update(table_path):
## 固定値
table_path = table_path
# TDV認証用のユーザー名とパスワード
user_name = "*****"
password = "********"
url_header = 'http://**.***.**.***:9400/rest/dataview/v1'
# Devの情報を取得
r = requests.get(f'{url_header}?path={table_path}&summary=false', auth=(user_name, password))
dev_table_information_json = r.json()
# jsonを一度dict型に直してから/Dev/ -> /Prod/
# 変更される部分は"Parent_Path"とSQLの中身
_tmp_dict = json.dumps(dev_table_information_json)
_modified_dict = _tmp_dict.replace('/Dev/','/Prod/')
modifired_json = json.loads(_modified_dict)
# ProdでViewを更新(PUT)
# request body
headers={
'Content-type':'application/json',
}
tmp = {"parentPath":f"{modifired_json['PARENT_PATH']}", "name":f"{modifired_json['NAME']}", "sql": f"{modifired_json['properties'][-1][-1]}" }
r_put = requests.put(url_header, data=json.dumps([tmp]),auth=(user_name, password),headers=headers)
print(r_put.status_code)
time.sleep(1)
5. バッチ化
1. 2.で更新すべき対象のビューのPathをすべて取得。
3.4.はPathを引数にして一件のProdのビューのクエリ内容を更新する。
main.pyでは1.2.で取得したPathすべてに対して3.4.の処理を実行する。
import api_from_TDV
import get_models_from_data_service
def main():
df = get_models_from_data_service.get_paths()
# カラム名とインデックスをMap化
map_colmun_and_index = {}
for index, colmun in enumerate(df.columns, 0):
map_colmun_and_index[colmun] = index
# print(map_colmun_and_index)
# 更新するビューを1つずつループで処理
for row in df.values:
path = row[map_colmun_and_index["PARENT_PATH"]] + '/' + row[map_colmun_and_index["TABLE_NAME"]]
print(path)
# print(f"item:{row}")
api_from_TDV.one_model_update(path)
if __name__ == "__main__":
main()
6. 実行
以下のコマンドをコンソールで実行することで更新を行うことができます。
python main.py
実行例
一つのビューのクエリを変更したときの例示します。
以下のように同じ「Dev」と「Prod」で同じ内容のクエリがあります。同じ内容ですが、参照先が「Dev」と「Prod」というような違いがあります。
「Dev」のView
「Prod」のView
「Dev」のViewを
select *
から
select sample."年度"
に変更してみます。
ここで
python main.py
を実行することで参照先を「Prod」に保ちつつ、クエリの内容を変更することができました。
(スクリプト実行後、Studio上でビューが開いたままだと左上の緑の矢印ボタンから更新を行う必要があります)