본문 바로가기
PC/Programming

Amazon Glacier 삭제가 힘드니 python으로...

by dragom 2022. 3. 19.
반응형

Glacier가 생각보다 금액이 나오는듯해서 삭제하려고 synology에서는 앱까지 삭제해버렸는데

아카이브가 남아있으면 Glacier 볼트를 삭제할수가 없네요.

AWS CLI를 이용해서 아카이브들을 찾고 삭제하도록 프로그래밍 해 보았습니다.

(참고) https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html

 

Getting started with the AWS CLI - AWS Command Line Interface

Thanks for letting us know this page needs work. We're sorry we let you down. If you've got a moment, please tell us how we can make the documentation better.

docs.aws.amazon.com

aws 설치 후 aws configure로 설정까지 마쳐야 합니다.

Access key는 aws웹페이지 상에서 IAM 에서 만드시면 되고, 

region은 아래 사진의 볼트 ARN의 빨간부분 앞에 써있는 ap-northeast-2 와 같은 형식으로 입력하시면 됩니다.


aws cli를 이용한 동작 과정을 말씀드리면

1. 볼트를 지정하여 볼트 내 아카이브들의 ID를 찾도록 명령(job) 
(저의 경우 명령 후 4시간 정도 후 완료)

2.  1의 job이 완료되었는지 체크

3. 1의 job이 완료되었을 경우 결과를 json 파일로 저장

4. json 파일대로 아카이브들을 하나하나 삭제 명령

의 순서 입니다.

아쉬운 점은 (제가 모르는 것일 수도 있지만) 결과로 얻은 json 파일을 아카이브 삭제하는 대상으로 통째로 넣어주고 싶은데 aws cli에 그런 기능이 없는지 id를 하나하나 삭제시켜야 합니다.

import json
import os
import sys
from threading import Thread
import subprocess
import time
import pickle

account_id = "빨강색 부분"
vault_name = "검은색 부분"


class aws_glacier:
    def __init__(self, account_id, vault_name):
        self.account_id = account_id
        self.vault_name = vault_name
        self.job_id = ""

    def search(self):
        if not os.path.isfile("job.id"):
            try:
                process = subprocess.Popen(
                    [
                        "aws",
                        "glacier",
                        "initiate-job",
                        "--account-id",
                        self.account_id,
                        "--vault-name",
                        self.vault_name,
                        "--job-parameters",
                        '{"Type":"inventory-retrieval"}',
                    ],
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                )
            except:
                print("Starting searching glacier Failed")
            try:
                stdout, stderr = process.communicate()
                stdout = eval(stdout.decode("ascii"))
                print(stdout)
                self.job_id = stdout["jobId"]
                with open("job.id", "wb") as f:
                    pickle.dump(self.job_id, f)
                return True
            except:
                print("Getting Job-ID Failed")
                return False
        else:
            print("You already have an job (job.id)")
            with open("job.id", "rb") as f:
                self.job_id = pickle.load(f)

    def check_job(self):
        try:
            process = subprocess.Popen(
                [
                    "aws",
                    "glacier",
                    "describe-job",
                    "--account-id",
                    self.account_id,
                    "--vault-name",
                    self.vault_name,
                    "--job-id",
                    self.job_id,
                ],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
            stdout, stderr = process.communicate()
        except:
            print("Starting checking job Failed")
        try:
            stdout = eval(stdout.decode("ascii").replace("true", "True").replace("false","False"))
            status = stdout["Completed"]
            print("Current Status = "+str(status))
            return status
        except Exception as e:
            print(e)
            print("Getting Job-status Failed")
            return False

    def get_json(self):
        while not self.check_job():
            time.sleep(30)
        try:
            process = subprocess.Popen(
                [
                    "aws",
                    "glacier",
                    "get-job-output",
                    "--account-id",
                    self.account_id,
                    "--vault-name",
                    self.vault_name,
                    "--job-id",
                    self.job_id,
                    "output1.json",
                ],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
            stdout, stderr = process.communicate()
            os.system("rm -f job.id")
        except:
            print("Getting Job resultFailed")


def run_amazone(amazon, account_id, vault_name, Arch):
    process = subprocess.Popen(
        [
            "aws",
            "glacier",
            "delete-archive",
            "--account-id",
            account_id,
            "--vault-name",
            vault_name,
            "--archive-id",
            "'" + str(Arch) + "'",
        ],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    stdout, stderr = process.communicate()
    if len(stdout) <= 10:
        amazon["ArchiveList"].remove(Arch)


def savings(amazon):
    print("saving file")
    with open("output1.json", "w") as jsf:
        json.dump(amazon, jsf)


if __name__ == "__main__":
    if not os.path.isfile("output1.json"):
        a = aws_glacier(account_id, vault_name)
        while not len(a.job_id) > 1:
            a.search()
        a.get_json()
    startat=0
    with open("output1.json", "r") as jsf:
        amazon = json.load(jsf)
    tot = str(len(amazon["ArchiveList"]))
    jobs = []

    for n, Arch in enumerate(amazon["ArchiveList"]):
        try:
            if n < startat:
                continue
            print(str(n) + " / " + tot, end="\t")
            print(Arch["ArchiveId"])
            th = Thread(target=run_amazone, args=(amazon, account_id, vault_name, Arch))
            jobs.append(th)
            jobs[-1].start()
            if len(jobs) >= 21:
                jobs[-20].join()
            if len(jobs) >= 101:
                jobs.remove(jobs[-100])
            # run_amazone(amazon, cmd, Arch)
            if n % 1000 == 0:
                savings(amazon)

        except KeyboardInterrupt:
            savings(amazon)
            break
        except Exception as e:
            print(e)

수십만개나 되는데 하나씩 지우는게 너무 오래걸려서

subprocess 이용하여 20개씩 지우도록 했습니다. 각자의 성능에 따라 적당히 조절해서 사용하시면 될 듯 합니다.

반응형

댓글