Monte CarloとSnowflakeを接続する方法を紹介します。
Monte Carloとデータウェアハウスを接続すると、テーブルとパイプラインの状態を追跡できるようになります。メタデータ、クエリ ログ、メトリクスをウェアハウスから自動的に取得することで、データパイプラインの状態を可視化しています。
1. SnowflakeでMonte Carlo用のサービスアカウントを作成する
公式ドキュメントにある以下のクエリを実行すれば作成できます。
まず、下記クエリでこれ以降に使用するクエリの変数を定義します。ハイライトを入れている3行目と7行目はユーザー側で任意のパスワードとデータベース名を入力します。他にもユーザー名、ウェアハウス名、ロール名も任意の名前にしたい場合には=(イコール)の右側を書き換えます。
-- Configuration
set mc_username='MONTE_CARLO';
set mc_password='<monte_carlo_password>';
set mc_warehouse_size='XSMALL';
set mc_warehouse_name='MONTE_CARLO_WH';
set mc_role_name='MONTE_CARLO_ROLE';
set database_to_monitor='<your_database>';
パスワードとデータベースを入力したら、以下のクエリをすべて実行します。
-- 権限付与用にロールを設定
USE ROLE ACCOUNTADMIN;
-- Monte Carloのモニタリングワークロード用にウェアハウスを作成
CREATE WAREHOUSE IF NOT EXISTS identifier($mc_warehouse_name) WAREHOUSE_SIZE=$mc_warehouse_size INITIALLY_SUSPENDED=TRUE
AUTO_SUSPEND = 5 AUTO_RESUME = TRUE;
-- ユーザーMONTE_CARLOが使用するロールを作成
CREATE ROLE IF NOT EXISTS identifier($mc_role_name);
-- モンテカルロ用ユーザー(MONTE_CARLO)の作成と、ロール(MONTE_CARLO_ROLE)の付与
CREATE USER IF NOT EXISTS identifier($mc_username) PASSWORD=$mc_password DEFAULT_ROLE=$mc_role_name;
GRANT ROLE identifier($mc_role_name) TO USER identifier($mc_username);
-- 新たなウェアハウス(MONTE_CARLO_WH)を使用する権限を付与
GRANT OPERATE, USAGE, MONITOR ON WAREHOUSE identifier($mc_warehouse_name) TO ROLE identifier($mc_role_name);
-- クエリ履歴へのアクセス権を付与
GRANT IMPORTED PRIVILEGES ON DATABASE "SNOWFLAKE" TO ROLE identifier($mc_role_name);
-- モニター対象のデータベースおよびスキーマのメタデータにアクセスできる権限を付与
GRANT USAGE,MONITOR ON DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name);
GRANT USAGE,MONITOR ON ALL SCHEMAS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name);
-- スキーマにfuture grantsが付与されているかを確認 ※参考を参照
USE DATABASE identifier($database_to_monitor);
CREATE OR REPLACE PROCEDURE GRANT_REFERENCES_TO_MONTE_CARLO()
RETURNS VARCHAR
LANGUAGE javascript
EXECUTE AS CALLER
AS
$$
snowflake.createStatement({sqlText: `use database identifier($database_to_monitor)`}).execute();
var show_future_grants = snowflake.createStatement({sqlText: `SHOW FUTURE GRANTS IN DATABASE identifier($database_to_monitor)`}).execute();
var schema_future_grants = snowflake.createStatement({sqlText: `select * from TABLE(RESULT_SCAN('${show_future_grants.getQueryId()}')) where "grant_on" = 'SCHEMA'`}).execute();
if (schema_future_grants.getRowCount() > 0) {
var schemas_to_grant = snowflake.createStatement({ sqlText:`select * from information_schema.SCHEMATA where SCHEMA_NAME <> 'INFORMATION_SCHEMA'`}).execute();
var granted_schemas = "";
while(schemas_to_grant.next()) {
table_schema = schemas_to_grant.getColumnValue("SCHEMA_NAME");
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON ALL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON ALL VIEWS IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON ALL EXTERNAL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON FUTURE TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON FUTURE VIEWS IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON FUTURE EXTERNAL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute();
granted_schemas += table_schema + "; "
}
return `Granted references for schemas ${granted_schemas}`;
}
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON ALL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON ALL VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON ALL EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON FUTURE TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON FUTURE VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON FUTURE EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute();
return `Granted references for database`;
$$;
CALL GRANT_REFERENCES_TO_MONTE_CARLO();
-- モニター対象のデータベースに読み取り専用(SELECT権限のみ)の権限を付与
GRANT SELECT ON ALL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name);
GRANT SELECT ON ALL VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name);
GRANT SELECT ON ALL EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name);
GRANT SELECT ON ALL STREAMS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name);
GRANT USAGE ON FUTURE SCHEMAS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name);
-- スキーマにfuture grantsが付与されているかを確認 ※参考を参照
USE DATABASE identifier($database_to_monitor);
CREATE OR REPLACE PROCEDURE GRANT_SELECT_FUTURES_TO_MONTE_CARLO()
RETURNS VARCHAR
LANGUAGE javascript
EXECUTE AS CALLER
AS
$$
snowflake.createStatement({sqlText: `use database identifier($database_to_monitor)`}).execute();
var show_future_grants = snowflake.createStatement({sqlText: `SHOW FUTURE GRANTS IN DATABASE identifier($database_to_monitor)`}).execute();
var schema_future_grants = snowflake.createStatement({sqlText: `select * from TABLE(RESULT_SCAN('${show_future_grants.getQueryId()}')) where "grant_on" = 'SCHEMA'`}).execute();
if (schema_future_grants.getRowCount() > 0) {
var schemas_to_grant = snowflake.createStatement({ sqlText:`select SCHEMA_NAME from information_schema.SCHEMATA where SCHEMA_NAME <> 'INFORMATION_SCHEMA'`}).execute();
var granted_schemas = "";
while(schemas_to_grant.next()) {
table_schema = schemas_to_grant.getColumnValue("SCHEMA_NAME");
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE VIEWS IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE EXTERNAL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE STREAMS IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute();
granted_schemas += table_schema + ";"
}
return `Granted future select for schemas ${granted_schemas}`;
}
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE STREAMS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute();
return `Granted future select for database`;
$$;
CALL GRANT_SELECT_FUTURES_TO_MONTE_CARLO();
※参考(https://docs.snowflake.com/ja/sql-reference/sql/grant-privilege#considerations)
データベースとスキーマに対するfuture grantが重複する場合、スキーマに対するfuture grantが優先されるというのがSnowflakeの仕様としてあるため、対象のデータベースにすでにスキーマに対するfuture grantがあるかどうかを確認しています。
2. Monte CarloでSnowflakeの情報を入力して接続する
Snowflake側でMonte Carlo用のユーザーが作成できたら、Monte Carloの画面でSnowflakeの接続情報を入力します。
Settings > Integrations > Data Lake and Warehouses > Create > Snowflake を選択
以下の入力フォームが出てくるので、ユーザー名などSnowflakeで作成したものを入力します。コネクション名はMonte Carloで管理しやすい任意の名前を入力します。
- Connection Name
- Account
- Warehouse
- MONTE_CARLO_WH
- User
- MONTE_CARLO
- Password
- ユーザー作成時に設定したパスワード
すべて入力して、テストが通れは接続は完了です。
アカウント名取得に苦戦
今回トライアルアカウントからの設定だったため、Account名でかなり引っかかってしまいました。アカウント名なのでログイン時のURLのsnowflakecomputing.comの前を持ってくればいいと思っていたのですが、ずっとError: 250001 (n/a): Could not connect to Snowflake backend after 0 attempt(s).Aborting
というエラーが出続けて心が折れました。
試しにselect current_account();
を実行したところ、ログイン用のURLとは全然違うものが出てきて自分の間違いに気づきました。
こういうAPIのアカウント名で引っかかった際には、まず、Snowsight画面の管理 > アカウント で対象のアカウントの行のロケーターという項目にマウスオーバーするとコピーマークが出てくるので、それをコピーします。コピーしたURLの`https://`以降と`.snowflakecomputing.com`より前の部分がアカウント名となります。(Snowflakeをホストしているクラウドとリージョンが入っていればそれがアカウント名です。)
参考:こちらからSnowflakeをホストしているクラウドとリージョンを見つけて、Account Identifierを確認できます。(例:AWSの東京リージョンならap-northeast-1.aws
)
自動でテーブル情報を収集
接続して2週間ほどでMonte Carloが接続しているデータベースの情報を学習して、Assetsページにデータの取得情報などをまとめてくれます。
まとめ
Monte CarloをSnowflakeと連携する方法のご紹介でした!