'Copying AWS Backup snaphots to RDS snapshots automatically
I have a backup of a type "snapshot"(Aurora) created by AWS Backups service. I want to automate copying it to RDS snapshots. There is such an option in the AWS Console in the AWS Backup tab.
For example, in boto3:
- AWS Backup has a start_copy_job() but it seems to be limited only to copying into another AWS Backup Vault
- RDS has a copy_db_snapshot() but it can only copy from other types of RDS snapshots to "manual" ones
So the question is how it can be done via CLI, SDK, or CDK?
For the context: I want to restore Aurora clusters from snapshots using CDK. I'll be fine doing it from backups but I don't see that option either.
Solution 1:[1]
OK, so I figured out a somewhat hacky way to do it by interposing my own scroll handler function between the TreeView and the Scrollbars. After every scroll event, if the entry widgets have been placed on the TreeView, their positions are updated to whatever the new TreeView.bbox(itm,column) is after the scroll event. It seems to be a little laggy, but it does work. I'd still like to know if someone else has a better solution, though.
Working code:
import tkinter as tk
from tkinter import ttk
class TreeViewWindow(tk.Tk):
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.xscroll = tk.Scrollbar(self,orient='horizontal',command=lambda *val, dir='x': self.__scrollhandler(*val,direction=dir))
self.yscroll = tk.Scrollbar(self,orient='vertical',command=lambda *val, dir='y': self.__scrollhandler(*val,direction=dir))
self.list = ttk.Treeview(self,columns=("#1","#2","#3"),
selectmode='extended',
xscrollcommand=lambda *val, dir='x',src='list': self.__scrollhandler(*val,direction=dir,source=src),
yscrollcommand=lambda *val, dir='y',src='list': self.__scrollhandler(*val,direction=dir,source=src))
for cc,ii in zip(self.list['columns'],range(len(self.list['columns']))):
self.list.column(cc,minwidth=150)
self.list.heading(cc,text=f'Column {ii}')
self.list.column("#0",minwidth=150)
self.list.heading("#0",text="Name")
self.list.grid(row=0,column=0,sticky='news')
self.xscroll.grid(row=1,column=0,sticky='ew')
self.yscroll.grid(row=0,column=1,sticky='ns')
self.columnconfigure(0,weight=1)
self.rowconfigure(0,weight=1)
self.list.bind("<F2>",self.__editentry)
self.disptext = tk.StringVar(self,value='')
self.display = tk.Label(self,textvariable=self.disptext)
self.display.grid(row=1,column=0,sticky='ne')
self.__inputvars = None
self.__inputboxes = None
self.__acceptid = None
# insert some items into the tree
for i in range(10):
self.list.insert('', 'end',iid='line%i' % i, text='line:%s' % i, values=('parent', i, 'hello'))
for j in ('a','b'):
self.list.insert('line%i' % i,'end',iid=f'line{i}{j}', text=f'line:{i}{j}', values = ('child',f'{j}','goodbye'))
self.mainloop()
def __scrollhandler(self,*val,direction='y',source='scroll'):
if source=='scroll' and direction=='x':
self.list.xview(*val)
elif source=='scroll' and direction=='y':
self.list.yview(*val)
elif source=='list' and direction=='x':
self.xscroll.set(*val)
elif source=='list' and direction=='y':
self.yscroll.set(*val)
self.list.update_idletasks()
self.__forgetentryboxes()
self.__placeentryboxes()
def __placeentryboxes(self,iid=None):
if iid is None:
iid = self.__acceptid
if iid is None:
return
cols = ('#0',) + self.list['columns']
for cc,ii in zip(cols,range(len(cols))):
bbx = self.list.bbox(iid,cc)
if bbx == '':
continue
if ii == 0:
self.__inputaccept.place(anchor='nw',x=bbx[0],y=bbx[1])
self.__inputaccept.update_idletasks()
bbx = (bbx[0]+self.__inputaccept.winfo_width(),bbx[1],bbx[2]-self.__inputaccept.winfo_width(),bbx[3])
self.__inputcancel.place(anchor='nw',x=bbx[0],y=bbx[1])
self.__inputcancel.update_idletasks()
bbx = (bbx[0]+self.__inputcancel.winfo_width(),bbx[1],bbx[2]-self.__inputcancel.winfo_width(),bbx[3])
self.__inputboxes[ii].place(anchor='nw',x=bbx[0],y=bbx[1],width=bbx[2],height=bbx[3])
def __forgetentryboxes(self):
if self.__inputboxes is not None:
for bx in self.__inputboxes:
bx.place_forget()
self.__inputaccept.place_forget()
self.__inputcancel.place_forget()
def __editentry(self,event):
iid = self.list.selection()
if len(iid) == 0:
return
iid = iid[0]
if self.__inputboxes is not None:
self.__acceptentry()
cols = ('#0',) + self.list['columns']
self.__inputvars = [tk.StringVar() for ii in range(len(cols))]
self.__inputboxes = [tk.Entry(self.list,relief=tk.FLAT,textvariable=var,bd=3,highlightthickness=1,highlightbackground='black',highlightcolor='black') for var in self.__inputvars]
self.__inputaccept = tk.Button(self.list,text="Y",command=self.__acceptentry)
self.__inputcancel = tk.Button(self.list,text="N",command=self.__rejectentry)
self.__placeentryboxes(iid)
values = (self.list.item(iid,'text'),) + self.list.item(iid,'values')
for bx,var,val in zip(self.__inputboxes,self.__inputvars,values):
var.set(val)
bx.bind('<FocusIn>',lambda event: event.widget.configure(highlightthickness=2,highlightbackground='red',highlightcolor='red'))
bx.bind('<FocusOut>',lambda event: event.widget.configure(highlightthickness=1,highlightbackground='black',highlightcolor='black'))
self.__acceptbind = self.bind('<Return>',self.__acceptentry)
self.__rejectbind = self.bind('<Escape>',self.__rejectentry)
self.__acceptid = iid
def __acceptentry(self,event=None):
self.unbind('<Return>',self.__acceptbind)
self.unbind('<Escape>',self.__rejectbind)
values = tuple(vv.get() for vv in self.__inputvars)
for ii in range(len(self.__inputboxes)):
self.__inputboxes[ii].destroy()
self.__inputboxes = None
self.__inputvars = None
self.__inputaccept.destroy()
self.__inputcancel.destroy()
self.list.item(self.__acceptid,text=values[0],values=values[1:])
self.__acceptid = None
def __rejectentry(self,event=None):
self.unbind('<Return>',self.__acceptbind)
self.unbind('<Escape>',self.__rejectbind)
for ii in range(len(self.__inputboxes)):
self.__inputboxes[ii].destroy()
self.__inputaccept.destroy()
self.__inputcancel.destroy()
self.__inputboxes = None
self.__inputvars = None
self.__acceptid = None
if __name__=="__main__":
TreeViewWindow()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Beezum |
