Snapshotのローテーション

最も古いSnapshotを削除して、新しいSnapshotを作成する(Snapshotをローテーションする)スクリプトを記載します。このスクリプトは、SnapOPC+を使用した世代管理された差分データのバックアップを作成する運用で使用します。詳細は、SnapOPC+を使用した世代管理された差分データのバックアップの作成を参照してください。

Crontabなどを使用して、このスクリプトを任意の周期で実行することで、定期的にSnapshotを取得できます。

備考

スクリプト実行中は、Snapshotのデータの整合性を保証するために、業務VolumeのI/Oやアプリケーションの処理を瞬間的に停止させ、静止点を作成する必要があります。スクリプトの処理が完了したあとは、論理的な更新データのコピーは完了しているため、業務を再開させることができます。

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

  1. POST /volume/{volume_id}/snapshot/rotate APIを使用してSnapshotをローテーションする。

snapopcplus_rotate.py


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 a list of source volume IDs of SnapOPC+ to rotate.
volume_id_list = [100001, 200001, 300001]

# If you want to schedule this script, you can use cron as follows.
# Examples: It is scheduled to rotate SnapOPC+s daily at 20:00.
# To ensure data consistency, host access must be stopped before rotation.
# crontab -e
# 0 20 * * * python3 /root/snapopcplus_rotate.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 snapopcplus_rotate(self, volume_id_list):
        """Rotate SnapOPC+s

        Args:
            volume_id_list (list[int]): List of source volume IDs of SnapOPC+s
              to rotate.

        Returns:
            list[int]: List of source volume IDs of successfully rotated
              SnapOPC+.
        """
        job_id_list = []
        for volume_id in volume_id_list:
            r = super().post("/api/v1/volume/{0!s}/snapshot/rotate"
                             .format(volume_id))
            if r.status_code != 202:
                print("Failed to request the snapshots rotation of volume "
                      "(ID: {0!s})".format(volume_id))
                print(r)
                print(r.json())
                continue
            job_info = (int(r.json()["job_id"]), volume_id)
            job_id_list.append(job_info)

        # Wait for the job completion
        success_volume_id_list = []
        for job_info in job_id_list:
            job_id = job_info[0]
            job_r = super().wait_job(job_id)
            if job_r.json()["status"] != "Success":
                print("Failed to rotate the snapshots of volume (ID: {0!s})"
                      .format(job_info[1]))
                print(job_r)
                print(job_r.json())
                continue
            success_volume_id_list.append(job_info[1])
        return success_volume_id_list


def main():
    storage = EtdxApi(storage_url)

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

    print("Rotating the SnapOPC+s specified by the list of source volume ID:",
          volume_id_list)

    # Initialize return value as True, since the procedure continues even if
    # error occurs.
    rtn = True

    # Rotate SnapOPC+s
    success_volume_list = storage.snapopcplus_rotate(volume_id_list)
    if success_volume_list == []:
        print("Failed to rotate all SnapOPC+s.")
        return False
    if set(success_volume_list) != set(volume_id_list):
        print("Failed to rotate some SnapOPC+s.")
        print("List of source volume IDs that failed rotation:",
              list(set(volume_id_list) - set(success_volume_list)))
        rtn = False
    else:
        print("All SnapOPC+s rotated successfully.")

    # Get information of all the specified SnapOPC+s.
    for volume_id in volume_id_list:
        r = storage.get("/api/v1/volume/{0!s}/copysession?backup_type=snapshot"
                        "&is_manual_snapshot=false".format(volume_id))
        print(r)
        print(r.json())

    # Logout
    storage.logout()
    return rtn


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