Rickに聞いてみよう:Tintri VMstoreにおけるデータのIP設定

Rick EhrhartはTintriの技術開発の伝道師であり、技術者です。自身のコラムでITに関する問題を取り上げ、Tintriのストレージを使った簡単な解決方法を伝授しています。ご質問はお気軽にどうぞ。


Rick
こんにちは

いつもブログを楽しく拝見し、Tintriの自動化に役立てています。現在、Tintriのプロビジョニングの自動化に取り組んでいますが、データのIPをrest APIで設定することに手間取っています。IPS(侵入防止システム)をリストアップするgetメソッド([v310/appliance/%7buuid7d/ips/index.html]/v310/appliance/{uuid}/ips)は利用できるものの、ドキュメンテーションにIPを設定するpostメソッドは見つかりませんでした。 データのIPはTintri Automation PowerShell Toolkitで設定できますが、個人的にはREST APIの方が好きです。REST APIによるデータのIP設定を近日中に可能にする予定はありますか。

Gaurav


こんにちは

データのIP設定はDNSの設定に似ています。 PUT /v310/appliance/default のAPIを使うのです。 例としてset_data_ip.pyを紹介します。これは、現在のIPアドレスを表示し、データのIPアドレスを追加または削除するものです。


[rle@rle-vm tintri-api-examples]$ ./set_data_ip.py -h
usage: set_data_ip.py [-h] [--add ADD] [--delete DELETE]
                      server_name user_name password

Optionally adds or deletes a data IP on a VMstore

positional arguments:
  server_name           VMstore server name
  user_name             VMstore user name
  password              User name password

optional arguments:
  -h, --help            show this help message and exit
  --add ADD, -a ADD     Add the specifed IP to the data IP configuration.
  --delete DELETE, -d DELETE
                        Delete the specifed IP from the data IP configuration.

set_dns_primary.pyでDNSアドレスを取得する代わりに、このコードは GET /v310/appliance/default/ipsget_ip_configs ファンクションとともに用いることで、現在のVMstoreのIPアドレスを取得します。


APPLIANCE_URL = "/v310/appliance/default"

# Return IP addresses.
def get_ip_configs(server_name, session_id):
    url = APPLIANCE_URL + "/ips"

    try:
        # Make the get call
        r = tintri.api_get(server_name, url, session_id)
        print_debug("The JSON response of the get invoke to the server " +
                    server_name + " is: " + r.text)

    except tintri.TintriRequestsException as tre:
        message = HTTP error for the get IP addresses invoke to the server."
        raise tintri.TintriApiException(message, r.status_code, url, str(Request), r.text)
    except tintri.TintriApiException as tae:
        message = "The HTTP response for the get IP addresses invoke to the server is not 200."
        raise tintri.TintriApiException(message, r.status_code, url, str(Request), r.text)

    ip_configs = r.json()
    return ip_configs

ここで忘れてはならないのは、アプライアンスAPIはUUIDを必要とし、VMstoreでAPIを呼び出す際にはAPI “default” が使われます。 GET /v310/appliance/default を使うこともできますが、検索する情報量が少ない分、 GET /v310/appliance/default/ips の方が速いのです。 set_dns_primary.pyset_data_ip.pyの大きな違いは、set_dns_primary.pyは複数のVMstoreを設定するのに対し、set_data_ip.pyは一つのVMstoreしか設定しないことです。これによりコードは単純化されますが、サーバーの仮想ストレージ化は依然として可能です。


try:
    r = tintri.api_version(server_name)
    json_info = r.json()
    if json_info['productName'] != "Tintri VMstore":
        message = "Server needs to be a VMstore"
        raise tintri.TintriRequestsException(message)

上記の例には異なるアップデート コンテンツが含まれている可能性があるため、 PUT v310/appliance/default のAPIを呼び出すコードとコンテンツを作成するコードを区別しました。APIの呼び出しは update_data_ip( ) で、アップデート コンテンツの作成は add_data_ip( ) もしくは delete_data_ip( ) で行われます。これは、使用するコマンドラインオプションに左右されます。 下記の update_data_ip( ) ファンクションでは、 new_ip_configs を用い、 configIps のDTOをインプットとして表します。 Request のDTOには、更新される値とプロパティを持つオブジェクトが含まれています。この場合、データ用IPアドレスの値を持つオブジェクトは new_appliance で、変更されるプロパティが configIps となります。これもまた、set_dns_primary.pyにおける process_vmstore( ) に似ています。


# Set the data IP with new IP configuration.
def update_data_ip(server_name, session_id, new_ip_configs):

    # Create the Appliance object with the new configIps DTO.
    new_appliance = \
        {'typeId': 'com.tintri.api.rest.v310.dto.domain.Appliance',
         'configIps': new_ip_configs
        }

    # Create the Request object with the Appliance DTO.
    Request = \
        {'typeId': 'com.tintri.api.rest.v310.dto.Request',
         'objectsWithNewValues': newAppliance,
         'propertiesToBeUpdated': ['configIps']
        }
    # Update the VMstore wit the new data IP configuration.
    url = APPLIANCE_URL
    r = tintri.api_put(server_name, url, Request, session_id)
    print_debug("The JSON response of the get invoke to the server " +
                server_name + " is: " + r.text)

    # if HTTP Response is not 204 then raise exception.
    if r.status_code != 204:
        message = "The HTTP response for put call to the server is not 204."
        raise tintri.TintriApiException(message, r.status_code, url, str(Request), r.text)

最初にadd_data_ip( )を見てみましょう。PUT v310/appliance/default はデータのIPアドレスを更新するため、現在の設定済みIPアドレスリストから、データのIPアドレスだけ見つければよいのです。各データのIPアドレスについては、コードが新しいリストに追加します。また、データ用IPアドレスの設定は、後で新しいデータIPアドレスのテンプレートとして使うために保存されます。ループ後に、保存されたデータIPアドレスの設定を変更することにより新しいデータIPアドレスが作成されます。ここで注意することはVLAN IDは untagged と表示されることです。しかし、ネットワークでVLANを使用している場合、この値は untagged ではなくVLAN IDとなります。新しいデータIPアドレスの設定は、設定済みIPアドレスのリストに追加され、リストは送信側に戻されます。


# Add a data IP to the list of current IPs and return new list.
def add_data_ip(ip_configs, new_data_ip):

    new_ip_configs = []

    # Find a data IP config to copy and copy only the data IP configs.
    for ip_config in ip_configs:
        if (ip_config['ip'] == new_data_ip):
            message = new_data_ip + " already configured."
            raise tintri.TintriRequestsException(message)

        if (ip_config['serviceType'] == "data"):
            ip_config_save = ip_config
            new_ip_configs.append(ip_config)

    if (not ip_config_save):
        message = "Data IP conifg does not exist."
        raise tintri.TintriRequestsException(message)

    data_ip_config = ip_config_save.copy()

    # Modify the save copy for our purposes.
    data_ip_config['ip'] = new_data_ip
    data_ip_config['vlanId'] = "untagged"  # For example only.

    new_ip_configs.append(data_ip_config)
    return new_ip_configs

IPアドレスを削除するには新しいデータIPアドレスのリストが再び必要になります。ご覧のように、これはIPアドレスの追加よりも簡単です。コードは設定リストをざっと調べ、特定のIPアドレスに適合するIPアドレスの設定を、新しいデータIPアドレスの設定リストに追加することはありません。


def del_data_ip(ip_configs, data_ip_to_del):

    new_ip_configs = []

    # Append IP config if the data IP doesn't match.
    for ip_config in ip_configs:
        if (ip_config['serviceType'] == "data"):
            if (ip_config['ip'] != data_ip_to_del):
                new_ip_configs.append(ip_config)

    return new_ip_configs

それでは最後のコードを見てみましょう。現在のIPアドレス設定は常に表示されます。追加オプションまたは削除オプションが指定されると、指定された作業が実行され、新しいIPアドレスの設定が表示されます。


# Execute
try:
    ip_configs = get_ip_configs(server_name, session_id)
    print_ip_configs(ip_configs, "Current")

    if add_ip or delete_ip:
        if add_ip:
            new_ip_configs = add_data_ip(ip_configs, new_data_ip)
        if delete_ip:
            new_ip_configs = del_data_ip(ip_configs, new_data_ip)

        update_data_ip(server_name, session_id, new_ip_configs)

        # Display the changes
        ip_configs = get_ip_configs(server_name, session_id)
        print_ip_configs(ip_configs, "New")

except tintri.TintriRequestsException as tre:
    print_error(server_name + ": " + tre.__str__())
except tintri.TintriApiException as tae:
    print_error(server_name + ": " + tae.__str__())

なお、Tintri GitHubサイトのほうがコーディング経験に関する事例が多く記載されていますので、チェックされてはいかがでしょうか。 他にもご質問があれば、お気軽にどうぞ。

Rick