Clone再同期のバックアップコピーの進捗確認

Clone再同期のバックグラウンドコピーの完了を確認するスクリプトを記載します。このスクリプトは、QuickOPCを使用した定期的なフルバックアップを作成する運用で使用します。詳細は、QuickOPCを使用した定期的なフルバックアップの作成を参照してください。

再同期開始 (quickopc_resync.py) が完了した時点で、業務Volumeへのアクセスを再開できますが、バックグラウンドでデータコピーが実施されています。そのため、バックグラウンドコピーが完了するまでCloneからのリストアができません。再同期の完了を確認したい場合は、ここで記載するスクリプトを使用してください。

スクリプトの処理の流れは以下です。

  1. GET /volume/copysession/ APIを使用してバックグラウンドコピーの進捗状況を確認し、コピー完了まで待機する。

quickopc_wait_sync.py


import time
import sys

from eternus_rest import EtdxBaseApi

# Change the following values for your environment.
storage_url = "https://192.168.0.1:5665"
storage_user_name = "username"
storage_password = "password"

# Change the following values as required.
# Specify the list of clone pairs. A clone pair is a tuple with a source
# volume ID and a clone volume ID of a QuickOPC.
# If you want to wait for the synchronization of multiple QuickOPCs to
# complete, list the clone pairs.
# Examples:
# clone_pair_list = [(100001,1100001),(200001,1200001)]
# This is specified to check the following QuickOPCs.
# QuickOPC#0 (source volume ID 100001, clone volume ID 1100001)
# QuickOPC#1 (source volume ID 200001, clone volume ID 1200001)
clone_pair_list = [(100001, 1100001), (200001, 1200001)]

# If you want to schedule this script, you can use cron as follows.
# Examples: It is scheduled daily at 20:00.
# crontab -e
# 0 20 * * * python3 /root/quickopc_resync.py >> /root/cron.log 2>&1


class EtdxApi(EtdxBaseApi):
    def __init__(self, base_url, boxid=None, proxies=None):
        super().__init__(base_url, boxid=boxid, proxies=proxies)

    def quickopc_wait_for_sync_completion(self, clone_volume_id_list):
        """Wait for all the QuickOPC clones synchronization to complete.

        Args:
            clone_volume_id_list (list[int]): List of clone volume IDs of
              QuickOPCs to check.

        Returns:
            bool: True if synchronization of all the specified QuickOPC clones
              are complete. False otherwise. Returns false if retrieving
              clone information failed.
        """
        while True:
            r = super().get("/api/v1/volume/copysession?volume_id={}"
                            "&fields=status,phase"
                            .format(",".join(map(str, clone_volume_id_list))))
            data = r.json()
            if r.status_code != 200 or data["list_count"] == 0:
                print("Failed to get information of clones.")
                print(r)
                print(data)
                return False
            try:
                status_list = [i["status"] for i in data["volume_list"]]
                phase_list = [i["phase"] for i in data["volume_list"]]
            except Exception:
                print("Some volumes are not clones.")
                print(data)
                return False
            # Returns false if not all of the specified clones are in
            # "Active" status.
            if status_list.count("Active") != len(clone_volume_id_list):
                print("Failed to get information about some clones or some "
                      "clones have an error.")
                print(data)
                return False
            # Break if all of the specified clones are in "Tracking" phase.
            if len(phase_list) == phase_list.count("Tracking"):
                break
            time.sleep(5 * 60)
        return True


def main():
    storage = EtdxApi(storage_url)

    # Login
    if not storage.login(storage_user_name, storage_password):
        return False

    print("Waiting for completion of sync of QuickOPC clones.")
    print("Clone pair list to check:", clone_pair_list)

    # Wait for completion of sync of clones
    clone_volume_id_list = [i[1] for i in clone_pair_list]
    if not storage.quickopc_wait_for_sync_completion(clone_volume_id_list):
        print("Failed to wait for completion of sync of the clones.")
        return False
    print("Completed to synchronize clones.")

    # Get information of all the specified clones.
    for backup_volume_id in clone_volume_id_list:
        r = storage.get("/api/v1/volume/{0!s}/copysession"
                        .format(backup_volume_id))
        print(r)
        print(r.json())

    # Logout
    storage.logout()
    return True


if __name__ == '__main__':
    if not main():
        sys.exit(1)