-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
executable file
·242 lines (208 loc) · 10.1 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox, filedialog
import os
import dateutil.parser
import datetime
import os.path
from math import floor, ceil
import argparse
from inventory import Inventory, File
from glacier import Glacier
# REFERENCE:
# - UPLOAD and RETRIEVA Requests $0.050 per 1,000 requests
# - LISTVAULTS, GETJOB OUTPUT,
# DELETE* Request and all other Requests Free
# - Data Retrievals Free
# * Early Deletion Fee (before 90 days)
# Deletion fee of $0.021 per GB
# - If you deleted 1GB, 1 month after uploading it: $0.014
# - If you deleted 1GB, 2 months after uploading: $0.007
#TODO: Show price of each action.. if it isnt free
#TODO: Show time expected for each action.. if isnt real-time
#TODO: Maybe show message dialog before every request
class App():
def __init__(self, vault=None):
self.Glacier = Glacier(vault)
self.root = tk.Tk()
self.root.title("Amazon Glacier - Support Tool")
w, h = 640, 480
ws, hs = self.root.winfo_screenwidth(), self.root.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
self.root.geometry("%dx%d+%d+%d" % (w,h,x,y) )
self.createUI()
self.updateTick()
self.root.wm_protocol("WM_DELETE_WINDOW", self.onDelete)
self.Glacier.loadDefault()
self.updateFileList()
self.root.mainloop()
def onDelete(self):
self.Glacier.closeDefault()
self.root.destroy()
def createUI(self):
# Add Labels about Vault
tk.Label(self.root, text="Vault Name: " + self.Glacier.vault.vault_name).pack()
tk.Label(self.root, text="Creation Date: " + self.Glacier.vault.creation_date).pack()
tk.Label(self.root, text="# of Archives: " + str(self.Glacier.vault.number_of_archives)).pack()
tk.Label(self.root, text="Size in bytes: " + str(self.Glacier.vault.size_in_bytes)).pack()
# Add Main Buttons
btnTop = tk.Frame(self.root)
tk.Button(btnTop, text="List Vaults", command=self.listVaults).pack(side=tk.LEFT)
tk.Button(btnTop, text="Request List Files", command=self.listFiles).pack(side=tk.LEFT)
tk.Button(btnTop, text="Job Status", command=self.jobStatus).pack(side=tk.LEFT)
btnTop.pack()
# Add File Treeview
cols = ["File","Size","Date"]
self._files = ttk.Treeview(self.root, columns=cols, show="headings")
for c in cols: self._files.heading(c,text=c)
self._files.pack()
# Add File Buttons
btnBottom = tk.Frame(self.root)
tk.Button(btnBottom, text="Upload Directory", command=self.uploadDirectory).pack(side=tk.LEFT)
tk.Button(btnBottom, text="Upload File", command=self.uploadFile).pack(side=tk.LEFT)
tk.Button(btnBottom, text="Multipart File Upload", command=self.uploadFileMP).pack(side=tk.LEFT)
tk.Button(btnBottom, text="Delete File", command=self.deleteFile).pack(side=tk.LEFT)
btnBottom.pack()
def uploadDirectory(self):
f = filedialog.askdirectory()
if ( f != () and os.path.isdir(f) ):
self.Glacier.uploadDirectory(f)
def uploadFileMP(self):
f = filedialog.askopenfilename()
if ( f != () and os.path.isfile(f) ):
request = messagebox.askyesno("Multipart Upload","Uploading file in Multiparts: " + f + " ?\nDepending of the size of the file and your bandwidth it may take some time.\nDo you want to continue?")
if (request): self.Glacier.uploadFileMultiPart(f)
def uploadFile(self):
f = filedialog.askopenfilename()
if ( f != () and os.path.isfile(f) ):
request = messagebox.askyesno("Upload File","Uploading file: " + f + " ?\nDepending of the size of the file and your bandwidth it may take some time.\nDo you want to continue?")
if (request):
self.Glacier.uploadFile(f)
aid, txtStatus, checksum, comcheck = self.updateFileList()
# Show Window with Result
top = tk.Toplevel()
tk.Label(top, text=txtStatus, height=0, width=150).pack()
tk.Label(top, text="ArchiveId: " + aid, height=0, width=150).pack()
tk.Label(top, text=checksum, height=0, width=150).pack()
tk.Label(top, text=comcheck, height=0, width=150).pack()
def deleteFile(self):
focus = self._files.focus()
if (focus == ''): return
# Get Row
f = self._files.set(focus)
# Get File
ffile = self.Glacier.inventory.getFile(f["Size"], f["Date"], f["File"])
if (ffile.deleted):
messagebox.showinfo("File can't be deleted", "File Already Removed from the Cloud")
return
# Check Interval
d = dateutil.parser.parse(f["Date"])
d.replace(tzinfo=None)
days = (d.replace(tzinfo=None)-datetime.datetime.utcnow()).days
request = True
if (days > -90):
title = "Continue Deleting Archive?"
msg = """This file was uploaded less than 90 days ago.
This action will cost deletion fee.
Do you want to continue?"""
request = messagebox.askyesno(title,msg)
# Delete?
if (request and ffile.aid != None and ffile.deleted == False):
self.Glacier.deleteFile(ffile)
self.updateFileList()
#TODO
def jobStatus(self):
jobs = self.Glacier.listJobs()
top = tk.Toplevel()
for job in jobs:
tk.Label(top, text="Action: " + job["Action"] , height=0, width=50).pack()
tk.Label(top, text="Status: " + job["StatusCode"] , height=0, width=50).pack()
tk.Label(top, text="Creation Date: " + job["CreationDate"] , height=0, width=50).pack()
if (job["StatusCode"] == "Succeeded"):
tk.Label(top, text="Completion Date: " + job["CompletionDate"] , height=0, width=50).pack()
self.updateFileList()
def updateFileList(self):
# Clear Tree
self._files.delete(*self._files.get_children())
# Repopulate Tree
if (self.Glacier.inventory != None):
for f in self.Glacier.inventory.files:
tags = ()
if (f.deleted): tags=("deleted",)
elif (f.isNew): tags=("new",)
self._files.insert("","end",values=[f.desc,f.size,f.date], tags=tags)
self._files.tag_configure("deleted", background="red")
self._files.tag_configure("new", background="green")
def listVaults(self):
ret = self.Glacier.glacier.list_vaults()
if ("VaultList" in ret):
for i in ret["VaultList"]:
print(i["VaultName"] + ": " + str(i["SizeInBytes"]) + " bytes")
def listFiles(self):
request = False
# Inventory is only created around 1 day after first file is upload
if (self.Glacier.vault.last_inventory_date == None):
request = messagebox.askyesno("No Inventory Found","Request Inventory from AWS Glacier?\nJob will take around 4-5 hours to complete.")
else:
d = dateutil.parser.parse( self.Glacier.vault.last_inventory_date )
d.replace(tzinfo=None)
days = (datetime.datetime.utcnow() - d.replace(tzinfo=None)).days
hours = (datetime.datetime.utcnow() - d.replace(tzinfo=None)).seconds/3600.0
hours = floor(hours*100)/100;
# Amazon Glacier prepares an inventory for each vault periodically, every 24 hours.
# When you initiate a job for a vault inventory, Amazon Glacier returns the last
# inventory for the vault. The inventory data you get might be up to a day or
# two days old.
#
# - So, we only request a new list if our current list is more than 2 days older
# TODO: Here we need to check if we already have a inventory_retrieval job
if (days >= 2):
request = messagebox.askyesno("Inventory is " + str(days) + " days old","Request Inventory from AWS Glacier?\nJob will take around 4-5 hours to complete.")
else:
request = messagebox.askyesno("Inventory is " + str(hours) + " hours old","Request Inventory from AWS Glacier?\nJob will take around 4-5 hours to complete.")
if (request):
self.Glacier.initListFiles()
#TODO: Add Message/Feedback
else:
# Use old data
#TODO: Here, update self.inventory with archives information
# Havent find a way to get old inventory data yet.. so will keep it locally
print(self.Glacier.vault.number_of_archives)
print(self.Glacier.vault.size_in_bytes)
def updateTick(self):
print("tum tum")
# Timer in milliseconds
#self.root.after(10000, self.updateTick)
#print("Tick")
#for i in reversed( range(len(self.active_jobs)) ):
# job = self.jobs[i]
# #TODO: However, it is more efficient to use an Amazon SNS
# # notification to determine when a job is complete.
# if (job.completed):
# self.active_jobs.pop(i)
# ret = self.glacier.get_job_output()
# print(ret)
class FullPath(argparse.Action):
"""Expand user- and relative-paths"""
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, os.path.abspath(os.path.expanduser(values)))
def is_dir(dirname):
"""Checks if a path is an actual directory"""
if not os.path.isdir(dirname):
msg = "{0} is not a directory".format(dirname)
raise argparse.ArgumentTypeError(msg)
else:
return dirname
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="description here")
parser.add_argument("-d",help="Directory to be uploaded using Multipart",action=FullPath, type=is_dir)
args = parser.parse_args()
if (args.d == None):
app = App()
else:
glacier = Glacier()
glacier.loadDefault()
glacier.uploadDirectory(args.d)
glacier.closeDefault()