diff --git a/stack_orchestrator/deploy/webapp/__pycache__/__init__.cpython-310.pyc b/stack_orchestrator/deploy/webapp/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 00000000..a3247a54 Binary files /dev/null and b/stack_orchestrator/deploy/webapp/__pycache__/__init__.cpython-310.pyc differ diff --git a/stack_orchestrator/deploy/webapp/__pycache__/deploy_webapp.cpython-310.pyc b/stack_orchestrator/deploy/webapp/__pycache__/deploy_webapp.cpython-310.pyc new file mode 100644 index 00000000..d4f90fda Binary files /dev/null and b/stack_orchestrator/deploy/webapp/__pycache__/deploy_webapp.cpython-310.pyc differ diff --git a/stack_orchestrator/deploy/webapp/__pycache__/deploy_webapp_from_registry.cpython-310.pyc b/stack_orchestrator/deploy/webapp/__pycache__/deploy_webapp_from_registry.cpython-310.pyc new file mode 100644 index 00000000..dbd1a31d Binary files /dev/null and b/stack_orchestrator/deploy/webapp/__pycache__/deploy_webapp_from_registry.cpython-310.pyc differ diff --git a/stack_orchestrator/deploy/webapp/__pycache__/run_webapp.cpython-310.pyc b/stack_orchestrator/deploy/webapp/__pycache__/run_webapp.cpython-310.pyc new file mode 100644 index 00000000..0ea5bdf4 Binary files /dev/null and b/stack_orchestrator/deploy/webapp/__pycache__/run_webapp.cpython-310.pyc differ diff --git a/stack_orchestrator/deploy/webapp/__pycache__/undeploy_webapp_from_registry.cpython-310.pyc b/stack_orchestrator/deploy/webapp/__pycache__/undeploy_webapp_from_registry.cpython-310.pyc new file mode 100644 index 00000000..49942936 Binary files /dev/null and b/stack_orchestrator/deploy/webapp/__pycache__/undeploy_webapp_from_registry.cpython-310.pyc differ diff --git a/stack_orchestrator/deploy/webapp/__pycache__/util.cpython-310.pyc b/stack_orchestrator/deploy/webapp/__pycache__/util.cpython-310.pyc new file mode 100644 index 00000000..0cca3e33 Binary files /dev/null and b/stack_orchestrator/deploy/webapp/__pycache__/util.cpython-310.pyc differ diff --git a/stack_orchestrator/deploy/webapp/deploy_webapp_from_registry.py b/stack_orchestrator/deploy/webapp/deploy_webapp_from_registry.py index e4053336..f8dd796f 100644 --- a/stack_orchestrator/deploy/webapp/deploy_webapp_from_registry.py +++ b/stack_orchestrator/deploy/webapp/deploy_webapp_from_registry.py @@ -489,12 +489,9 @@ def command( # noqa: C901 else: deployments = laconic.app_deployments({"by": payment_address}) deployments_by_request = {} - deployments_by_payment = {} for d in deployments: if d.attributes.request: deployments_by_request[d.attributes.request] = d - if d.attributes.payment: - deployments_by_request[d.attributes.payment] = d # Find removal requests. main_logger.log("Discovering deployment removal and cancellation requests...") @@ -532,13 +529,7 @@ def command( # noqa: C901 if min_required_payment: for r in requests_to_check_for_payment: main_logger.log(f"{r.id}: Confirming payment...") - if r.attributes.payment in deployments_by_payment: - main_logger.log( - f"Skipping request {r.id}: payment already applied to deployment " - f"{deployments_by_payment[r.attributes.payment].id}" - ) - dump_known_requests(state_file, [r], status="UNPAID") - elif confirm_payment( + if confirm_payment( laconic, r, payment_address, min_required_payment, main_logger ): main_logger.log(f"{r.id}: Payment confirmed.") diff --git a/stack_orchestrator/deploy/webapp/undeploy_webapp_from_registry.py b/stack_orchestrator/deploy/webapp/undeploy_webapp_from_registry.py index 3580e5ca..631a2fef 100644 --- a/stack_orchestrator/deploy/webapp/undeploy_webapp_from_registry.py +++ b/stack_orchestrator/deploy/webapp/undeploy_webapp_from_registry.py @@ -25,6 +25,7 @@ from stack_orchestrator.deploy.webapp.util import ( LaconicRegistryClient, match_owner, skip_by_tag, + confirm_payment, ) main_logger = TimedLogger(file=sys.stderr) @@ -159,6 +160,23 @@ def dump_known_requests(filename, requests): help="Exclude requests with matching tags (comma-separated).", default="", ) +@click.option( + "--min-required-payment", + help="Requests must have a minimum payment to be processed", + default=0, +) +@click.option( + "--payment-address", + help="The address to which payments should be made. " + "Default is the current laconic account.", + default=None, +) +@click.option( + "--all-requests", + help="Handle requests addressed to anyone (by default only requests to" + "my payment address are examined).", + is_flag=True, +) @click.pass_context def command( # noqa: C901 ctx, @@ -173,6 +191,9 @@ def command( # noqa: C901 dry_run, include_tags, exclude_tags, + min_required_payment, + payment_address, + all_requests, ): if request_id and discover: print("Cannot specify both --request-id and --discover", file=sys.stderr) @@ -201,7 +222,10 @@ def command( # noqa: C901 # all requests elif discover: main_logger.log("Discovering removal requests...") - requests = laconic.app_deployment_removal_requests() + if all_requests: + requests = laconic.app_deployment_removal_requests() + else: + requests = laconic.app_deployment_removal_requests({"to": payment_address}) if only_update_state: if not dry_run: @@ -242,7 +266,7 @@ def command( # noqa: C901 else: one_per_deployment[r.attributes.deployment] = r - requests_to_execute = [] + requests_to_check_for_payment = [] for r in one_per_deployment.values(): try: if r.attributes.deployment not in named_deployments: @@ -267,7 +291,7 @@ def command( # noqa: C901 else: if r.id not in previous_requests: main_logger.log(f"Request {r.id} needs to processed.") - requests_to_execute.append(r) + requests_to_check_for_payment.append(r) else: main_logger.log( f"Skipping unsatisfied request {r.id} because we have seen it before." @@ -275,6 +299,21 @@ def command( # noqa: C901 except Exception as e: main_logger.log(f"ERROR examining {r.id}: {e}") + requests_to_execute = [] + if min_required_payment: + for r in requests_to_check_for_payment: + main_logger.log(f"{r.id}: Confirming payment...") + if confirm_payment( + laconic, r, payment_address, min_required_payment, main_logger + ): + main_logger.log(f"{r.id}: Payment confirmed.") + requests_to_execute.append(r) + else: + main_logger.log(f"Skipping request {r.id}: unable to verify payment.") + dump_known_requests(state_file, [r]) + else: + requests_to_execute = requests_to_check_for_payment + main_logger.log( "Found %d unsatisfied request(s) to process." % len(requests_to_execute) ) diff --git a/stack_orchestrator/deploy/webapp/util.py b/stack_orchestrator/deploy/webapp/util.py index 18e0566a..0d8c3317 100644 --- a/stack_orchestrator/deploy/webapp/util.py +++ b/stack_orchestrator/deploy/webapp/util.py @@ -93,6 +93,11 @@ def is_id(name_or_id: str): def confirm_payment(laconic, record, payment_address, min_amount, logger): + req_owner = laconic.get_owner(record) + if req_owner == payment_address: + # No need to confirm payment if the sender and recipient are the same account. + return True + if not record.attributes.payment: logger.log(f"{record.id}: no payment tx info") return False @@ -108,7 +113,6 @@ def confirm_payment(laconic, record, payment_address, min_amount, logger): ) return False - req_owner = laconic.get_owner(record) if tx.sender != req_owner: logger.log( f"{record.id}: payment sender {tx.sender} in tx {tx.hash} does not match deployment " @@ -136,6 +140,23 @@ def confirm_payment(laconic, record, payment_address, min_amount, logger): ) return False + # Check if the payment was already used on a + used = laconic.app_deployments( + {"by": payment_address, "payment": tx.hash}, all=True + ) + if len(used): + logger.log(f"{record.id}: payment {tx.hash} already used on deployment {used}") + return False + + used = laconic.app_deployment_removals( + {"by": payment_address, "payment": tx.hash}, all=True + ) + if len(used): + logger.log( + f"{record.id}: payment {tx.hash} already used on deployment removal {used}" + ) + return False + return True