Skip to content

Commit 11387b4

Browse files
authored
Add unified %reset magic (#644)
* Add unified %reset magic * update changelog
1 parent 6c6ecd5 commit 11387b4

File tree

3 files changed

+144
-83
lines changed

3 files changed

+144
-83
lines changed

ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Starting with v1.31.6, this file will contain a record of major features and upd
66

77
- New Neptune Database notebook - Games Industry Graphs ([Link to PR](https://github.com/aws/graph-notebook/pull/566))
88
- Path: 01-Neptune-Database > 03-Sample-Applications > 07-Games-Industry-Graphs
9+
- Added unified `%reset` line magic ([Link to PR](https://github.com/aws/graph-notebook/pull/644))
910
- Added `--connected-table` option to magics with table widget output ([Link to PR](https://github.com/aws/graph-notebook/pull/634))
1011
- Added `--silent` option to the `%%graph_notebook_config` line and cell magics ([Link to PR](https://github.com/aws/graph-notebook/pull/641))
1112
- Added helpful redirect messaging for service-specific Neptune magics ([Link to PR](https://github.com/aws/graph-notebook/pull/643))

src/graph_notebook/magics/graph_magic.py

Lines changed: 141 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
NEPTUNE_CONFIG_HOST_IDENTIFIERS, is_allowed_neptune_host, \
5252
STATISTICS_LANGUAGE_INPUTS, STATISTICS_LANGUAGE_INPUTS_SPARQL, STATISTICS_MODES, SUMMARY_MODES, \
5353
SPARQL_EXPLAIN_MODES, OPENCYPHER_EXPLAIN_MODES, GREMLIN_EXPLAIN_MODES, \
54-
OPENCYPHER_PLAN_CACHE_MODES, OPENCYPHER_DEFAULT_TIMEOUT, OPENCYPHER_STATUS_STATE_MODES, \
55-
normalize_service_name, GRAPH_PG_INFO_METRICS, \
54+
OPENCYPHER_PLAN_CACHE_MODES, OPENCYPHER_DEFAULT_TIMEOUT, OPENCYPHER_STATUS_STATE_MODES,
55+
normalize_service_name, NEPTUNE_DB_SERVICE_NAME, NEPTUNE_ANALYTICS_SERVICE_NAME, GRAPH_PG_INFO_METRICS, \
5656
DEFAULT_GREMLIN_PROTOCOL, GREMLIN_PROTOCOL_FORMATS, DEFAULT_HTTP_PROTOCOL, normalize_protocol_name)
5757
from graph_notebook.network import SPARQLNetwork
5858
from graph_notebook.network.gremlin.GremlinNetwork import parse_pattern_list_str, GremlinNetwork
@@ -1531,82 +1531,141 @@ def get_graph(self, line='', local_ns: dict = None):
15311531
@line_magic
15321532
@needs_local_scope
15331533
@display_exceptions
1534-
@neptune_db_only
1535-
def db_reset(self, line, local_ns: dict = None):
1534+
def reset(self, line, local_ns: dict = None, service: str = None):
15361535
logger.info(f'calling system endpoint {self.client.host}')
15371536
parser = argparse.ArgumentParser()
1538-
parser.add_argument('-g', '--generate-token', action='store_true', help='generate token for database reset')
1539-
parser.add_argument('-t', '--token', default='', help='perform database reset with given token')
1540-
parser.add_argument('-y', '--yes', action='store_true', help='skip the prompt and perform database reset')
1537+
parser.add_argument('-g', '--generate-token', action='store_true',
1538+
help='Generate token for database reset. Database only.')
1539+
parser.add_argument('-t', '--token', default='',
1540+
help='Perform database reset with given token. Database only.')
1541+
parser.add_argument('-s', '--snapshot', action='store_true', default=False,
1542+
help='Creates a final graph snapshot before the graph data is deleted. Analytics only.')
1543+
parser.add_argument('-y', '--yes', action='store_true',
1544+
help='Skip the prompt and perform reset.')
15411545
parser.add_argument('-m', '--max-status-retries', type=int, default=10,
15421546
help='Specifies how many times we should attempt to check if the database reset has '
15431547
'completed, in intervals of 5 seconds. Default is 10')
15441548
args = parser.parse_args(line.split())
15451549
generate_token = args.generate_token
15461550
skip_prompt = args.yes
1551+
snapshot = args.snapshot
1552+
if not service:
1553+
service = self.graph_notebook_config.neptune_service
1554+
if service == NEPTUNE_DB_SERVICE_NAME:
1555+
using_db = True
1556+
graph_id = None
1557+
message_instance = "cluster"
1558+
else:
1559+
using_db = False
1560+
graph_id = self.client.get_graph_id()
1561+
message_instance = "graph"
15471562
max_status_retries = args.max_status_retries if args.max_status_retries > 0 else 1
1548-
if generate_token is False and args.token == '':
1563+
if not using_db or (generate_token is False and args.token == ''):
15491564
if skip_prompt:
1550-
initiate_res = self.client.initiate_reset()
1551-
initiate_res.raise_for_status()
1552-
res = initiate_res.json()
1553-
token = res['payload']['token']
1554-
1555-
perform_reset_res = self.client.perform_reset(token)
1556-
perform_reset_res.raise_for_status()
1557-
logger.info(f'got the response {res}')
1558-
res = perform_reset_res.json()
1559-
return res
1565+
if using_db:
1566+
initiate_res = self.client.initiate_reset()
1567+
initiate_res.raise_for_status()
1568+
res = initiate_res.json()
1569+
token = res['payload']['token']
1570+
1571+
perform_reset_res = self.client.perform_reset(token)
1572+
perform_reset_res.raise_for_status()
1573+
logger.info(f'got the response {res}')
1574+
res = perform_reset_res.json()
1575+
return res
1576+
else:
1577+
try:
1578+
res = self.client.reset_graph(graph_id=graph_id, snapshot=snapshot)
1579+
print(
1580+
f"ResetGraph call submitted successfully for graph ID [{graph_id}]. "
1581+
f"Please note that the graph may take several minutes to become available again, "
1582+
f"You can use %status or %get_graph to check the current status of the graph.\n")
1583+
print(json.dumps(res, indent=2, default=str))
1584+
except Exception as e:
1585+
print("Received an error when attempting graph reset:")
1586+
print(e)
1587+
return
15601588

15611589
output = widgets.Output()
1562-
source = 'Are you sure you want to delete all the data in your cluster?'
1563-
label = widgets.Label(source)
1564-
text_hbox = widgets.HBox([label])
1565-
check_box = widgets.Checkbox(
1590+
confirm_source = f'Are you sure you want to delete all the data in your {message_instance}?'
1591+
confirm_label = widgets.Label(confirm_source)
1592+
confirm_text_hbox = widgets.HBox([confirm_label])
1593+
confirm_check_box = widgets.Checkbox(
15661594
value=False,
15671595
disabled=False,
15681596
indent=False,
1569-
description='I acknowledge that upon deletion the cluster data will no longer be available.',
1597+
description=f'I acknowledge that upon deletion the {message_instance} data will no longer be available.',
15701598
layout=widgets.Layout(width='600px', margin='5px 5px 5px 5px')
15711599
)
15721600
button_delete = widgets.Button(description="Delete")
15731601
button_cancel = widgets.Button(description="Cancel")
15741602
button_hbox = widgets.HBox([button_delete, button_cancel])
15751603

1576-
display(text_hbox, check_box, button_hbox, output)
1604+
if using_db:
1605+
display(confirm_text_hbox, confirm_check_box, button_hbox, output)
1606+
else:
1607+
snapshot_source = f'OPTIONAL: Create a final graph snapshot before reset?'
1608+
snapshot_label = widgets.Label(snapshot_source)
1609+
snapshot_text_hbox = widgets.HBox([snapshot_label])
1610+
snapshot_check_box = widgets.Checkbox(
1611+
value=snapshot,
1612+
disabled=False,
1613+
indent=False,
1614+
description=f'Yes',
1615+
layout=widgets.Layout(width='600px', margin='5px 5px 5px 5px')
1616+
)
1617+
1618+
display(confirm_text_hbox, confirm_check_box,
1619+
snapshot_text_hbox, snapshot_check_box,
1620+
button_hbox, output)
15771621

15781622
def on_button_delete_clicked(b):
1579-
initiate_res = self.client.initiate_reset()
1580-
initiate_res.raise_for_status()
1581-
result = initiate_res.json()
1582-
1583-
text_hbox.close()
1584-
check_box.close()
1623+
if using_db:
1624+
initiate_res = self.client.initiate_reset()
1625+
initiate_res.raise_for_status()
1626+
result = initiate_res.json()
1627+
1628+
confirm_text_hbox.close()
1629+
confirm_check_box.close()
1630+
if not using_db:
1631+
snapshot_text_hbox.close()
1632+
snapshot_check_box.close()
15851633
button_delete.close()
15861634
button_cancel.close()
15871635
button_hbox.close()
15881636

1589-
if not check_box.value:
1590-
with output:
1591-
print('Checkbox is not checked.')
1592-
return
1593-
token = result['payload']['token']
1594-
if token == "":
1637+
if not confirm_check_box.value:
15951638
with output:
1596-
print('Failed to get token.')
1597-
print(result)
1639+
print('Reset confirmation checkbox is not checked.')
15981640
return
15991641

1600-
perform_reset_res = self.client.perform_reset(token)
1601-
perform_reset_res.raise_for_status()
1602-
result = perform_reset_res.json()
1642+
if using_db:
1643+
token = result['payload']['token']
1644+
if token == "":
1645+
with output:
1646+
print('Failed to get token.')
1647+
print(result)
1648+
return
16031649

1604-
if 'status' not in result or result['status'] != '200 OK':
1605-
with output:
1606-
print('Database reset failed, please try the operation again or reboot the cluster.')
1607-
print(result)
1608-
logger.error(result)
1609-
return
1650+
perform_reset_res = self.client.perform_reset(token)
1651+
perform_reset_res.raise_for_status()
1652+
result = perform_reset_res.json()
1653+
1654+
if 'status' not in result or result['status'] != '200 OK':
1655+
with output:
1656+
print('Database reset failed, please see exception below for details.')
1657+
print(result)
1658+
logger.error(result)
1659+
return
1660+
else:
1661+
try:
1662+
result = self.client.reset_graph(graph_id=graph_id, snapshot=snapshot_check_box.value)
1663+
except Exception as e:
1664+
with output:
1665+
print("Failed to initiate graph reset, please see the exception below.")
1666+
print(f"\n{e}")
1667+
logger.error(e)
1668+
return
16101669

16111670
retry = max_status_retries
16121671
poll_interval = 5
@@ -1631,20 +1690,30 @@ def on_button_delete_clicked(b):
16311690
new_interval = True
16321691
try:
16331692
retry -= 1
1634-
status_res = self.client.status()
1635-
status_res.raise_for_status()
1636-
interval_check_response = status_res.json()
1693+
if using_db:
1694+
status_res = self.client.status()
1695+
status_res.raise_for_status()
1696+
interval_check_response = status_res.json()
1697+
else:
1698+
interval_check_response = self.client.get_graph(graph_id=graph_id)
16371699
except Exception as e:
16381700
# Exception is expected when database is resetting, continue waiting
1639-
with job_status_output:
1640-
last_poll_time = time.time()
1641-
time.sleep(1)
1642-
continue
1701+
if using_db:
1702+
with job_status_output:
1703+
last_poll_time = time.time()
1704+
time.sleep(1)
1705+
continue
1706+
else:
1707+
print('Graph status check failed, something went wrong.')
1708+
print(e)
1709+
logger.error(e)
1710+
return
16431711
job_status_output.clear_output()
16441712
with job_status_output:
1645-
if interval_check_response["status"] == 'healthy':
1713+
done_status = 'healthy' if using_db else 'AVAILABLE'
1714+
if interval_check_response["status"] == done_status:
16461715
interval_output.close()
1647-
print('Database has been reset.')
1716+
print(f'{message_instance.capitalize()} has been reset.')
16481717
return
16491718
last_poll_time = time.time()
16501719
else:
@@ -1663,16 +1732,19 @@ def on_button_delete_clicked(b):
16631732
if interval_check_response.get("status") != 'healthy':
16641733
print(f"Could not retrieve the status of the reset operation within the allotted time of "
16651734
f"{total_status_wait} seconds. If the database is not in healthy status after at least 1 "
1666-
f"minute, please try the operation again or reboot the cluster.")
1735+
f"minute, please try the operation again or reboot the {message_instance}.")
16671736

16681737
def on_button_cancel_clicked(b):
1669-
text_hbox.close()
1670-
check_box.close()
1738+
confirm_text_hbox.close()
1739+
confirm_check_box.close()
1740+
if not using_db:
1741+
snapshot_text_hbox.close()
1742+
snapshot_check_box.close()
16711743
button_delete.close()
16721744
button_cancel.close()
16731745
button_hbox.close()
16741746
with output:
1675-
print('Database reset operation has been canceled.')
1747+
print(f'{message_instance.capitalize()} reset operation has been canceled.')
16761748

16771749
button_delete.on_click(on_button_delete_clicked)
16781750
button_cancel.on_click(on_button_cancel_clicked)
@@ -1690,38 +1762,26 @@ def on_button_cancel_clicked(b):
16901762
logger.info(f'got the response {res}')
16911763
return res
16921764

1765+
@line_magic
1766+
@needs_local_scope
1767+
@display_exceptions
1768+
@neptune_db_only
1769+
def db_reset(self, line, local_ns: dict = None):
1770+
self.reset(line, local_ns, service=NEPTUNE_DB_SERVICE_NAME)
1771+
16931772
@line_magic
16941773
@needs_local_scope
16951774
@display_exceptions
16961775
@neptune_graph_only
16971776
def graph_reset(self, line, local_ns: dict = None):
1698-
self.reset_graph(line, local_ns)
1777+
self.reset(line, local_ns, service=NEPTUNE_ANALYTICS_SERVICE_NAME)
16991778

17001779
@line_magic
17011780
@needs_local_scope
17021781
@display_exceptions
17031782
@neptune_graph_only
17041783
def reset_graph(self, line, local_ns: dict = None):
1705-
parser = argparse.ArgumentParser()
1706-
parser.add_argument('-ns', '--no-skip-snapshot', action='store_true', default=False,
1707-
help='Creates a final graph snapshot before the graph data is deleted.')
1708-
parser.add_argument('--silent', action='store_true', default=False, help="Display no output.")
1709-
parser.add_argument('--store-to', type=str, default='', help='Store query result to this variable.')
1710-
args = parser.parse_args(line.split())
1711-
1712-
try:
1713-
graph_id = self.client.get_graph_id()
1714-
res = self.client.reset_graph(graph_id=graph_id, no_skip_snapshot=args.no_skip_snapshot)
1715-
if not args.silent:
1716-
print(f"ResetGraph call submitted successfully for graph ID [{graph_id}]. Please note that the graph "
1717-
f"may take several minutes to become available again.\n")
1718-
print(json.dumps(res, indent=2, default=str))
1719-
store_to_ns(args.store_to, res, local_ns)
1720-
except Exception as e:
1721-
if not args.silent:
1722-
print("Received an error when attempting graph reset:")
1723-
print(e)
1724-
store_to_ns(args.store_to, e, local_ns)
1784+
self.reset(line, local_ns, service=NEPTUNE_ANALYTICS_SERVICE_NAME)
17251785

17261786
@magic_variables
17271787
@line_magic

src/graph_notebook/neptune/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -633,11 +633,11 @@ def perform_reset(self, token: str) -> requests.Response:
633633
res = self._http_session.send(req, verify=self.ssl_verify)
634634
return res
635635

636-
def reset_graph(self, graph_id: str = '', no_skip_snapshot: bool = False) -> dict:
636+
def reset_graph(self, graph_id: str = '', snapshot: bool = False) -> dict:
637637
try:
638638
res = self.neptune_graph_client.reset_graph(
639639
graphIdentifier=graph_id,
640-
skipSnapshot=(not no_skip_snapshot)
640+
skipSnapshot=(not snapshot)
641641
)
642642
return res
643643
except ClientError as e:

0 commit comments

Comments
 (0)