API Reference
Generated from the docstrings in the package. Only modules reachable from a live
code path are listed; network/, compute/ec2.py, and several utils
modules are unreferenced by any current path and are scheduled for removal in
v0.8.0 (#90).
Provider
Parsl Ephemeral Provider implementation.
This module implements the main provider class that conforms to the Parsl execution provider interface.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.provider.ComputeType(*values)[source]
-
Supported compute resource types.
- EC2 = 'ec2'
- ECS = 'ecs'
- LAMBDA = 'lambda'
- class parsl_ephemeral_provider.provider.EphemeralProvider(image_id: str | None = None, instance_type: str = 't3.micro', region: str = 'us-east-1', mode: str = 'standard', min_blocks: int = 0, max_blocks: int = 10, init_blocks: int = 0, nodes_per_block: int = 1, worker_init: str = 'dnf install -y python3.11 python3.11-pip\nln -sf /usr/bin/python3.11 /usr/bin/python3\npip3.11 install --quiet --upgrade parsl\n', vpc_id: str | None = None, subnet_id: str | None = None, security_group_id: str | None = None, key_name: str | None = None, profile_name: str | None = None, endpoint_url: str | None = None, state_store_type: str = StateStoreType.FILE, state_file_path: str = 'ephemeral_aws_state.json', s3_bucket: str | None = None, s3_key: str = 'ephemeral_aws_state.json', s3_create_bucket: bool = False, parameter_store_path: str = '/parsl/ephemeral_aws_state', use_spot: bool = False, spot_max_price: str | None = None, spot_allocation_strategy: str = 'price-capacity-optimized', spot_interruption_handling: bool = False, use_spot_fleet: bool = False, instance_types: List[str] | None = None, spot_max_price_percentage: int | None = None, additional_tags: Dict[str, str] | None = None, auto_shutdown: bool = True, max_idle_time: int = 300, compute_type: str = ComputeType.EC2, bastion_instance_type: str = 't3.micro', idle_timeout: int = 30, preserve_bastion: bool = True, bastion_host_type: str = 'cloudformation', workflow_id: str | None = None, bastion_instance_profile_arn: str | None = None, memory_size: int = 1024, timeout: int = 300, lambda_runtime: str = 'python3.12', ecs_task_cpu: int = 1024, ecs_task_memory: int = 2048, ecs_container_image: str = 'python:3.12-slim', debug: bool = False, use_public_ips: bool = True, custom_ami: bool = False, provider_id: str | None = None, iam_instance_profile_arn: str | None = None, auto_create_instance_profile: bool = False, status_polling_interval: int = 60, waiter_delay: int = 5, waiter_max_attempts: int = 60, warm_pool_size: int = 0, warm_pool_ttl: int = 120, bake_ami: bool = False, baked_ami_id: str | None = None, one_shot: bool = False, cores_per_node: int | None = None, mem_per_node: float | None = None, **kwargs: Any)[source]
Bases:
ExecutionProvider,RepresentationMixinEphemeral AWS Provider for Parsl.
The Ephemeral AWS Provider allows Parsl to execute tasks on ephemeral AWS resources that are created on-demand and automatically cleaned up when no longer needed.
Parameters
- image_idstr, optional
EC2 AMI ID to use for instances. When omitted, the latest Amazon Linux 2023 AMI matching
instance_type’s architecture is resolved from AWS’s public SSM parameters. Supply one explicitly for a custom image, or for an instance family AL2023 does not cover (mac*.metal).- instance_typestr, optional
EC2 instance type. Default is ‘t3.micro’. Graviton (arm64) families are supported; the matching arm64 AMI is selected automatically.
- regionstr, optional
AWS region. Default is ‘us-east-1’.
- modestr, optional
Operating mode (‘standard’, ‘detached’, or ‘serverless’). Default is ‘standard’.
- min_blocksint, optional
Minimum number of blocks. Default is 0.
- max_blocksint, optional
Maximum number of blocks. Default is 10.
- worker_initstr, optional
Initialization script for workers. Default is an empty script.
- vpc_idstr
Existing VPC ID to use. Required, and pre-provisioned outside the provider: since #69 the provider creates no VPC, subnet, or security group. Omitting any of the three raises
ValueError.- subnet_idstr
Existing subnet ID to use. Required; see
vpc_id.- security_group_idstr
Existing security group ID to use. Required; see
vpc_id. It is never modified or deleted – a caller-supplied group is not the provider’s to touch (#100).The one exception to all three is
mode="serverless"withcompute_type="lambda": functions run in the Lambda-managed VPC, so there is nothing for the caller to pre-provision.- key_namestr, optional
EC2 key pair name for SSH access. If not provided, instances will be created without a key pair.
- profile_namestr, optional
AWS profile name to use. If not provided, the default profile will be used.
- endpoint_urlstr, optional
Override the endpoint every AWS client uses. Set this for VPC interface endpoints, FIPS endpoints, or to point the provider at an emulator such as substrate. Applies to clients the operating modes and compute managers build from the session too, not just the provider’s own. A caller that needs one service elsewhere can still override it per client.
- state_store_typestr, optional
Type of state store to use (‘file’, ‘parameter_store’, or ‘s3’). Default is ‘file’.
- state_file_pathstr, optional
Path to state file when using ‘file’ state store. Default is ‘ephemeral_aws_state.json’.
- s3_bucketstr, optional
S3 bucket name when using ‘s3’ state store.
- s3_keystr, optional
S3 key name when using ‘s3’ state store. Default is ‘ephemeral_aws_state.json’.
- s3_create_bucketbool, optional
Whether to create
s3_bucketif it does not exist, when using the ‘s3’ state store. Default isFalse, so a missing bucket is an error rather than something the provider quietly provisions.- parameter_store_pathstr, optional
Parameter Store path when using ‘parameter_store’ state store. Default is ‘/parsl/ephemeral_aws_state’.
- use_spotbool, optional
Whether to use spot instances. Default is False.
- spot_max_pricestr, optional
Maximum price for spot instances. Default is on-demand price.
- spot_allocation_strategystr, optional
Allocation strategy for spot instances, in kebab-case: one of ‘price-capacity-optimized’ (the default, and AWS’s recommendation), ‘capacity-optimized’, ‘capacity-optimized-prioritized’, ‘diversified’, or ‘lowest-price’. Converted to the camelCase spelling Spot Fleet requires at the API boundary.
- spot_interruption_handlingbool, optional
Whether to detect spot interruptions. Default is False. When enabled, an interrupted block is reported to Parsl as FAILED rather than COMPLETED, so the executor stops dispatching to it and re-runs the lost tasks under its own
retriessetting. No checkpointing is performed: a provider never sees task state, so re-running is the only recovery available at this layer. Setretrieson your Parsl config to make use of it.- additional_tagsDict[str, str], optional
Additional tags to apply to AWS resources.
- auto_shutdownbool, optional
Whether a worker terminates itself once its command finishes. Default is True, which appends
shutdown -h nowto the worker’s UserData; the instance launches withInstanceInitiatedShutdownBehavior=terminate, so it is terminated rather than stopped with a billed EBS volume. Set False only if you intend to keep instances after their work completes.- max_idle_timeint, optional
Deprecated and ignored; accepted only so existing configurations keep loading. Default is 300.
This never measured idleness. It was compared against a timestamp stamped once at submit, making it wall-clock age since submission, so it terminated any task that ran longer than the limit (#194). A provider cannot compute idleness – that needs per-manager task counts only Parsl’s interchange has. Use Parsl’s own
max_idletime, whichHighThroughputExecutor.scale_inapplies to genuinely idle blocks:from parsl.config import Config config = Config(executors=[...], max_idletime=300.0)
- compute_typestr, optional
Type of compute resource when using serverless mode (‘ec2’, ‘lambda’, or ‘ecs’). Default is ‘ec2’.
'lambda'and'ecs'are rejected on the other two modes, which launch EC2 instances; leaving it at'ec2'onmode="serverless"warns, becauseServerlessModethen falls back to its own'auto'selection rather than honouring the value.- bastion_instance_typestr, optional
Instance type for bastion host when using detached mode. Default is
't3.micro'.mode="detached"only.- idle_timeoutint, optional
Minutes of inactivity before the bastion shuts itself down. Default is 30.
mode="detached"only.- preserve_bastionbool, optional
Whether
cleanup_infrastructure()leaves the bastion running so a later session can adopt it. Default is True, which means the bastion survives shutdown and keeps billing — set False to have it torn down.mode="detached"only.- bastion_host_typestr, optional
How the bastion is deployed:
'cloudformation'(the default) or'direct'for a plainRunInstancescall.mode="detached"only.- workflow_idstr, optional
Workflow identifier used in bastion state paths and resource tags. Default is a UUID generated by the mode. Supply the same value to reconnect to an existing workflow’s bastion.
mode="detached"only.- bastion_instance_profile_arnstr, optional
Instance profile for the bastion to carry. Default is None, which creates one scoped to this workflow and deletes it with the bastion. A profile you supply is never deleted. Only used when
bastion_host_type='direct'; the CloudFormation path declares its own inside the stack.mode="detached"only.- memory_sizeint, optional
Memory size in MB for Lambda functions. Default is 1024. The provider-facing name for
ServerlessMode’slambda_memory.mode="serverless"only.- timeoutint, optional
Timeout in seconds for Lambda functions. Default is 300; Lambda’s own ceiling is 900. The provider-facing name for
lambda_timeout.mode="serverless"only.- lambda_runtimestr, optional
Runtime identifier for Lambda functions. Default is
'python3.12'. Must be one of theRuntimevalues allowed bytemplates/cloudformation/lambda_worker.yml.mode="serverless"only.- ecs_task_cpuint, optional
Fargate CPU units per task. Default is 1024 (1 vCPU).
mode="serverless"only.- ecs_task_memoryint, optional
Fargate memory per task in MB. Default is 2048. Must be a combination Fargate accepts for the chosen
ecs_task_cpu.mode="serverless"only.- ecs_container_imagestr, optional
Container image for Fargate tasks. Default is
'python:3.12-slim'. Set this to your own image to run a workload with its own dependencies — without it every task runs the stock image and can only use the standard library.mode="serverless"only.- debugbool, optional
Whether to enable debug logging. Default is False.
- use_public_ipsbool, optional
Whether to assign public IPs to instances. Default is True.
- custom_amibool, optional
Whether image_id refers to a custom AMI. Default is False.
- provider_idstr, optional
Provider ID for distinguishing between multiple providers. Default is a UUID.
- iam_instance_profile_arnstr, optional
ARN of an existing IAM instance profile to attach to EC2 instances. Required for SSM connectivity when using Session Manager tunneling.
- auto_create_instance_profilebool, optional
When True, automatically create an IAM role and instance profile with AmazonSSMManagedInstanceCore permissions if one does not already exist. Default is False.
- status_polling_intervalint, optional
Interval in seconds between status polls. Default is 60.
- waiter_delayint, optional
Seconds between waiter attempts when polling for resource state changes. Default is 5.
- waiter_max_attemptsint, optional
Maximum number of waiter attempts before raising an error. Default is 60 (5 minutes at the default delay).
- warm_pool_sizeint, optional
Maximum number of instances to keep warm after their job finishes, ready for immediate reuse without re-running worker_init. Requires
auto_create_instance_profile=Trueoriam_instance_profile_arn(SSM SendCommand needs an IAM role). Default is 0 (disabled).mode="standard"only.This costs money while idle. A warm instance is left Running, not Stopped, so it bills at the full instance rate for up to
warm_pool_ttlseconds after its job finishes —warm_pool_sizeinstances ×warm_pool_ttlseconds of instance time per idle period, whether or not another job ever arrives to use them. Capped atMAX_WARM_POOL_SIZE(20). Instances must stay Running because dispatch is SSMSendCommandand a Stopped instance runs no SSM agent; issue #130 tracks moving to a pull model so the pool can be Stopped instead.- warm_pool_ttlint, optional
Seconds a warm running instance stays alive before being terminated. Default is 120 (2 minutes); this was 600 in v0.6.0 and was reduced because the instance bills for the whole window.
mode="standard"only.- bake_amibool, optional
When True, run
worker_initon a builder instance duringinitialize(), snapshot it into a custom AMI, and use that AMI for all subsequent instance launches. Eliminates the per-boot install overhead for new instances. Default is False.mode="standard"only.- baked_ami_idstr, optional
Pre-existing baked AMI ID to use instead of baking a new one. When supplied,
initialize()skips the baking step and uses this AMI directly for all instance launches.mode="standard"only.- one_shotbool, optional
When True, each instance runs a single command over SSM and then terminates, so the command’s exit code determines the job status. Default is False.
mode="standard"only.
Raises
- ProviderConfigurationError
If
warm_pool_size,warm_pool_ttl,bake_ami,baked_ami_id, orone_shotis set on any mode other than"standard"— no other mode implements them.If
idle_timeout,preserve_bastion,bastion_host_type,workflow_id, orbastion_instance_profile_arnis set on any mode other than"detached", orlambda_runtime,ecs_task_cpu,ecs_task_memory, orecs_container_imageon any mode other than"serverless"— each is forwarded from one mode’s branch only, so it would silently have no effect.
Initialize the Ephemeral AWS Provider.
- __init__(image_id: str | None = None, instance_type: str = 't3.micro', region: str = 'us-east-1', mode: str = 'standard', min_blocks: int = 0, max_blocks: int = 10, init_blocks: int = 0, nodes_per_block: int = 1, worker_init: str = 'dnf install -y python3.11 python3.11-pip\nln -sf /usr/bin/python3.11 /usr/bin/python3\npip3.11 install --quiet --upgrade parsl\n', vpc_id: str | None = None, subnet_id: str | None = None, security_group_id: str | None = None, key_name: str | None = None, profile_name: str | None = None, endpoint_url: str | None = None, state_store_type: str = StateStoreType.FILE, state_file_path: str = 'ephemeral_aws_state.json', s3_bucket: str | None = None, s3_key: str = 'ephemeral_aws_state.json', s3_create_bucket: bool = False, parameter_store_path: str = '/parsl/ephemeral_aws_state', use_spot: bool = False, spot_max_price: str | None = None, spot_allocation_strategy: str = 'price-capacity-optimized', spot_interruption_handling: bool = False, use_spot_fleet: bool = False, instance_types: List[str] | None = None, spot_max_price_percentage: int | None = None, additional_tags: Dict[str, str] | None = None, auto_shutdown: bool = True, max_idle_time: int = 300, compute_type: str = ComputeType.EC2, bastion_instance_type: str = 't3.micro', idle_timeout: int = 30, preserve_bastion: bool = True, bastion_host_type: str = 'cloudformation', workflow_id: str | None = None, bastion_instance_profile_arn: str | None = None, memory_size: int = 1024, timeout: int = 300, lambda_runtime: str = 'python3.12', ecs_task_cpu: int = 1024, ecs_task_memory: int = 2048, ecs_container_image: str = 'python:3.12-slim', debug: bool = False, use_public_ips: bool = True, custom_ami: bool = False, provider_id: str | None = None, iam_instance_profile_arn: str | None = None, auto_create_instance_profile: bool = False, status_polling_interval: int = 60, waiter_delay: int = 5, waiter_max_attempts: int = 60, warm_pool_size: int = 0, warm_pool_ttl: int = 120, bake_ami: bool = False, baked_ami_id: str | None = None, one_shot: bool = False, cores_per_node: int | None = None, mem_per_node: float | None = None, **kwargs: Any) None[source]
Initialize the Ephemeral AWS Provider.
- __repr__() str[source]
Return string representation of the provider.
Returns
- str
String representation.
- cancel(job_ids: Sequence[object]) List[bool][source]
Cancel specified jobs.
Parameters
- job_idsSequence[object]
Job identifiers to cancel. Typed as
objectto match Parsl’sExecutionProvider; an ID this provider never issued reportsFalserather than raising.
Returns
- List[bool]
True for each job_id where cancellation was accepted, False otherwise.
- list_resources() Dict[str, List[Dict[str, Any]]][source]
List all resources created by this provider.
Returns
- Dict[str, List[Dict[str, Any]]]
Dictionary of resource types and their details.
- scale_in(blocks: int) List[str][source]
Scale in the number of blocks by the specified amount.
Parameters
- blocksint
Number of blocks to scale in by.
Returns
- List[str]
List of job IDs that were terminated.
- scale_out(blocks: int) List[str][source]
Scale out resources by the specified number of blocks.
Parameters
- blocksint
Number of blocks to scale out by.
Returns
- List[str]
List of job IDs for the new resources.
- status(job_ids: Sequence[object]) List[JobStatus][source]
Get the status of a list of jobs.
Parameters
- job_idsSequence[object]
Job identifiers as returned by
submit(). Typed asobjectto match Parsl’sExecutionProvider, which treats job IDs as opaque; this provider issues strings, so anything else resolves toJobState.UNKNOWNrather than raising.
Returns
- List[JobStatus]
List of JobStatus objects corresponding to each job_id.
- property status_polling_interval: int
Return the status polling interval for the provider.
Returns
- int
Polling interval in seconds.
- submit(command: str, tasks_per_node: int, job_name: str = 'parsl.auto') str[source]
Submit a job to execute the specified command.
Parameters
- commandstr
Command to execute.
- tasks_per_nodeint
Number of tasks to run per node.
- job_namestr
Human-friendly name for the job request. Defaults to Parsl’s
"parsl.auto"sentinel, which is replaced with a unique generated name.
Returns
- str
Job ID for tracking status.
- class parsl_ephemeral_provider.provider.OperatingModeType(*values)[source]
-
Supported operating modes for the provider.
- DETACHED = 'detached'
- SERVERLESS = 'serverless'
- STANDARD = 'standard'
- class parsl_ephemeral_provider.provider.StateStoreType(*values)[source]
-
Supported state persistence options.
- FILE = 'file'
- PARAMETER_STORE = 'parameter_store'
- S3 = 's3'
Parsl Ephemeral Compute Provider for Globus Compute.
An independent Parsl provider for running ephemeral compute on AWS through Globus Compute. AWS stays named here because it is the platform the compute actually runs on – this is a subclass of the AWS provider, not an alternative to it – and because a description is exactly where the AWS Trademark Guidelines permit the mark (s13, plain-text factual reference); s7 keeps it out of the identifiers.
Exposes EphemeralComputeProvider, a thin subclass of EphemeralProvider
that:
Carries
endpoint_idandcontainer_imagemetadata for Globus Compute.Provides
generate_endpoint_config(path)which writes a Globus Compute endpoint configuration theglobus-compute-endpointdaemon can load.
Usage:
from parsl_ephemeral_provider import EphemeralComputeProvider
provider = EphemeralComputeProvider(
endpoint_id="<your-globus-endpoint-uuid>",
region="us-east-1",
instance_type="t3.medium",
mode="standard",
vpc_id="vpc-...",
subnet_id="subnet-...",
security_group_id="sg-...",
use_spot=True,
auto_create_instance_profile=True,
display_name="My Ephemeral AWS Endpoint",
)
provider.generate_endpoint_config("~/.globus_compute/my_aws_endpoint")
The shape of a startable endpoint
Every endpoint globus-compute-endpoint 4.15.0 can start is a manager
endpoint (MEP). The classification is made by one key: load_config_yaml()
pops engine and picks ManagerEndpointConfig when it is absent,
UserEndpointConfig when it is present. start then refuses anything that
is not a ManagerEndpointConfig (cli.py:899), and the only other entry
point – _start-user-endpoint – reads its config from stdin and is invoked
solely by a running manager. So a config.yaml carrying a top-level
engine: block cannot be started at all: that was #196.
generate_endpoint_config() therefore writes the manager/template pair
upstream’s own configure produces:
config.yamlManager configuration.
display_nameand nothing else that matters – upstream’s packageddefault_config.yamlis the single linedisplay_name: null.user_config_template.yaml.j2The
engine:block, including theprovider:sub-block that names this class. The manager renders this per user endpoint.
How Globus Compute finds this provider
Globus Compute resolves the provider: type: key by plain attribute lookup on
the parsl.providers module – getattr(parsl.providers, type_name, None),
raising if the result is None
(globus_compute_endpoint/endpoint/config/dispatch.py). Two consequences,
both verified against 4.15.0:
A dotted path can never resolve, because
getattrdoes not walk dots. The type key must therefore be the bare class name.The bare name only resolves if something has already assigned the class onto
parsl.providers. Importing this package does that (see_register_with_parsl_providers()), but nothing in the endpoint’s own startup has a reason to import it.
The template is rendered and loaded in a different interpreter from the
manager: EndpointManager forks and os.execvpe``s ``globus-compute-endpoint
_start-user-endpoint <name>, and that child calls load_config_yaml() on
the rendered string handed to it on stdin. So the config.py shim this
package used to write (#87) cannot help – get_config() is never reached in
the child, and the import has to happen before its first line of user code.
The seam that does reach it is user_environment.yaml, which the manager
reads and merges into the child’s environment immediately before execvpe
(endpoint_manager.py:1069). generate_endpoint_config() writes a
PYTHONPATH there pointing at a _bootstrap/ directory holding a
sitecustomize.py whose body is import parsl_ephemeral_provider – so the
interpreter registers the class during site initialisation, before the
config is parsed. Verified in a genuinely fresh interpreter: with the
PYTHONPATH the bare name resolves, without it getattr returns None.
Dotted-path support upstream (#133) would make the bootstrap unnecessary. Until then this is what makes a generated endpoint start.
One platform caveat: start requires pyprctl, which is Linux-only, so on
macOS it exits “multi-user endpoints are not supported on this system” before
reading any configuration. Generation works anywhere; running an endpoint needs
Linux, and that is true of every 4.15.0 endpoint, not just these.
Minimum IAM permissions
EphemeralComputeProvider.minimum_iam_policy() returns these as a policy
document. The lists are derived from the AWS API calls the package actually
makes on the mode="standard" path, which is what a generated endpoint
config uses; AWS may require further implicit permissions.
- EC2 (always required)
ec2:RunInstances, ec2:TerminateInstances, ec2:DescribeInstances, ec2:DescribeInstanceTypes, ec2:CreateTags, ec2:DescribeTags, ec2:DescribeImages, ec2:CreateImage, ec2:DeregisterImage, ec2:DeleteSnapshot, ec2:DescribeVpcs, ec2:DescribeSubnets, ec2:DescribeSecurityGroups, ec2:CreateLaunchTemplate, ec2:CreateLaunchTemplateVersion, ec2:DeleteLaunchTemplate, ec2:CreateFleet, ec2:DescribeFleets, ec2:DeleteFleets, ec2:RequestSpotInstances, ec2:DescribeSpotInstanceRequests, ec2:DescribeSpotPriceHistory
The network resources are read-only:
vpc_id,subnet_idandsecurity_group_idhave been caller-supplied since v0.7.0, so no create/delete grant is needed for them.- SSM (required)
ssm:GetParameter (resolves the current Amazon Linux 2023 AMI), ssm:SendCommand, ssm:GetCommandInvocation, ssm:DescribeInstanceInformation (warm-pool and one-shot dispatch), ssm:PutParameter, ssm:DeleteParameter, ssm:DeleteParameters (
state_store_type="parameter_store")No Session Manager grants. ssm:StartSession, TerminateSession, ResumeSession, DescribeSessions and GetConnectionStatus were listed here for “Session Manager tunnels”, but no such transport exists in this package and nothing calls them (#195).
- STS (always required)
sts:GetCallerIdentity –
create_session()verifies every session with it, so this is the first AWS call the provider makes.- EventBridge + SQS (required when use_spot and spot_interruption_handling)
events:PutRule, events:PutTargets, events:RemoveTargets, events:DeleteRule, events:TagResource, sqs:CreateQueue, sqs:GetQueueAttributes, sqs:SetQueueAttributes, sqs:ReceiveMessage, sqs:DeleteMessage, sqs:DeleteQueue
- IAM (required when auto_create_instance_profile=True)
iam:CreateRole, iam:GetRole, iam:AttachRolePolicy, iam:CreateInstanceProfile, iam:GetInstanceProfile, iam:AddRoleToInstanceProfile, iam:PassRole, iam:RemoveRoleFromInstanceProfile, iam:DeleteInstanceProfile, iam:ListAttachedRolePolicies, iam:DetachRolePolicy, iam:ListRolePolicies, iam:DeleteRolePolicy, iam:DeleteRole
The teardown half is required, not optional:
cleanup_infrastructure()deletes the pair it created (#132), and cleanup logs rather than raises, so a missing delete grant leaks a standing privileged principal silently (#195).- ECR (only when container_image references an ECR repository)
ecr:GetAuthorizationToken, ecr:BatchGetImage, ecr:GetDownloadUrlForLayer, ecr:BatchCheckLayerAvailability
Not covered by minimum_iam_policy(): state_store_type="s3" (needs S3
object access), mode="detached" (CloudFormation stack management), and
mode="serverless" (Lambda, ECS, CloudWatch Logs, and IAM role lifecycle).
The Parameter Store backend is covered now – it was listed here as uncovered
while the policy also omitted the actions, so the omission read as deliberate
(#195).
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.globus_compute.EphemeralComputeProvider(endpoint_id: str | None = None, container_image: str | None = None, display_name: str = 'Ephemeral AWS Endpoint', encrypted: bool = False, **kwargs: Any)[source]
Bases:
EphemeralProviderGlobus Compute-aware wrapper around
EphemeralProvider.Extends
EphemeralProviderwith Globus Compute endpoint metadata and a helper that generates a ready-to-start endpoint directory for theglobus-compute-endpointdaemon.All
EphemeralProviderconstructor parameters are accepted as-is (forwarded via**kwargs).Parameters
- endpoint_idstr, optional
Globus Compute endpoint UUID. Optional, and it is not a configuration key – Globus Compute’s
BaseConfigrejectsendpoint_id, and the UUID lives inendpoint.jsonwritten during registration. When set, the generatedconfig.yamlrecords it as a comment together with the--endpoint-uuidinvocation that adopts it; when unset,startregisters the endpoint and assigns one.- container_imagestr, optional
Container image URI to run Parsl workers inside a container. Examples:
"python:3.11-slim","123456789.dkr.ecr.us-east-1.amazonaws.com/my-image:latest". When set, the generateduser_config_template.yaml.j2includescontainer_type: dockerandcontainer_uri: <image>under theengineblock.- display_namestr, optional
Human-readable name for the Globus Compute endpoint. Default is
"Ephemeral AWS Endpoint".- encryptedbool, optional
Whether the engine encrypts worker traffic with CurveZMQ. Default is
False, and that default is deliberate:HighThroughputExecutorgenerates the certificates under its ownrun_diron the endpoint host and passes that path to workers as--cert_dir, so an EC2 worker is handed a directory that does not exist on it and dies withFileNotFoundError. Until certificate distribution is implemented (#62),Truecannot work for remote workers and rely on VPC isolation instead. This was hardcodedtruebefore #138, which made every generated config unusable.High-Assurance endpoints are the exception –
assert_ha_compliant()rejectsencrypted=False, so those need #62 resolved rather than this default.- **kwargs
All keyword arguments accepted by
EphemeralProvider.
Initialize the Ephemeral AWS Provider.
- generate_endpoint_config(path: str) str[source]
Write a startable Globus Compute endpoint configuration to path.
Creates the directory at path if it does not exist, then writes four files into it:
config.yamlManager configuration:
display_name, and nothing else. Deliberately thin – upstream’s own packaged default is the single linedisplay_name: null.user_config_template.yaml.j2The
engine:block and itsprovider:sub-block, which is where all the AWS configuration lives. The file to edit.user_environment.yamlA
PYTHONPATHpointing at_bootstrap/._bootstrap/sitecustomize.pyimport parsl_ephemeral_provider, which registersEphemeralComputeProvideronparsl.providers.
The split between the first two is not cosmetic: an
engine:key inconfig.yamlmakesload_config_yaml()return aUserEndpointConfig, andstartrejects anything that is not aManagerEndpointConfig– so the previous single-file output could never be started (#196). The last two exist because the process that loads the template is a fresh interpreter that never imports this package; see the module docstring.Returns the absolute path to
user_config_template.yaml.j2– the file a caller would want to read or edit, and the one holding everything this class configures.The result is ready for the
globus-compute-endpointdaemon:globus-compute-endpoint start my_aws_endpoint
Parameters
- pathstr
Path to the Globus Compute endpoint directory (e.g.
"~/.globus_compute/my_aws_endpoint").
Returns
- str
Absolute path to the written
user_config_template.yaml.j2.
- label = 'globus_compute_aws'
- static minimum_iam_policy(include_ecr: bool = False) Dict[str, Any][source]
Return the minimum IAM policy document as a Python dict.
The returned dict can be serialised to JSON and attached to the IAM principal that runs the provider – the user, role, or endpoint host that calls
submit(). It is not the instance role: workers need onlyAmazonSSMManagedInstanceCore, whichauto_create_instance_profile=Trueattaches for them.Scope: the
mode="standard"path, which is what a generated endpoint config uses, with either file-backed or Parameter Store state. Actions were derived from the package’s actual API calls, so the set is narrower than it was before v0.7.0 – network resources are caller-supplied since #69, so no VPC/subnet/security-group/NAT/gateway create or delete grant appears, and Spot Fleet was replaced by EC2 Fleet in #86. See the module docstring for what is deliberately not covered (the S3 state backend, and detached and serverless modes).Every action here has a call site in the package, and the teardown actions matter as much as the create ones: cleanup logs rather than raises, so a missing delete permission leaks resources silently. That is what #195 found – this method granted
iam:CreateRoleandiam:CreateInstanceProfilewith no corresponding deletes, so a user on this policy reproduced the very leak #132 had just fixed.Parameters
- include_ecrbool
When
True, include ECR permissions required to pull images from a private ECR repository (needed whencontainer_imagereferences an ECR URI).
Returns
- dict
IAM policy document compatible with
json.dumps().
Operating modes
Base operating mode interface for the EphemeralProvider.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.modes.base.OperatingMode(provider_id: str, session: Session, state_store: StateStore, image_id: str | None = None, instance_type: str = 't3.micro', worker_init: str = '', vpc_id: str | None = None, subnet_id: str | None = None, security_group_id: str | None = None, key_name: str | None = None, use_spot: bool = False, spot_max_price: str | None = None, spot_allocation_strategy: str = 'price-capacity-optimized', spot_interruption_handling: bool = False, additional_tags: Dict[str, str] | None = None, auto_shutdown: bool = True, max_idle_time: int = 300, use_public_ips: bool = True, custom_ami: bool = False, debug: bool = False, region: str | None = None, require_network_resources: bool = True, **kwargs: Any)[source]
Bases:
ABCAbstract base class for provider operating modes.
An operating mode defines how the provider interacts with AWS resources to execute jobs. Different modes have different trade-offs in terms of cost, performance, and capabilities.
Attributes
- provider_idstr
Unique identifier for the provider instance
- sessionboto3.Session
AWS session for API calls
- state_storeStateStore
Store for persisting state
- image_idOptional[str]
EC2 AMI ID to use for instances
- instance_typestr
EC2 instance type for compute resources
- worker_initstr
Script to execute during worker initialization
- vpc_idOptional[str]
Existing VPC ID to use
- subnet_idOptional[str]
Existing subnet ID to use
- security_group_idOptional[str]
Existing security group ID to use
- key_nameOptional[str]
EC2 key pair name for SSH access
- use_spotbool
Whether to use spot instances
- spot_max_priceOptional[str]
Maximum price for spot instances
- spot_allocation_strategystr
Allocation strategy for spot instances
- spot_interruption_handlingbool
Whether to detect spot interruptions and mark the affected block failed
- additional_tagsDict[str, str]
Tags to apply to created resources
- auto_shutdownbool
Whether a worker terminates itself once its command finishes
- max_idle_timeint
Deprecated and ignored; retained so older state files still load (#194)
- use_public_ipsbool
Whether to assign public IPs to instances
- custom_amibool
Whether image_id refers to a custom AMI
- debugbool
Whether to enable debug logging
Initialize the operating mode.
Parameters
- provider_idstr
Unique identifier for the provider instance
- sessionboto3.Session
AWS session for API calls
- state_storeStateStore
Store for persisting state
- image_idOptional[str], optional
EC2 AMI ID to use for instances, by default None
- instance_typestr, optional
EC2 instance type for compute resources, by default “t3.micro”
- worker_initstr, optional
Script to execute during worker initialization, by default “”
- vpc_idOptional[str], optional
Existing VPC ID to use, by default None
- subnet_idOptional[str], optional
Existing subnet ID to use, by default None
- security_group_idOptional[str], optional
Existing security group ID to use, by default None
- key_nameOptional[str], optional
EC2 key pair name for SSH access, by default None
- use_spotbool, optional
Whether to use spot instances, by default False
- spot_max_priceOptional[str], optional
Maximum price for spot instances, by default None
- spot_allocation_strategystr, optional
Allocation strategy for spot instances, in kebab-case, by default “price-capacity-optimized”
- spot_interruption_handlingbool, optional
Whether to detect spot interruptions, by default False. Detection marks the affected block STATUS_INTERRUPTED, which the provider reports to Parsl as FAILED so it re-runs the lost tasks.
- additional_tagsOptional[Dict[str, str]], optional
Tags to apply to created resources, by default None
- auto_shutdownbool, optional
Whether a worker terminates itself once its command finishes, by default True
- max_idle_timeint, optional
Deprecated and ignored, by default 300. Nothing reads it; it is kept so state files written by earlier versions still load. Use Parsl’s own
max_idletimeto reclaim idle blocks (#194).- use_public_ipsbool, optional
Whether to assign public IPs to instances, by default True
- custom_amibool, optional
Whether image_id refers to a custom AMI, by default False
- debugbool, optional
Whether to enable debug logging, by default False
- require_network_resourcesbool, optional
Whether vpc_id, subnet_id, and security_group_id are mandatory, by default True. Subclasses whose compute backend supplies its own networking (e.g. Lambda-only serverless mode) pass False.
- __init__(provider_id: str, session: Session, state_store: StateStore, image_id: str | None = None, instance_type: str = 't3.micro', worker_init: str = '', vpc_id: str | None = None, subnet_id: str | None = None, security_group_id: str | None = None, key_name: str | None = None, use_spot: bool = False, spot_max_price: str | None = None, spot_allocation_strategy: str = 'price-capacity-optimized', spot_interruption_handling: bool = False, additional_tags: Dict[str, str] | None = None, auto_shutdown: bool = True, max_idle_time: int = 300, use_public_ips: bool = True, custom_ami: bool = False, debug: bool = False, region: str | None = None, require_network_resources: bool = True, **kwargs: Any) None[source]
Initialize the operating mode.
Parameters
- provider_idstr
Unique identifier for the provider instance
- sessionboto3.Session
AWS session for API calls
- state_storeStateStore
Store for persisting state
- image_idOptional[str], optional
EC2 AMI ID to use for instances, by default None
- instance_typestr, optional
EC2 instance type for compute resources, by default “t3.micro”
- worker_initstr, optional
Script to execute during worker initialization, by default “”
- vpc_idOptional[str], optional
Existing VPC ID to use, by default None
- subnet_idOptional[str], optional
Existing subnet ID to use, by default None
- security_group_idOptional[str], optional
Existing security group ID to use, by default None
- key_nameOptional[str], optional
EC2 key pair name for SSH access, by default None
- use_spotbool, optional
Whether to use spot instances, by default False
- spot_max_priceOptional[str], optional
Maximum price for spot instances, by default None
- spot_allocation_strategystr, optional
Allocation strategy for spot instances, in kebab-case, by default “price-capacity-optimized”
- spot_interruption_handlingbool, optional
Whether to detect spot interruptions, by default False. Detection marks the affected block STATUS_INTERRUPTED, which the provider reports to Parsl as FAILED so it re-runs the lost tasks.
- additional_tagsOptional[Dict[str, str]], optional
Tags to apply to created resources, by default None
- auto_shutdownbool, optional
Whether a worker terminates itself once its command finishes, by default True
- max_idle_timeint, optional
Deprecated and ignored, by default 300. Nothing reads it; it is kept so state files written by earlier versions still load. Use Parsl’s own
max_idletimeto reclaim idle blocks (#194).- use_public_ipsbool, optional
Whether to assign public IPs to instances, by default True
- custom_amibool, optional
Whether image_id refers to a custom AMI, by default False
- debugbool, optional
Whether to enable debug logging, by default False
- require_network_resourcesbool, optional
Whether vpc_id, subnet_id, and security_group_id are mandatory, by default True. Subclasses whose compute backend supplies its own networking (e.g. Lambda-only serverless mode) pass False.
- abstractmethod cancel_jobs(resource_ids: List[str]) Dict[str, str][source]
Cancel jobs.
Parameters
- resource_idsList[str]
List of resource IDs to cancel
Returns
- Dict[str, str]
Dictionary mapping resource IDs to status strings
- abstractmethod cleanup_infrastructure() None[source]
Clean up infrastructure created by this mode.
This should clean up any VPC, subnets, security groups, etc. created by the mode.
- abstractmethod cleanup_resources(resource_ids: List[str]) None[source]
Clean up resources.
Parameters
- resource_idsList[str]
List of resource IDs to clean up
- delete_state() None[source]
Delete the state stored under the mode’s own state key.
Called on provider shutdown. The provider deletes its own key separately; leaving either behind strands a document that describes resources which no longer exist.
- ensure_initialized() None[source]
Ensure the mode is initialized.
Raises
- OperatingModeError
If initialization fails
- abstractmethod get_job_status(resource_ids: List[str]) Dict[str, str][source]
Get the status of jobs.
Parameters
- resource_idsList[str]
List of resource IDs to check
Returns
- Dict[str, str]
Dictionary mapping resource IDs to status strings
- handle_fleet_interruption(fleet_id: str, instance_ids: List[str], event: Dict[str, Any]) None[source]
Mark a fleet’s block, and each warned instance, interrupted.
Both are marked: the block is what Parsl holds a job ID for, while the instances are what the monitor names, and either may be the tracked resource depending on the launch path.
A fleet ID is almost never a resource key.
resourcesis keyed by block ID in StandardMode and byserverless-<job_id>in the other two, with the fleet recorded as afleet_request_idfield on the record – so a directresources[fleet_id]lookup misses every time and the block would keep reporting healthy while AWS took its capacity away. The field is searched instead.Parameters
- fleet_idstr
The fleet AWS has warned about.
- instance_idsList[str]
Instances within the fleet being reclaimed.
- eventDict[str, Any]
The interruption event, logged for diagnosis.
- handle_instance_interruption(instance_id: str, event: Dict[str, Any]) None[source]
Mark instance_id interrupted so the block stops being dispatched to.
Registered with
SpotInterruptionMonitoras the per-instance callback and invoked on the two-minute reclaim warning, roughly 15 s after AWS issues it.Marking the resource is the whole response, and it is the useful one:
get_job_statusreportsSTATUS_INTERRUPTED, the provider maps that toJobState.FAILED, and Parsl stops dispatching to the block and re-runs its tasks under the executor’s ownretries. Nothing here needs S3.Without this the interruption was invisible rather than merely unhandled: the instance moves to
shutting-down, whichEC2_STATUS_MAPPINGrendersCOMPLETED, so a reclaimed block reported success and its tasks were dropped silently (#137).Parameters
- instance_idstr
The instance AWS has warned about.
- eventDict[str, Any]
The interruption event, logged for diagnosis.
- abstractmethod initialize() None[source]
Initialize mode-specific resources.
This method should create any resources needed for the mode to operate, such as VPC, subnets, security groups, etc.
Raises
- ResourceCreationError
If resource creation fails
- abstractmethod list_resources() Dict[str, List[Dict[str, Any]]][source]
List all resources created by this mode.
Returns
- Dict[str, List[Dict[str, Any]]]
Dictionary of resource types and their details
- load_state() bool[source]
Load state from the mode’s own state key.
Returns
- bool
True if state was loaded successfully, False otherwise
- save_state() None[source]
Save the current state under the mode’s own state key.
The provider writes
STATE_KEY_PROVIDERseparately; seeEphemeralProvider._save_state.
- abstractmethod submit_job(job_id: str, command: str, tasks_per_node: int, job_name: str | None = None) str[source]
Submit a job for execution.
Parameters
- job_idstr
Unique identifier for the job
- commandstr
Command to execute
- tasks_per_nodeint
Number of tasks to run per node
- job_nameOptional[str], optional
Human-readable name for the job, by default None
Returns
- str
Resource ID for tracking the job
Raises
- OperatingModeError
If job submission fails
Standard operating mode for the EphemeralProvider.
The standard mode uses EC2 instances for computation with direct communication between the client and worker nodes.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.modes.standard.StandardMode(provider_id: str, session: Session, state_store: Any, image_id: str | None = None, instance_type: str = 't3.micro', worker_init: str = '', vpc_id: str | None = None, subnet_id: str | None = None, security_group_id: str | None = None, key_name: str | None = None, use_spot: bool = False, spot_max_price: str | None = None, spot_allocation_strategy: str = 'price-capacity-optimized', additional_tags: Dict[str, str] | None = None, auto_shutdown: bool = True, max_idle_time: int = 300, use_public_ips: bool = True, custom_ami: bool = False, debug: bool = False, use_spot_fleet: bool = False, instance_types: List[str] | None = None, nodes_per_block: int = 1, spot_max_price_percentage: int | None = None, warm_pool_size: int = 0, warm_pool_ttl: int = 600, iam_instance_profile_arn: str | None = None, auto_create_instance_profile: bool = False, bake_ami: bool = False, baked_ami_id: str | None = None, one_shot: bool = False, **kwargs: Any)[source]
Bases:
OperatingModeStandard operating mode implementation.
In standard mode, EC2 instances are created for computation with direct communication between the client and worker nodes.
This mode supports regular EC2 instances, spot instances, and spot fleet requests for more reliable and cost-effective computation.
Initialize the standard mode.
Parameters
- provider_idstr
Unique identifier for the provider instance
- sessionboto3.Session
AWS session for API calls
- state_storeAny
Store for persisting state
- image_idOptional[str], optional
EC2 AMI ID to use for instances, by default None
- instance_typestr, optional
EC2 instance type for compute resources, by default “t3.micro”
- worker_initstr, optional
Script to execute during worker initialization, by default “”
- vpc_idOptional[str], optional
Existing VPC ID to use, by default None
- subnet_idOptional[str], optional
Existing subnet ID to use, by default None
- security_group_idOptional[str], optional
Existing security group ID to use, by default None
- key_nameOptional[str], optional
EC2 key pair name for SSH access, by default None
- use_spotbool, optional
Whether to use spot instances, by default False
- spot_max_priceOptional[str], optional
Maximum price for spot instances, by default None
- spot_allocation_strategystr, optional
Allocation strategy for spot instances, in kebab-case, by default “price-capacity-optimized”
- additional_tagsOptional[Dict[str, str]], optional
Tags to apply to created resources, by default None
- auto_shutdownbool, optional
Whether a worker terminates itself once its command finishes, by default True. Appends
shutdown -h nowto the worker’s UserData.- max_idle_timeint, optional
Deprecated and ignored, by default 300. Use Parsl’s own
max_idletimeto reclaim idle blocks (#194).- use_public_ipsbool, optional
Whether to assign public IPs to instances, by default True
- custom_amibool, optional
Whether image_id refers to a custom AMI, by default False
- debugbool, optional
Whether to enable debug logging, by default False
- use_spot_fleetbool, optional
Whether to use Spot Fleet for spot instances, by default False
- instance_typesOptional[List[str]], optional
List of instance types to use with Spot Fleet, by default None
- nodes_per_blockint, optional
Number of nodes per block, by default 1
- spot_max_price_percentageOptional[int], optional
Maximum spot price as a percentage of on-demand price, by default None
- warm_pool_sizeint, optional
Number of idle instances to keep for reuse, by default 0 (disabled)
- warm_pool_ttlint, optional
Seconds a warm instance is kept before termination, by default 600
- iam_instance_profile_arnOptional[str], optional
Instance profile ARN granting SSM access, by default None
- auto_create_instance_profilebool, optional
Whether to create an instance profile with the
AmazonSSMManagedInstanceCorepolicy wheniam_instance_profile_arnis not supplied, by default False. SSMSendCommanddispatch cannot work without one of the two.- bake_amibool, optional
Whether to pre-install
worker_initinto a custom AMI, by default False- baked_ami_idOptional[str], optional
Pre-baked AMI to use instead of baking one, by default None
- one_shotbool, optional
Whether to dispatch a single command per instance and terminate, by default False
- __init__(provider_id: str, session: Session, state_store: Any, image_id: str | None = None, instance_type: str = 't3.micro', worker_init: str = '', vpc_id: str | None = None, subnet_id: str | None = None, security_group_id: str | None = None, key_name: str | None = None, use_spot: bool = False, spot_max_price: str | None = None, spot_allocation_strategy: str = 'price-capacity-optimized', additional_tags: Dict[str, str] | None = None, auto_shutdown: bool = True, max_idle_time: int = 300, use_public_ips: bool = True, custom_ami: bool = False, debug: bool = False, use_spot_fleet: bool = False, instance_types: List[str] | None = None, nodes_per_block: int = 1, spot_max_price_percentage: int | None = None, warm_pool_size: int = 0, warm_pool_ttl: int = 600, iam_instance_profile_arn: str | None = None, auto_create_instance_profile: bool = False, bake_ami: bool = False, baked_ami_id: str | None = None, one_shot: bool = False, **kwargs: Any) None[source]
Initialize the standard mode.
Parameters
- provider_idstr
Unique identifier for the provider instance
- sessionboto3.Session
AWS session for API calls
- state_storeAny
Store for persisting state
- image_idOptional[str], optional
EC2 AMI ID to use for instances, by default None
- instance_typestr, optional
EC2 instance type for compute resources, by default “t3.micro”
- worker_initstr, optional
Script to execute during worker initialization, by default “”
- vpc_idOptional[str], optional
Existing VPC ID to use, by default None
- subnet_idOptional[str], optional
Existing subnet ID to use, by default None
- security_group_idOptional[str], optional
Existing security group ID to use, by default None
- key_nameOptional[str], optional
EC2 key pair name for SSH access, by default None
- use_spotbool, optional
Whether to use spot instances, by default False
- spot_max_priceOptional[str], optional
Maximum price for spot instances, by default None
- spot_allocation_strategystr, optional
Allocation strategy for spot instances, in kebab-case, by default “price-capacity-optimized”
- additional_tagsOptional[Dict[str, str]], optional
Tags to apply to created resources, by default None
- auto_shutdownbool, optional
Whether a worker terminates itself once its command finishes, by default True. Appends
shutdown -h nowto the worker’s UserData.- max_idle_timeint, optional
Deprecated and ignored, by default 300. Use Parsl’s own
max_idletimeto reclaim idle blocks (#194).- use_public_ipsbool, optional
Whether to assign public IPs to instances, by default True
- custom_amibool, optional
Whether image_id refers to a custom AMI, by default False
- debugbool, optional
Whether to enable debug logging, by default False
- use_spot_fleetbool, optional
Whether to use Spot Fleet for spot instances, by default False
- instance_typesOptional[List[str]], optional
List of instance types to use with Spot Fleet, by default None
- nodes_per_blockint, optional
Number of nodes per block, by default 1
- spot_max_price_percentageOptional[int], optional
Maximum spot price as a percentage of on-demand price, by default None
- warm_pool_sizeint, optional
Number of idle instances to keep for reuse, by default 0 (disabled)
- warm_pool_ttlint, optional
Seconds a warm instance is kept before termination, by default 600
- iam_instance_profile_arnOptional[str], optional
Instance profile ARN granting SSM access, by default None
- auto_create_instance_profilebool, optional
Whether to create an instance profile with the
AmazonSSMManagedInstanceCorepolicy wheniam_instance_profile_arnis not supplied, by default False. SSMSendCommanddispatch cannot work without one of the two.- bake_amibool, optional
Whether to pre-install
worker_initinto a custom AMI, by default False- baked_ami_idOptional[str], optional
Pre-baked AMI to use instead of baking one, by default None
- one_shotbool, optional
Whether to dispatch a single command per instance and terminate, by default False
- cancel_jobs(resource_ids: List[str]) Dict[str, str][source]
Cancel jobs.
Parameters
- resource_idsList[str]
List of resource IDs to cancel
Returns
- Dict[str, str]
Dictionary mapping resource IDs to status strings
- cleanup_infrastructure() None[source]
Clean up infrastructure created by this mode.
This cleans up the VPC, subnet, and security group if they were created by the provider.
- cleanup_resources(resource_ids: List[str]) None[source]
Clean up resources.
Parameters
- resource_idsList[str]
List of resource IDs to clean up
- get_job_status(resource_ids: List[str]) Dict[str, str][source]
Get the status of jobs.
Parameters
- resource_idsList[str]
List of resource IDs to check
Returns
- Dict[str, str]
Dictionary mapping resource IDs to status strings
- initialize() None[source]
Initialize standard mode infrastructure.
Raises
- ResourceCreationError
If resource creation fails
- list_resources() Dict[str, List[Dict[str, Any]]][source]
List all resources created by this mode.
Returns
- Dict[str, List[Dict[str, Any]]]
Dictionary of resource types and their details
- load_state() bool[source]
Load state from the state store.
Returns
- bool
True if state was loaded successfully, False otherwise
- submit_job(job_id: str, command: str, tasks_per_node: int, job_name: str | None = None) str[source]
Submit a job for execution.
Parameters
- job_idstr
Unique identifier for the job
- commandstr
Command to execute
- tasks_per_nodeint
Number of tasks to run per node
- job_nameOptional[str], optional
Human-readable name for the job, by default None
Returns
- str
EC2 instance ID for tracking the job
Raises
- OperatingModeError
If job submission fails
Detached operating mode for the EphemeralProvider.
The detached mode uses a persistent bastion host for coordinating long-running workflows, allowing the client to disconnect and reconnect to the same infrastructure.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.modes.detached.DetachedMode(provider_id: str, session: Session, state_store: StateStore, workflow_id: str | None = None, bastion_instance_type: str = 't3.micro', idle_timeout: int = 30, preserve_bastion: bool = True, bastion_host_type: str = 'cloudformation', use_spot_fleet: bool = False, instance_types: List[str] | None = None, nodes_per_block: int = 1, spot_max_price_percentage: int | None = None, bastion_id: str | None = None, bastion_instance_profile_arn: str | None = None, **kwargs: Any)[source]
Bases:
OperatingModeDetached operating mode implementation.
In detached mode, a persistent bastion host is created to coordinate long-running workflows, allowing the client to disconnect and reconnect to the same infrastructure. The bastion host manages EC2 worker instances as needed.
Attributes
- workflow_idstr
Unique identifier for the workflow
- bastion_idOptional[str]
ID of the bastion host instance or CloudFormation stack
- bastion_host_typestr
Type of bastion host deployment (direct or cloudformation)
- bastion_instance_typestr
EC2 instance type for the bastion host
- idle_timeoutint
Minutes to wait before shutting down idle resources
- preserve_bastionbool
Whether to preserve the bastion host during cleanup
- stack_nameOptional[str]
Name of the CloudFormation stack for the bastion host
Initialize the detached mode.
Parameters
- provider_idstr
Unique identifier for the provider instance
- sessionboto3.Session
AWS session for API calls
- state_storeStateStore
Store for persisting state
- workflow_idOptional[str], optional
Unique identifier for the workflow, by default None
- bastion_instance_typestr, optional
EC2 instance type for the bastion host, by default “t3.micro”
- idle_timeoutint, optional
Minutes to wait before shutting down idle resources, by default 30
- preserve_bastionbool, optional
Whether to preserve the bastion host during cleanup, by default True
- bastion_host_typestr, optional
Type of bastion host deployment (direct or cloudformation), by default “cloudformation”
- use_spot_fleetbool, optional
Whether to use Spot Fleet for worker instances, by default False
- instance_typesOptional[List[str]], optional
List of instance types to use with Spot Fleet, by default None
- nodes_per_blockint, optional
Number of nodes per block, by default 1
- spot_max_price_percentageOptional[int], optional
Maximum spot price as a percentage of on-demand price, by default None
- bastion_instance_profile_arnOptional[str], optional
Instance profile for the bastion to carry, by default None — in which case one is created and deleted with the bastion. Supply an ARN to use your own, which this mode then never deletes. Ignored on the
cloudformationpath, wherebastion.ymldeclares its own.- **kwargsAny
Additional arguments passed to the parent class
- __init__(provider_id: str, session: Session, state_store: StateStore, workflow_id: str | None = None, bastion_instance_type: str = 't3.micro', idle_timeout: int = 30, preserve_bastion: bool = True, bastion_host_type: str = 'cloudformation', use_spot_fleet: bool = False, instance_types: List[str] | None = None, nodes_per_block: int = 1, spot_max_price_percentage: int | None = None, bastion_id: str | None = None, bastion_instance_profile_arn: str | None = None, **kwargs: Any) None[source]
Initialize the detached mode.
Parameters
- provider_idstr
Unique identifier for the provider instance
- sessionboto3.Session
AWS session for API calls
- state_storeStateStore
Store for persisting state
- workflow_idOptional[str], optional
Unique identifier for the workflow, by default None
- bastion_instance_typestr, optional
EC2 instance type for the bastion host, by default “t3.micro”
- idle_timeoutint, optional
Minutes to wait before shutting down idle resources, by default 30
- preserve_bastionbool, optional
Whether to preserve the bastion host during cleanup, by default True
- bastion_host_typestr, optional
Type of bastion host deployment (direct or cloudformation), by default “cloudformation”
- use_spot_fleetbool, optional
Whether to use Spot Fleet for worker instances, by default False
- instance_typesOptional[List[str]], optional
List of instance types to use with Spot Fleet, by default None
- nodes_per_blockint, optional
Number of nodes per block, by default 1
- spot_max_price_percentageOptional[int], optional
Maximum spot price as a percentage of on-demand price, by default None
- bastion_instance_profile_arnOptional[str], optional
Instance profile for the bastion to carry, by default None — in which case one is created and deleted with the bastion. Supply an ARN to use your own, which this mode then never deletes. Ignored on the
cloudformationpath, wherebastion.ymldeclares its own.- **kwargsAny
Additional arguments passed to the parent class
- cancel_jobs(resource_ids: List[str]) Dict[str, str][source]
Cancel jobs.
Parameters
- resource_idsList[str]
List of resource IDs to cancel
Returns
- Dict[str, str]
Dictionary mapping resource IDs to status strings
- cleanup_infrastructure() None[source]
Clean up infrastructure created by this mode.
Terminates the workers, then the bastion — either by deleting its CloudFormation stack or terminating the instance, depending on
bastion_host_type. The bastion is left running whenpreserve_bastionis set, which is what makes later reconnection possible.The VPC, subnet, and security group are not touched: they are supplied by the caller and this mode never created them (#69). An earlier version of this docstring claimed otherwise.
- cleanup_resources(resource_ids: List[str]) None[source]
Clean up resources.
Parameters
- resource_idsList[str]
List of resource IDs to clean up
- get_job_status(resource_ids: List[str]) Dict[str, str][source]
Get the status of jobs.
Parameters
- resource_idsList[str]
List of resource IDs to check
Returns
- Dict[str, str]
Dictionary mapping resource IDs to status strings
- initialize() None[source]
Initialize detached mode infrastructure.
Creates the bastion host for coordinating the workflow.
Raises
- ResourceCreationError
If resource creation fails
- list_resources() Dict[str, List[Dict[str, Any]]][source]
List all resources created by this mode.
Returns
- Dict[str, List[Dict[str, Any]]]
Dictionary of resource types and their details
- load_state() bool[source]
Load state from the state store.
Returns
- bool
True if state was loaded successfully, False otherwise
- submit_job(job_id: str, command: str, tasks_per_node: int, job_name: str | None = None) str[source]
Submit a job for execution.
Parameters
- job_idstr
Unique identifier for the job
- commandstr
Command to execute
- tasks_per_nodeint
Number of tasks to run per node
- job_nameOptional[str], optional
Human-readable name for the job, by default None
Returns
- str
Resource ID for tracking the job
Raises
- OperatingModeError
If job submission fails
Serverless mode implementation for Parsl Ephemeral AWS Provider.
This mode uses AWS Lambda and ECS/Fargate for executing jobs without EC2 instances, providing cost-effective serverless execution for suitable workloads.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.modes.serverless.ServerlessMode(provider_id: str, session: Session, state_store: Any, worker_type: str = 'auto', lambda_timeout: int = 300, lambda_memory: int = 1024, lambda_runtime: str = 'python3.12', ecs_task_cpu: int = 1024, ecs_task_memory: int = 2048, ecs_container_image: str = 'python:3.12-slim', vpc_id: str | None = None, subnet_id: str | None = None, security_group_id: str | None = None, use_public_ips: bool = True, use_spot: bool = False, use_spot_fleet: bool = False, instance_types: List[str] | None = None, nodes_per_block: int = 1, spot_max_price_percentage: float | None = None, additional_tags: Dict[str, str] | None = None, debug: bool = False, compute_type: str | None = None, memory_size: int | None = None, timeout: int | None = None, lambda_code_bucket: str | None = None, **kwargs: Any)[source]
Bases:
OperatingModeServerless operating mode implementation.
In serverless mode, AWS Lambda and/or ECS/Fargate are used to execute tasks without any EC2 instances. This mode is suitable for event-driven or sporadic workloads with short-running tasks. It also supports EC2 SpotFleet for improved reliability and cost savings when more substantial compute resources are needed.
Attributes
- worker_typestr
Type of worker to use (lambda, ecs, or auto)
- lambda_timeoutint
Timeout for Lambda functions in seconds
- lambda_memoryint
Memory for Lambda functions in MB
- ecs_task_cpuint
CPU units for ECS tasks
- ecs_task_memoryint
Memory for ECS tasks in MB
- ecs_container_imagestr
Container image for ECS tasks
- use_spotbool
Whether to use spot instances for ECS tasks (Fargate Spot)
- use_spot_fleetbool
Whether to use Spot Fleet for EC2 instance deployment
- instance_typesList[str]
List of instance types to use with Spot Fleet
- nodes_per_blockint
Number of nodes per block for Spot Fleet
- spot_max_price_percentageOptional[float]
Maximum spot price as percentage of on-demand price
- lambda_code_bucketOptional[str]
Caller-supplied S3 bucket for staging Lambda deployment packages
- lambda_managerLambdaManager
Manager for Lambda functions
- ecs_managerECSManager
Manager for ECS tasks
Initialize the serverless mode.
Parameters
- provider_idstr
Unique identifier for the provider instance
- sessionboto3.Session
AWS session for API calls
- state_storeAny
Store for persisting state
- worker_typestr, optional
Type of worker to use (lambda, ecs, or auto), by default WORKER_TYPE_AUTO
- lambda_timeoutint, optional
Timeout for Lambda functions in seconds, by default DEFAULT_LAMBDA_TIMEOUT
- lambda_memoryint, optional
Memory for Lambda functions in MB, by default DEFAULT_LAMBDA_MEMORY
- lambda_runtimestr, optional
Runtime for Lambda functions, by default DEFAULT_LAMBDA_RUNTIME
- ecs_task_cpuint, optional
CPU units for ECS tasks, by default DEFAULT_ECS_CPU
- ecs_task_memoryint, optional
Memory for ECS tasks in MB, by default DEFAULT_ECS_MEMORY
- ecs_container_imagestr, optional
Container image for ECS tasks, by default DEFAULT_ECS_CONTAINER_IMAGE
- vpc_idOptional[str], optional
Existing VPC ID to use, by default None
- subnet_idOptional[str], optional
Existing subnet ID to use, by default None
- security_group_idOptional[str], optional
Existing security group ID to use, by default None
- use_public_ipsbool, optional
Whether to assign public IPs to ECS tasks, by default True
- use_spotbool, optional
Whether to use spot instances for ECS tasks (Fargate Spot), by default False
- use_spot_fleetbool, optional
Whether to use Spot Fleet for EC2 instance deployment, by default False. If True, this overrides the use_spot parameter and uses EC2 Spot Fleet instead of Fargate Spot.
- instance_typesOptional[List[str]], optional
List of instance types to use with Spot Fleet, by default None. If not provided but use_spot_fleet is True, a default set of instance types will be used.
- nodes_per_blockint, optional
Number of nodes per block for Spot Fleet, by default 1
- spot_max_price_percentageOptional[float], optional
Maximum spot price as percentage of on-demand price, by default None. If None, AWS will use the current spot market price up to the on-demand price.
- additional_tagsOptional[Dict[str, str]], optional
Tags to apply to created resources, by default None
- debugbool, optional
Whether to enable debug logging, by default False
- compute_typeOptional[str], optional
Compute type forwarded by
EphemeralProvider(“lambda” or “ecs”). When supplied it takes precedence overworker_type; “ec2” is treated as unset since it has no meaning for serverless mode.- memory_sizeOptional[int], optional
Lambda memory in MB, forwarded by
EphemeralProvider. Overrideslambda_memorywhen supplied.- timeoutOptional[int], optional
Lambda timeout in seconds, forwarded by
EphemeralProvider. Overrideslambda_timeoutwhen supplied.- lambda_code_bucketOptional[str], optional
Existing S3 bucket to stage Lambda deployment packages in. A caller-supplied bucket is reused as-is and never deleted; when omitted, a provider-scoped bucket is created on first use and removed by
cleanup_infrastructure().This is the surviving half of the old
checkpoint_bucketparameter. Its checkpointing purpose was removed in #137 along with the unimplementable task-recovery API, but the staging override was real and is kept under a name that says what it does.
- __init__(provider_id: str, session: Session, state_store: Any, worker_type: str = 'auto', lambda_timeout: int = 300, lambda_memory: int = 1024, lambda_runtime: str = 'python3.12', ecs_task_cpu: int = 1024, ecs_task_memory: int = 2048, ecs_container_image: str = 'python:3.12-slim', vpc_id: str | None = None, subnet_id: str | None = None, security_group_id: str | None = None, use_public_ips: bool = True, use_spot: bool = False, use_spot_fleet: bool = False, instance_types: List[str] | None = None, nodes_per_block: int = 1, spot_max_price_percentage: float | None = None, additional_tags: Dict[str, str] | None = None, debug: bool = False, compute_type: str | None = None, memory_size: int | None = None, timeout: int | None = None, lambda_code_bucket: str | None = None, **kwargs: Any) None[source]
Initialize the serverless mode.
Parameters
- provider_idstr
Unique identifier for the provider instance
- sessionboto3.Session
AWS session for API calls
- state_storeAny
Store for persisting state
- worker_typestr, optional
Type of worker to use (lambda, ecs, or auto), by default WORKER_TYPE_AUTO
- lambda_timeoutint, optional
Timeout for Lambda functions in seconds, by default DEFAULT_LAMBDA_TIMEOUT
- lambda_memoryint, optional
Memory for Lambda functions in MB, by default DEFAULT_LAMBDA_MEMORY
- lambda_runtimestr, optional
Runtime for Lambda functions, by default DEFAULT_LAMBDA_RUNTIME
- ecs_task_cpuint, optional
CPU units for ECS tasks, by default DEFAULT_ECS_CPU
- ecs_task_memoryint, optional
Memory for ECS tasks in MB, by default DEFAULT_ECS_MEMORY
- ecs_container_imagestr, optional
Container image for ECS tasks, by default DEFAULT_ECS_CONTAINER_IMAGE
- vpc_idOptional[str], optional
Existing VPC ID to use, by default None
- subnet_idOptional[str], optional
Existing subnet ID to use, by default None
- security_group_idOptional[str], optional
Existing security group ID to use, by default None
- use_public_ipsbool, optional
Whether to assign public IPs to ECS tasks, by default True
- use_spotbool, optional
Whether to use spot instances for ECS tasks (Fargate Spot), by default False
- use_spot_fleetbool, optional
Whether to use Spot Fleet for EC2 instance deployment, by default False. If True, this overrides the use_spot parameter and uses EC2 Spot Fleet instead of Fargate Spot.
- instance_typesOptional[List[str]], optional
List of instance types to use with Spot Fleet, by default None. If not provided but use_spot_fleet is True, a default set of instance types will be used.
- nodes_per_blockint, optional
Number of nodes per block for Spot Fleet, by default 1
- spot_max_price_percentageOptional[float], optional
Maximum spot price as percentage of on-demand price, by default None. If None, AWS will use the current spot market price up to the on-demand price.
- additional_tagsOptional[Dict[str, str]], optional
Tags to apply to created resources, by default None
- debugbool, optional
Whether to enable debug logging, by default False
- compute_typeOptional[str], optional
Compute type forwarded by
EphemeralProvider(“lambda” or “ecs”). When supplied it takes precedence overworker_type; “ec2” is treated as unset since it has no meaning for serverless mode.- memory_sizeOptional[int], optional
Lambda memory in MB, forwarded by
EphemeralProvider. Overrideslambda_memorywhen supplied.- timeoutOptional[int], optional
Lambda timeout in seconds, forwarded by
EphemeralProvider. Overrideslambda_timeoutwhen supplied.- lambda_code_bucketOptional[str], optional
Existing S3 bucket to stage Lambda deployment packages in. A caller-supplied bucket is reused as-is and never deleted; when omitted, a provider-scoped bucket is created on first use and removed by
cleanup_infrastructure().This is the surviving half of the old
checkpoint_bucketparameter. Its checkpointing purpose was removed in #137 along with the unimplementable task-recovery API, but the staging override was real and is kept under a name that says what it does.
- cancel_jobs(resource_ids: List[str]) Dict[str, str][source]
Cancel jobs.
Parameters
- resource_idsList[str]
List of resource IDs to cancel
Returns
- Dict[str, str]
Dictionary mapping resource IDs to status strings
- cleanup_infrastructure() None[source]
Clean up infrastructure created by this mode.
The VPC, subnet, and security group are supplied by the caller and are never created — or deleted — by this mode. Only the Lambda functions, ECS tasks, and Spot Fleet resources created here are removed.
- cleanup_resources(resource_ids: List[str]) None[source]
Clean up resources.
Parameters
- resource_idsList[str]
List of resource IDs to clean up
- get_job_status(resource_ids: List[str]) Dict[str, str][source]
Get the status of jobs.
Parameters
- resource_idsList[str]
List of resource IDs to check
Returns
- Dict[str, str]
Dictionary mapping resource IDs to status strings
- initialize() None[source]
Initialize serverless mode.
Verifies the caller-supplied network resources (when the worker type needs them) and initializes the Lambda and/or ECS managers. Network resources are never created by this mode.
Raises
- ResourceNotFoundError
If a configured VPC, subnet, or security group is missing.
- ResourceCreationError
If initialization fails
- list_resources() Dict[str, List[Dict[str, Any]]][source]
List all resources created by this mode.
Returns
- Dict[str, List[Dict[str, Any]]]
Dictionary of resource types and their details
- load_state() bool[source]
Load state from the state store.
Returns
- bool
True if state was loaded successfully, False otherwise
- submit_job(job_id: str, command: str, tasks_per_node: int, job_name: str | None = None) str[source]
Submit a job for execution.
Parameters
- job_idstr
Unique identifier for the job
- commandstr
Command to execute
- tasks_per_nodeint
Number of tasks to run per node
- job_nameOptional[str], optional
Human-readable name for the job, by default None
Returns
- str
Resource ID for tracking the job
Raises
- OperatingModeError
If job submission fails
Compute
Fleet-based compute resource implementation for Parsl Ephemeral AWS Provider.
Provides multi-pool spot instance management, which is more reliable than individual spot requests: a fleet draws from several instance types at once, so a single exhausted capacity pool does not fail the request.
Built on EC2 Fleet (CreateFleet) since #86. It previously used Spot Fleet
(RequestSpotFleet), which AWS describes as “a legacy API with no planned
investment”, recommending EC2 Fleet or EC2 Auto Scaling instead. The class name
is unchanged to keep the use_spot_fleet provider kwarg and the persisted
state documents working across the upgrade.
Fleet type instant is used throughout: it returns the launched instance IDs
synchronously, so a block knows its instances without polling. See
parsl_ephemeral_provider.utils.aws.create_ec2_fleet() for the parameters this
fleet type rejects, and why capacity rebalancing is not among the options.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.compute.spot_fleet.SpotFleetManager(provider: Any)[source]
Bases:
objectManager for AWS EC2 Fleet compute resources.
Requests instances from several instance types at once, so an exhausted capacity pool degrades the fleet rather than failing it, and the allocation strategy can pick the pools least likely to be interrupted.
Named for the legacy Spot Fleet API it was originally built on. It now calls
CreateFleet(#86); the name is retained because it is reachable through the publicuse_spot_fleetprovider kwarg and appears in persisted state.Initialize the fleet manager.
Parameters
- providerEphemeralProvider
The provider instance
- __init__(provider: Any) None[source]
Initialize the fleet manager.
Parameters
- providerEphemeralProvider
The provider instance
- create_blocks(count: int) Dict[str, Dict[str, Any]][source]
Create compute blocks, one EC2 Fleet each.
Parameters
- countint
Number of blocks to create
Returns
- Dict[str, Dict[str, Any]]
Dictionary mapping block IDs to block information
- get_block_status(block_id: str) str[source]
Get the status of a block.
An instant fleet does not maintain capacity, so its
FleetStatestaysactivefor the life of the fleet regardless of what happened to the instances. The block’s status therefore comes from the instances, with the fleet state consulted only for the terminal cases.Parameters
- block_idstr
ID of the block to check
Returns
- str
Block status
- get_instance_private_ip(instance_id: str) str | None[source]
Get the private IP address of an instance.
Parameters
- instance_idstr
ID of the instance
Returns
- Optional[str]
Private IP address, or None if not available
- get_instance_public_ip(instance_id: str) str | None[source]
Get the public IP address of an instance.
Parameters
- instance_idstr
ID of the instance
Returns
- Optional[str]
Public IP address, or None if not available
- terminate_block(block_id: str) None[source]
Terminate a compute block.
Parameters
- block_idstr
ID of the block to terminate
Raises
- SpotFleetThrottlingError
If AWS throttled the deletion. Carries
retry_after, so a caller can wait the interval AWS named rather than retry blind.- SpotFleetError
If EC2 refused the deletion for any other reason.
- ResourceCleanupError
For a failure that is not EC2 refusing the deletion.
Detection of AWS spot instance interruptions.
This module detects that AWS is reclaiming a spot instance and calls the
handlers registered for it. It does not decide what to do about it: the
response lives on OperatingMode, which
marks the doomed block interrupted so Parsl re-runs its tasks.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.compute.spot_interruption.SpotInterruptionMonitor(session: Session, check_interval: int = 30, lead_time: int = 120, provider_id: str | None = None, use_event_bridge: bool = True)[source]
Bases:
objectMonitor for AWS spot instance interruption notices.
The SpotInterruptionMonitor checks for spot instance interruption notices and executes recovery actions when interruptions are detected. It can monitor both individual spot instances and spot fleet requests.
Detection runs on two tracks. The EventBridge warning is the one that matters: it arrives roughly two minutes before the reclaim, with the instance still running, so the block can be marked
STATUS_INTERRUPTEDwhile the executor still has time to stop dispatching into it. The EC2-state poll is kept as a fallback for when the notifier could not be created (missingevents/sqspermissions, say), but it can only ever report an interruption post-facto, once the instance has already reachedshutting-down– by which time work has been dispatched to a worker that is already gone.Attributes
- sessionboto3.Session
AWS session for making API calls
- check_intervalint
Interval in seconds between checks for interruption notices
- lead_timeint
Minimum time in seconds we want for recovery before instance termination
- instance_handlersDict[str, Callable]
Mapping of instance IDs to handler functions
- fleet_handlersDict[str, Callable]
Mapping of fleet request IDs to handler functions
- monitoring_threadOptional[threading.Thread]
Thread for background monitoring
- stop_eventthreading.Event
Event to signal thread termination
- warning_rule_nameOptional[str]
EventBridge rule delivering interruption warnings, once created.
- warning_queue_urlOptional[str]
SQS queue the rule delivers to, once created.
Initialize the SpotInterruptionMonitor.
Parameters
- sessionboto3.Session
AWS session for making API calls
- check_intervalint, optional
Interval in seconds between checks for interruption notices
- lead_timeint, optional
Minimum time in seconds we want for recovery before instance termination
- provider_idOptional[str], optional
Names the EventBridge rule and SQS queue, keeping them unique per provider. Falls back to a random suffix when omitted.
- use_event_bridgebool, optional
Whether to create the EventBridge notifier that supplies the two-minute advance warning. Set False to rely solely on the post-facto EC2-state poll – useful when the caller’s IAM policy grants no
events/sqsaccess.
- __init__(session: Session, check_interval: int = 30, lead_time: int = 120, provider_id: str | None = None, use_event_bridge: bool = True) None[source]
Initialize the SpotInterruptionMonitor.
Parameters
- sessionboto3.Session
AWS session for making API calls
- check_intervalint, optional
Interval in seconds between checks for interruption notices
- lead_timeint, optional
Minimum time in seconds we want for recovery before instance termination
- provider_idOptional[str], optional
Names the EventBridge rule and SQS queue, keeping them unique per provider. Falls back to a random suffix when omitted.
- use_event_bridgebool, optional
Whether to create the EventBridge notifier that supplies the two-minute advance warning. Set False to rely solely on the post-facto EC2-state poll – useful when the caller’s IAM policy grants no
events/sqsaccess.
- deregister_fleet(fleet_request_id: str) None[source]
Stop monitoring a spot fleet.
Parameters
- fleet_request_idstr
ID of the spot fleet request to stop monitoring
- deregister_instance(instance_id: str) None[source]
Stop monitoring a spot instance.
Parameters
- instance_idstr
ID of the spot instance to stop monitoring
- register_fleet(fleet_request_id: str, handler: Callable[[str, List[str], Dict[str, Any]], None]) None[source]
Register a spot fleet to be monitored.
Parameters
- fleet_request_idstr
ID of the spot fleet request to monitor
- handlerCallable[[str, List[str], Dict[str, Any]], None]
Function to call when interruption is detected, receives fleet_request_id, list of affected instance_ids, and event details
- register_instance(instance_id: str, handler: Callable[[str, Dict[str, Any]], None]) None[source]
Register a spot instance to be monitored.
Parameters
- instance_idstr
ID of the spot instance to monitor
- handlerCallable[[str, Dict[str, Any]], None]
Function to call when interruption is detected, receives instance_id and event details
- start_monitoring() None[source]
Start background monitoring for spot interruption notices.
Creates the EventBridge notifier first, when enabled. A failure there is logged and not raised: losing the advance warning degrades this to the post-facto EC2-state poll, which is worse but still functional, and is not a reason to fail the workflow that was about to run.
Lambda function compute implementation for Parsl Ephemeral AWS Provider.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.compute.lambda_func.LambdaManager(provider: Any)[source]
Bases:
objectManager for AWS Lambda compute resources.
Initialize the Lambda manager.
Parameters
- providerEphemeralProvider
The provider instance
- __init__(provider: Any) None[source]
Initialize the Lambda manager.
Parameters
- providerEphemeralProvider
The provider instance
ECS/Fargate compute implementation for Parsl Ephemeral AWS Provider.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.compute.ecs.ECSManager(provider: Any)[source]
Bases:
objectManager for AWS ECS/Fargate compute resources.
Initialize the ECS manager.
Parameters
- providerEphemeralProvider
The provider instance
- __init__(provider: Any) None[source]
Initialize the ECS manager.
Parameters
- providerEphemeralProvider
The provider instance
- cancel_job(cluster: str, task_id: str) None[source]
Cancel a job.
Parameters
- clusterstr
Name of the ECS cluster
- task_idstr
ID of the ECS task
State persistence
Base state store interface for the EphemeralProvider.
State documents are addressed by a state key. The provider and its operating
mode persist different, partially overlapping sets of fields, so each owns its
own key: without that separation the two full-document writes overwrite each
other and mode-only fields (the baked AMI ID, the warm-pool list) or
provider-only fields (job_map) are silently destroyed (#78).
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- parsl_ephemeral_provider.state.base.STATE_KEY_MODE = 'mode'
State key owned by the
OperatingMode(network IDs, baked AMI, warm pool, …)
- parsl_ephemeral_provider.state.base.STATE_KEY_PROVIDER = 'provider'
State key owned by
EphemeralProvider(resources,job_map, …)
- class parsl_ephemeral_provider.state.base.StateStore(provider_id: str)[source]
Bases:
ABCAbstract base class for provider state stores.
A state store persists and retrieves state documents, each addressed by a
state_key. Different implementations store them in different places — local files, AWS Parameter Store, or S3.Attributes
- provider_idstr
Unique identifier for the provider instance
Initialize the state store.
Parameters
- provider_idstr
Unique identifier for the provider instance
- __init__(provider_id: str) None[source]
Initialize the state store.
Parameters
- provider_idstr
Unique identifier for the provider instance
- abstractmethod delete_state(state_key: str) None[source]
Delete a state document.
Deleting a key that does not exist is not an error.
Parameters
- state_keystr
Key to delete the document for
Raises
- StateStoreError
If deleting state fails
- abstractmethod load_state(state_key: str) Dict[str, Any] | None[source]
Load a state document.
Parameters
- state_keystr
Key to load the document from
Returns
- Optional[Dict[str, Any]]
State document if it exists, None otherwise
Raises
- StateStoreError
If loading state fails
- abstractmethod save_state(state_key: str, state_data: Dict[str, Any]) None[source]
Save a state document.
Writing one key must leave the other keys in the store untouched.
Parameters
- state_keystr
Key to store the document under
- state_dataDict[str, Any]
State document to save
Raises
- StateStoreError
If saving state fails
- parsl_ephemeral_provider.state.base.get_provider_id(provider: Any) str[source]
Return a provider’s own identifier.
- parsl_ephemeral_provider.state.base.get_workflow_id(provider: Any) str[source]
Return a provider’s workflow identifier, for tagging stored state.
workflow_idis the convention the compute managers use; the provider itself only guaranteesprovider_id. Falls back to"unknown"so a missing identifier degrades a tag rather than failing the save.
- parsl_ephemeral_provider.state.base.resolve_session(provider: Any) Session[source]
Return a boto3 session for talking to a provider’s account.
Prefers the session the provider already built — it resolved credentials once, correctly, via
utils.aws.create_session(). Only when there is none does this fall back to assembling a session from whatever credential attributes the object happens to carry.Every attribute is read with
getattrbecause this is called with either anEphemeralProvideror anOperatingMode, and neither defines the full set. Reading them directly is what made the AWS state stores raiseAttributeErroron construction (#77).Parameters
- providerAny
An
EphemeralProviderorOperatingMode
Returns
- boto3.Session
A session bound to the provider’s region
File-based state store for the EphemeralProvider.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.state.file.FileStateStore(file_path: str, provider_id: str)[source]
Bases:
StateStoreFile-based state store implementation.
Stores state in a single local JSON file. Each
state_keyis a top-level sub-document under_states, so writing one key preserves the others:{"_version": 2, "_states": {"provider": {...}, "mode": {...}}}Files written before v0.7.0 hold a single flat document with no
_stateswrapper. Those are read back under every key — the provider and the mode each take the fields they recognise — and the first write upgrades the file to the keyed layout, seeding both keys from the flat document so the writer’s counterpart can still find its fields afterwards.Attributes
- file_pathstr
Path to the state file
- provider_idstr
Unique identifier for the provider instance
Initialize the file state store.
Parameters
- file_pathstr
Path to the state file
- provider_idstr
Unique identifier for the provider instance
- __init__(file_path: str, provider_id: str) None[source]
Initialize the file state store.
Parameters
- file_pathstr
Path to the state file
- provider_idstr
Unique identifier for the provider instance
- delete_state(state_key: str) None[source]
Delete the state document stored under state_key.
The file itself is removed once the last key is gone.
Parameters
- state_keystr
Key to delete the document for
Raises
- StateStoreError
If deleting state fails
- load_state(state_key: str) Dict[str, Any] | None[source]
Load the state document stored under state_key.
Parameters
- state_keystr
Key to load the document from
Returns
- Optional[Dict[str, Any]]
State document if present, None otherwise. A flat pre-v0.7.0 file is returned whole for any key.
Raises
- StateDeserializationError
If deserializing state fails
- StateStoreError
If loading state fails
- save_state(state_key: str, state_data: Dict[str, Any]) None[source]
Save a state document under state_key.
Read-modify-write: the other keys in the file are preserved.
Parameters
- state_keystr
Key to store the document under
- state_dataDict[str, Any]
State document to save
Raises
- StateSerializationError
If serializing state fails
- StateStoreError
If saving state fails
S3 state implementation for Parsl Ephemeral AWS Provider.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.state.s3.S3State(provider: Any, bucket_name: str, key_prefix: str = 'parsl/workflows', create_bucket_if_not_exists: bool = False)[source]
Bases:
StateStoreAWS S3 implementation of state persistence.
Initialize S3 state.
Parameters
- providerEphemeralProvider
The provider instance
- bucket_namestr
Name of the S3 bucket to use
- key_prefixstr, optional
Prefix for S3 keys, by default ‘parsl/workflows’
- create_bucket_if_not_existsbool, optional
Whether to create the bucket if it doesn’t exist, by default False
- __init__(provider: Any, bucket_name: str, key_prefix: str = 'parsl/workflows', create_bucket_if_not_exists: bool = False) None[source]
Initialize S3 state.
Parameters
- providerEphemeralProvider
The provider instance
- bucket_namestr
Name of the S3 bucket to use
- key_prefixstr, optional
Prefix for S3 keys, by default ‘parsl/workflows’
- create_bucket_if_not_existsbool, optional
Whether to create the bucket if it doesn’t exist, by default False
- delete_bucket_if_empty() bool[source]
Delete the S3 bucket if it’s empty.
Returns
- bool
Whether the bucket was deleted
- delete_state(state_key: str) None[source]
Delete provider state from S3.
Parameters
- state_keystr
Key to delete the state for
- list_states(prefix: str) Dict[str, Dict[str, Any]][source]
List all states with a given prefix.
Parameters
- prefixstr
Prefix to list states for
Returns
- Dict[str, Dict[str, Any]]
Dictionary mapping state keys to state data
Parameter Store state implementation for Parsl Ephemeral AWS Provider.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.state.parameter_store.ParameterStoreState(provider: Any, prefix: str = '/parsl/workflows', use_secure_string: bool = False)[source]
Bases:
StateStoreAWS Parameter Store implementation of state persistence.
Initialize Parameter Store state.
Parameters
- providerEphemeralProvider
The provider instance
- prefixstr, optional
Prefix for parameter names, by default ‘/parsl/workflows’
- use_secure_stringbool, optional
Whether to use SecureString parameter type, by default False
- __init__(provider: Any, prefix: str = '/parsl/workflows', use_secure_string: bool = False) None[source]
Initialize Parameter Store state.
Parameters
- providerEphemeralProvider
The provider instance
- prefixstr, optional
Prefix for parameter names, by default ‘/parsl/workflows’
- use_secure_stringbool, optional
Whether to use SecureString parameter type, by default False
- delete_state(state_key: str) None[source]
Delete provider state from Parameter Store.
Parameters
- state_keystr
Key to delete the state for
- list_states(prefix: str) Dict[str, Dict[str, Any]][source]
List all states with a given prefix.
Parameters
- prefixstr
Prefix to list states for
Returns
- Dict[str, Dict[str, Any]]
Dictionary mapping state keys to state data
- parsl_ephemeral_provider.state.parameter_store.ParameterStoreStateStore
alias of
ParameterStoreState
Support modules
Clean constants for the EphemeralProvider.
No legacy garbage, just what’s actually needed.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
Custom exceptions for the EphemeralProvider.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- exception parsl_ephemeral_provider.exceptions.AMINotFoundError[source]
Bases:
ResourceCreationErrorSpecified AMI not found.
- exception parsl_ephemeral_provider.exceptions.AWSAuthenticationError[source]
Bases:
AWSConnectionErrorAWS authentication failure.
- exception parsl_ephemeral_provider.exceptions.AWSConnectionError[source]
Bases:
ProviderErrorError connecting to AWS services.
- exception parsl_ephemeral_provider.exceptions.BastionHostError[source]
Bases:
ResourceCreationErrorError managing bastion hosts.
- exception parsl_ephemeral_provider.exceptions.CleanupError[source]
Bases:
ProviderErrorError cleaning up resources.
- exception parsl_ephemeral_provider.exceptions.CloudFormationError[source]
Bases:
ResourceCreationErrorError in CloudFormation stack operations.
- exception parsl_ephemeral_provider.exceptions.ConfigurationError[source]
Bases:
ProviderConfigurationErrorError in provider configuration.
- exception parsl_ephemeral_provider.exceptions.CredentialResolutionError(message: str)[source]
Bases:
NoCredentialsErrorNo usable AWS credentials could be resolved, with a reason.
botocore’s
NoCredentialsErrorderives fromBotoCoreError, whose__init__accepts keyword arguments only and formats them into a fixed class-levelfmt— soNoCredentialsError("why")raisesTypeError: BotoCoreError.__init__() takes 1 positional argument but 2 were givenand the reason never reaches the caller. Every raise site insecurity/credential_manager.pydid exactly that, turning each of the seven distinct credential failures into the same opaqueTypeError.Subclassing keeps
except NoCredentialsErrorhandlers working —compute/{ec2,ecs,lambda_func,spot_fleet}.pyanderror_handling.py:269all catch the botocore class and must continue to — while allowing the message through.- fmt = '{message}'
- exception parsl_ephemeral_provider.exceptions.EC2InstanceError[source]
Bases:
ResourceCreationErrorError managing EC2 instances.
- exception parsl_ephemeral_provider.exceptions.ECSTaskError[source]
Bases:
ResourceCreationErrorError managing ECS tasks.
- exception parsl_ephemeral_provider.exceptions.EphemeralAWSError[source]
Bases:
ExceptionBase class for all EphemeralProvider exceptions.
- exception parsl_ephemeral_provider.exceptions.InvalidStateError[source]
Bases:
ProviderErrorProvider is in an invalid state for the requested operation.
- exception parsl_ephemeral_provider.exceptions.JobCancellationError[source]
Bases:
ProviderErrorError cancelling a job.
- exception parsl_ephemeral_provider.exceptions.JobExecutionError[source]
Bases:
ProviderErrorError executing a job.
- exception parsl_ephemeral_provider.exceptions.JobSubmissionError[source]
Bases:
ProviderErrorError submitting job for execution.
- exception parsl_ephemeral_provider.exceptions.LambdaFunctionError[source]
Bases:
ResourceCreationErrorError managing Lambda functions.
- exception parsl_ephemeral_provider.exceptions.NetworkCreationError[source]
Bases:
ResourceCreationErrorError creating network resources.
- exception parsl_ephemeral_provider.exceptions.OperatingModeError[source]
Bases:
ProviderErrorError in operating mode functionality.
- exception parsl_ephemeral_provider.exceptions.ProviderConfigurationError[source]
Bases:
ProviderErrorError in provider configuration.
- exception parsl_ephemeral_provider.exceptions.ProviderError[source]
Bases:
EphemeralAWSErrorGeneral provider error.
- exception parsl_ephemeral_provider.exceptions.ResourceCleanupError[source]
Bases:
ResourceDeletionErrorError cleaning up AWS resources.
- exception parsl_ephemeral_provider.exceptions.ResourceCreationError[source]
Bases:
ProviderErrorError creating AWS resources.
- exception parsl_ephemeral_provider.exceptions.ResourceDeletionError[source]
Bases:
ProviderErrorError deleting AWS resources.
- exception parsl_ephemeral_provider.exceptions.ResourceNotFoundError[source]
Bases:
ProviderErrorRequested AWS resource not found.
- exception parsl_ephemeral_provider.exceptions.SecurityGroupError[source]
Bases:
ResourceCreationErrorError managing security groups.
- exception parsl_ephemeral_provider.exceptions.SpotFleetError[source]
Bases:
EC2InstanceErrorError managing EC2 Spot Fleet.
- exception parsl_ephemeral_provider.exceptions.SpotFleetRequestError[source]
Bases:
SpotFleetErrorError creating or managing Spot Fleet requests.
- exception parsl_ephemeral_provider.exceptions.SpotFleetThrottlingError(message='AWS Spot Fleet API request was throttled', operation=None, retry_after=None)[source]
Bases:
SpotFleetErrorAWS API throttling for Spot Fleet operations.
- exception parsl_ephemeral_provider.exceptions.SpotInstanceError[source]
Bases:
EC2InstanceErrorError managing spot instances.
- exception parsl_ephemeral_provider.exceptions.SpotInterruptionError[source]
Bases:
SpotInstanceErrorError related to spot instance interruption.
- exception parsl_ephemeral_provider.exceptions.StateDeserializationError[source]
Bases:
StateStoreErrorError deserializing state data.
- exception parsl_ephemeral_provider.exceptions.StateError[source]
Bases:
StateStoreErrorGeneral state management error - alias for compatibility.
- exception parsl_ephemeral_provider.exceptions.StateSerializationError[source]
Bases:
StateStoreErrorError serializing state data.
- exception parsl_ephemeral_provider.exceptions.StateStoreError[source]
Bases:
ProviderErrorError in state store operations.
- exception parsl_ephemeral_provider.exceptions.TaggingError[source]
Bases:
ProviderErrorError tagging AWS resources.
- exception parsl_ephemeral_provider.exceptions.TaskTimeoutError[source]
Bases:
JobExecutionErrorTask execution timeout.
Enhanced error handling and recovery framework for Parsl Ephemeral AWS Provider.
This module provides robust error handling, retry mechanisms, and recovery strategies for AWS operations and provider state management.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- class parsl_ephemeral_provider.error_handling.ErrorAnalyzer[source]
Bases:
objectAnalyzes errors and determines appropriate recovery actions.
Initialize error analyzer.
- analyze_error(exception: Exception, context: ErrorContext) tuple[ErrorSeverity, RecoveryAction][source]
Analyze an error and determine appropriate response.
Parameters
- exceptionException
Exception to analyze
- contextErrorContext
Context of the error
Returns
- tuple[ErrorSeverity, RecoveryAction]
Error severity and recommended recovery action
- class parsl_ephemeral_provider.error_handling.ErrorContext(operation: str, resource_type: str, resource_id: str | None = None, region: str | None = None, attempt: int = 1, start_time: float = <factory>, metadata: Dict[str, ~typing.Any]=<factory>)[source]
Bases:
objectContext information for error handling.
- class parsl_ephemeral_provider.error_handling.ErrorRecord(exception: Exception, context: ErrorContext, severity: ErrorSeverity, recovery_action: RecoveryAction, timestamp: float = <factory>, resolved: bool = False, resolution_time: float | None = None)[source]
Bases:
objectRecord of an error for analysis and reporting.
- context: ErrorContext
- recovery_action: RecoveryAction
- resolution_duration() float | None[source]
Get time taken to resolve error.
Returns
- Optional[float]
Resolution duration in seconds, None if not resolved
- severity: ErrorSeverity
- class parsl_ephemeral_provider.error_handling.ErrorRecoveryHandler[source]
Bases:
objectHandles error recovery and fallback strategies.
Initialize recovery handler.
- attempt_recovery(error_record: ErrorRecord, fallback_params: Dict[str, Any] = None) bool[source]
Attempt to recover from an error.
Parameters
- error_recordErrorRecord
Error to recover from
- fallback_paramsDict[str, Any], optional
Parameters for fallback strategies
Returns
- bool
True if recovery was successful
- class parsl_ephemeral_provider.error_handling.ErrorSeverity(*values)[source]
Bases:
EnumError severity levels.
- CRITICAL = 'critical'
- HIGH = 'high'
- LOW = 'low'
- MEDIUM = 'medium'
- class parsl_ephemeral_provider.error_handling.RecoveryAction(*values)[source]
Bases:
EnumRecovery actions for error handling.
- ABORT = 'abort'
- CLEANUP = 'cleanup'
- FALLBACK = 'fallback'
- IGNORE = 'ignore'
- RETRY = 'retry'
- class parsl_ephemeral_provider.error_handling.RetryConfig(max_attempts: int = 3, base_delay: float = 1.0, max_delay: float = 60.0, exponential_backoff: bool = True, jitter: bool = True, jitter_factor: float = 0.1, retry_on_exceptions: List[Type[Exception]] = <factory>, retry_on_status_codes: List[int] = <factory>)[source]
Bases:
objectConfiguration for retry behavior.
- class parsl_ephemeral_provider.error_handling.RobustErrorHandler(retry_config: RetryConfig | None = None)[source]
Bases:
objectMain error handling coordinator.
Initialize robust error handler.
Parameters
- retry_configOptional[RetryConfig]
Retry configuration, uses default if None
- __init__(retry_config: RetryConfig | None = None)[source]
Initialize robust error handler.
Parameters
- retry_configOptional[RetryConfig]
Retry configuration, uses default if None
- error_history: List[ErrorRecord]
- get_error_statistics(time_window: float = 3600) Dict[str, Any][source]
Get error statistics for a time window.
Parameters
- time_windowfloat
Time window in seconds (default: 1 hour)
Returns
- Dict[str, Any]
Error statistics
- handle_error(exception: Exception, context: ErrorContext, fallback_params: Dict[str, Any] | None = None) ErrorRecord[source]
Handle an error with analysis and recovery.
Parameters
- exceptionException
Exception that occurred
- contextErrorContext
Context of the operation
- fallback_paramsOptional[Dict[str, Any]]
Parameters for fallback strategies
Returns
- ErrorRecord
Record of the error and handling
- parsl_ephemeral_provider.error_handling.poll_until(predicate: Callable[[], T | None], *, timeout: float, description: str, retry_config: RetryConfig | None = None, on_error: Callable[[Exception], None] | None = None) T[source]
Poll predicate until it returns a truthy value, with backoff and jitter.
This is the framework’s entry point for a success-poll, which is a different shape from
retry_with_backoff()and cannot be expressed with it (#91). The decorator retries a call that raised; here the call succeeds and returns a not-yet answer – an instance that has not appeared indescribe_instance_information, a fleet block that has not reachedrunning. Nothing is thrown, so the decorator would never fire and the loop would run exactly once.Before this existed,
modes/hand-rolled three of these with flattime.sleep(10)/sleep(15)intervals, which is the concrete debt #91 tracked: no jitter, so N providers started together poll AWS in lockstep, and no shared notion of a bounded wait.Parameters
- predicateCallable[[], Optional[T]]
Called once per attempt. Return a truthy value to stop and have it returned; return
Noneor any falsey value to keep waiting. Raising is treated as “not yet” – see on_error.- timeoutfloat
Total seconds to keep polling before giving up. This bounds wall-clock time, not attempt count: unlike
RetryConfig.max_attempts, a caller waiting for a 10-minute boot wants a deadline rather than a number of tries.- descriptionstr
What is being waited for, used in the timeout message and debug logs. Phrase it as a noun so the message reads “timed out waiting for {…}”.
- retry_configOptional[RetryConfig]
Supplies the delay schedule via
RetryConfig.get_delay(), so a poll gets the same exponential backoff and jitter as a retry. Defaults toRetryConfig().max_attemptsis deliberately not consulted – timeout is the bound here.- on_errorOptional[Callable[[Exception], None]]
Called with any exception the predicate raises, then polling continues. Use it to log at the level the caller wants. When omitted, exceptions are logged at debug: a poll’s early attempts are expected to fail (the resource does not exist yet), so warning on each one turns normal operation into a wall of noise.
Returns
- T
The first truthy value predicate returned.
Raises
- TimeoutError
If timeout elapses with no truthy result. Callers that owe their own exception type should catch this and re-raise;
modes/standard.pyconverts it toOperatingModeError.
- parsl_ephemeral_provider.error_handling.retry_with_backoff(retry_config: RetryConfig | None = None, error_handler: RobustErrorHandler | None = None)[source]
Decorator for adding retry behavior with exponential backoff.
Parameters
- retry_configOptional[RetryConfig]
Retry configuration
- error_handlerOptional[RobustErrorHandler]
Error handler for comprehensive error management
Returns
- Callable
Decorated function with retry behavior
AWS utility functions for the EphemeralProvider.
SPDX-License-Identifier: Apache-2.0 SPDX-FileCopyrightText: 2025-2026 Scott Friedman and Project Contributors
- parsl_ephemeral_provider.utils.aws.BASTION_INLINE_POLICY_NAME = 'BastionHostPolicy'
Name of the bastion role’s inline policy. Matches
bastion.yml’sPolicyName, so the two paths present the same thing to an operator reading the console.
- parsl_ephemeral_provider.utils.aws.EC2_ASSUME_ROLE_POLICY: Dict[str, Any] = {'Statement': [{'Action': 'sts:AssumeRole', 'Effect': 'Allow', 'Principal': {'Service': 'ec2.amazonaws.com'}}], 'Version': '2012-10-17'}
Trust policy letting EC2 assume a role, so an instance can carry it.
Shared by the worker (SSM) role and the bastion role rather than written out at each site: the two roles differ in what they may do, never in who may assume them, and a copied-out trust policy is where that distinction quietly erodes.
- parsl_ephemeral_provider.utils.aws.architecture_for_instance_type(instance_type: str) str[source]
Return the CPU architecture an instance type needs an AMI for.
An AMI is architecture-specific, so launching a Graviton instance with an x86_64 image fails. Nothing in this package distinguished the two before #84, which made every arm64 instance type unusable.
The family suffix is the signal: AWS appends
gto the generation of every Graviton family (c7g,m8g,r7gd,c8gn, …) and to no x86_64 family. Validated againstdescribe_instance_typesfor all 1,346 types AWS offers in us-east-1: 396 arm64 and 950 x86_64, zero mistakes.The only exceptions are the eight
mac*.metaltypes, which reportarm64_macand need a macOS AMI rather than AL2023 – so classifying them as x86_64 is no worse than the arm64 answer would be. A caller wanting a Mac instance must passimage_idexplicitly either way.Parameters
- instance_typestr
EC2 instance type, e.g.
"c7g.xlarge"or"t3.micro".
Returns
- str
"arm64"or"x86_64".
- parsl_ephemeral_provider.utils.aws.bastion_instance_profile_names(name_suffix: str) Tuple[str, str][source]
Return the bastion
(role_name, profile_name)pair for name_suffix.Derived rather than stored, for the same reason as
ssm_instance_profile_names. Kept separate from that pair because the two roles carry different permissions: the worker role only needs SSM, while the bastion role can launch and terminate instances.IAM caps both names at 64 characters. name_suffix is a provider ID — a UUID, 36 characters — so the longest name here is 58.
- parsl_ephemeral_provider.utils.aws.bastion_role_policy(region: str, account_id: str, workflow_id: str) Dict[str, Any][source]
Return the inline policy granting a bastion exactly what it calls.
bastion.yml’sBastionHostPolicyis the same set, and the two are meant to stay in step: a bastion deployed by CloudFormation and one launched byRunInstancesrun the identical manager script, so a permission missing from either is a bug in that path only, which is the hardest kind to notice.The list is derived from what
_get_bastion_manager_scriptactually calls, not from what a bastion plausibly needs, and a test asserts the correspondence in both directions. Enumerating the script found the CloudFormation policy both too narrow and too wide: it omittedec2:RunInstances, the two launch-template calls and all three fleet calls — so a spot-fleet job on the CFN path could not launch a worker either — while grantingec2:StartInstances,ec2:StopInstances,ec2:DescribeInstanceStatusandec2:DescribeTags, none of which the script calls (the bastion terminates workers rather than stopping them, and it reads worker state throughDescribeInstancesalone).Three actions need explaining:
iam:PassRoleis absent, deliberately. The manager launches workers with no instance profile, so it passes no role. Adding it would let a compromised bastion attach any passable role to an instance it launches, which is a privilege-escalation primitive rather than a convenience.ec2:CreateTagsis unavoidably broad. The script tags throughTagSpecificationsonRunInstances/CreateFleet/CreateLaunchTemplate, which AWS authorizes asCreateTagsagainst the resource being created — a resource whose ID does not exist yet, so it cannot be named in the policy.The SSM parameter path is scoped to this workflow. That is the one place the policy is genuinely tight, and it is the important one: the parameters are the whole control channel, so a bastion that could read another workflow’s path could read its job commands.
- parsl_ephemeral_provider.utils.aws.build_fleet_launch_template_configs(template_id: str, template_version: str, instance_types: List[str], subnet_id: str) List[Dict[str, Any]][source]
Build the
LaunchTemplateConfigsfor a CreateFleet request (#86).One config referencing one template, with an override per instance type so a single template still covers every pool the fleet may draw from.
CreateFleet’s override shape is richer than Spot Fleet’s – it also acceptsImageId,MaxPrice, andBlockDeviceMappings– but it still has noUserData, which is why the per-block user data has to live in the template rather than here.Parameters
- template_idstr
Launch template to draw the baseline definition from.
- template_versionstr
Pinned version. Not
$Latest: a fleet must launch the definition the caller built, not whatever a concurrent provider added afterwards.- instance_typesList[str]
Types to emit as overrides, in preference order.
- subnet_idstr
Subnet every override launches into.
Returns
- List[Dict[str, Any]]
A single-element
LaunchTemplateConfigslist.
- parsl_ephemeral_provider.utils.aws.build_launch_template_data(image_id: str, instance_type: str, subnet_id: str | None = None, security_group_id: str | None = None, associate_public_ip: bool = True, key_name: str | None = None, iam_instance_profile_arn: str | None = None, shutdown_behavior: str = 'terminate', user_data: str | None = None, monitoring: bool = False) Dict[str, Any][source]
Build the
LaunchTemplateDatashared by every launch path (#85).One definition serves the on-demand, spot, and fleet paths, which is what makes the Phase 6 EC2 Fleet/ASG migration possible – those APIs accept a template reference and nothing resembling
RunInstanceskwargs.Every field is optional except the image and instance type, because the template is a baseline:
RunInstancesoverridesUserDataandTagSpecificationsper launch, and Spot Fleet overridesInstanceTypeandSubnetIdper pool.Parameters
- image_idstr
AMI to launch.
- instance_typestr
Default instance type; fleet paths override it per pool.
- subnet_idOptional[str]
Subnet for the primary network interface.
- security_group_idOptional[str]
Security group for the primary network interface.
- associate_public_ipbool
Whether the primary interface gets a public IP.
- key_nameOptional[str]
EC2 key pair for SSH access.
- iam_instance_profile_arnOptional[str]
Instance profile ARN; required for SSM command dispatch.
- shutdown_behaviorstr
"terminate"or"stop"for an instance-initiated shutdown.- user_dataOptional[str]
Plaintext user data; base64-encoded here, since
CreateLaunchTemplatedoes not do it.- monitoringbool
Whether to enable detailed CloudWatch monitoring.
Returns
- Dict[str, Any]
A
LaunchTemplateDatadocument.
- parsl_ephemeral_provider.utils.aws.create_bastion_instance_profile(session: Session, name_suffix: str, workflow_id: str) str[source]
Create (or reuse) an instance profile the bastion manager can work with.
The direct
RunInstancesbastion path had no profile at all (#229), soparsl-bastion-manager.pyraisedNoCredentialsErroron its first AWS call and, underRestart=always, crash-looped every ten seconds. Nothing the bastion exists to do — polling for jobs, launching workers, terminating them — had ever worked on that path.AmazonSSMManagedInstanceCorecomes as a managed policy; the rest is inline because it is scoped to one workflow’s parameter path and so is not reusable.Parameters
- sessionboto3.Session
AWS session used to build the IAM and STS clients.
- name_suffixstr
Discriminator for the role and profile names — the provider ID, so the pair is traceable to its provider and to the state that owns it.
- workflow_idstr
Scopes the SSM parameter statement. The bastion reads and writes only its own workflow’s parameters.
Returns
- str
ARN of the instance profile, ready to pass as
IamInstanceProfile.
Raises
- ResourceCreationError
If the role or profile cannot be created or retrieved.
- parsl_ephemeral_provider.utils.aws.create_ec2_fleet(ec2_client: Any, launch_template_configs: List[Dict[str, Any]], target_capacity: int, allocation_strategy: str, client_token: str | None = None, tags: List[Dict[str, str]] | None = None, max_total_price: str | None = None) Tuple[str, List[str]][source]
Create an
instantEC2 Fleet and return its ID and instance IDs.Replaces
RequestSpotFleet, which AWS describes as “a legacy API with no planned investment” (#86).Fleet type
instantis deliberate: it places a synchronous request and returns the launched instance IDs in the response, so a block knows its instances without polling. That is what the rest of this package assumes, and the asynchronous types cannot provide it.Several parameters the legacy path sent are rejected for this fleet type – verified against real EC2, with
InvalidParameterrather than silent acceptance – so they are deliberately absent here:ReplaceUnhealthyInstancesandTerminateInstancesWithExpiration(“not supported for given fleet type”)SpotOptions.MaintenanceStrategies, i.e. Capacity Rebalance (“only compatible with fleet type maintain”)
Parameters
- ec2_clientAny
A boto3 EC2 client.
- launch_template_configsList[Dict[str, Any]]
As returned by
build_fleet_launch_template_configs().- target_capacityint
Number of instances to request, all spot.
- allocation_strategystr
Spot allocation strategy; normalised to the kebab-case spelling
CreateFleetrequires.- client_tokenOptional[str]
Idempotency token. EC2 generates one when omitted.
- tagsOptional[List[Dict[str, str]]]
Applied to both the fleet resource and the instances it launches, so either can be found by the cleanup sweep.
- max_total_priceOptional[str]
Maximum hourly spot price for the whole fleet. Left unset by default: AWS warns that capping the price increases interruptions.
Returns
- Tuple[str, List[str]]
The fleet ID, and the IDs of the instances it launched. The instance list may be shorter than target_capacity, or empty, if EC2 could not fill the request; the caller decides whether that is fatal.
Raises
- ClientError
Propagated unchanged from
CreateFleet, so the caller can discriminate on the EC2 error code. See the note at the call itself.- ValueError
If allocation_strategy is not one EC2 recognises.
- parsl_ephemeral_provider.utils.aws.create_launch_template(ec2_client: Any, name: str, launch_template_data: Dict[str, Any], tags: List[Dict[str, str]] | None = None) Tuple[str, str][source]
Create a launch template, reusing one that already exists under name.
Idempotent because
initialize()may run again after a partial failure, and a secondCreateLaunchTemplateunder the same name is rejected withInvalidLaunchTemplateName.AlreadyExistsException. Rather than fail, the existing template is adopted – its name encodes the provider ID, so it can only be one this provider made.Parameters
- ec2_clientAny
A boto3 EC2 client.
- namestr
Launch template name; must be unique within the account and region.
- launch_template_dataDict[str, Any]
As returned by
build_launch_template_data().- tagsOptional[List[Dict[str, str]]]
Tags applied to the template resource itself, for cleanup tracking.
Returns
- Tuple[str, str]
The template ID and version number, the latter as the string
RunInstancesexpects.
Raises
- ResourceCreationError
If the template can neither be created nor found.
- parsl_ephemeral_provider.utils.aws.create_session(region: str | None = None, profile_name: str | None = None, aws_access_key_id: str | None = None, aws_secret_access_key: str | None = None, aws_session_token: str | None = None, endpoint_url: str | None = None) Session[source]
Create a boto3 session with the given parameters.
Parameters
- regionOptional[str], optional
AWS region to use, by default None
- profile_nameOptional[str], optional
AWS profile name to use, by default None
- aws_access_key_idOptional[str], optional
AWS access key ID, by default None
- aws_secret_access_keyOptional[str], optional
AWS secret access key, by default None
- aws_session_tokenOptional[str], optional
AWS session token, by default None
- endpoint_urlOptional[str], optional
Custom endpoint URL for every AWS service, by default None. Use for VPC or FIPS endpoints, or to point the whole package at an emulator.
Returns
- boto3.Session
The created boto3 session
Raises
- AWSAuthenticationError
If authentication fails
- AWSConnectionError
If connection to AWS services fails
- parsl_ephemeral_provider.utils.aws.create_spot_interruption_notifier(events_client: Any, sqs_client: Any, name: str, tags: List[Dict[str, str]] | None = None) Tuple[str, str, str][source]
Wire an EventBridge spot-interruption rule to a fresh SQS queue (#86).
This is what supplies the two-minute advance warning. Polling EC2 state cannot: an interrupted instance is only observable once it reaches
shutting-down, which is after the reclaim, far too late to stop dispatching into it. Aninstantfleet also gets no Capacity Rebalance –CreateFleetrejectsSpotOptions.MaintenanceStrategiesfor the type – so EventBridge is the mechanism, and it has the further advantage of working for instances that are already running.No IAM role is created, and none is needed. Verified against real EventBridge:
put_targetswith an SQS ARN and noRoleArnreturnedFailedEntryCount=0. Unlike most target types, delivery to SQS is authorised by the queue’s resource policy, which is why this sets one grantingevents.amazonaws.compermission tosqs:SendMessage, conditioned onaws:SourceArnbeing this rule – so no other rule, in this account or any other, can post to the queue.Verified end to end with a Fault Injection Simulator experiment (
aws:ec2:send-spot-instance-interruptions): the warning reached the queue 15.2s after the experiment started, while the instance was stillrunning.Parameters
- events_clientAny
A boto3 EventBridge client.
- sqs_clientAny
A boto3 SQS client.
- namestr
Name for both the rule and the queue. Must be unique per provider.
- tagsOptional[List[Dict[str, str]]]
Applied to the rule so a leaked one is traceable. Not applied to the queue: SQS takes tags as a flat mapping, and the queue is named after the same provider anyway.
Returns
- Tuple[str, str, str]
The rule name, the queue URL, and the queue ARN.
Raises
- ResourceCreationError
If the rule, the queue, or the wiring between them cannot be created.
- parsl_ephemeral_provider.utils.aws.create_tags(resource_ids: str | List[str], tags: Dict[str, str], session: Session, region: str | None = None) None[source]
Create tags for AWS resources.
Parameters
- resource_idsUnion[str, List[str]]
Resource ID or list of resource IDs to tag
- tagsDict[str, str]
Tags to apply to the resources
- sessionboto3.Session
Boto3 session to use
- regionOptional[str], optional
AWS region, by default None
Raises
- ResourceCreationError
If tagging fails
- parsl_ephemeral_provider.utils.aws.delete_bastion_instance_profile(session: Session, name_suffix: str) bool[source]
Delete the bastion role and instance profile named for name_suffix.
The inverse of
create_bastion_instance_profile. Only for a pair this provider created —DetachedMode._owns_bastion_profileis the gate.
- parsl_ephemeral_provider.utils.aws.delete_ec2_fleet(ec2_client: Any, fleet_id: str) None[source]
Delete an EC2 Fleet, terminating its instances.
Instance termination is not optional for an instant fleet: AWS rejects
NoTerminateInstancesfor this type, and “a deleted instant fleet with running instances is not supported”.Tolerates a fleet that is already gone, and a repeat call on one already deleting – verified that deleting twice succeeds both times, reporting
deleted_terminating, and that an unknown ID comes back as afleetIdDoesNotExistentry inUnsuccessfulFleetDeletionsrather than as a raised error. Both are the desired outcome for a cleanup path, so neither raises.Parameters
- ec2_clientAny
A boto3 EC2 client.
- fleet_idstr
Fleet to delete.
Raises
- ResourceDeletionError
If EC2 refuses the deletion for any reason other than the fleet not existing.
- parsl_ephemeral_provider.utils.aws.delete_instance_profile_pair(session: Session, profile_name: str, role_name: str) bool[source]
Delete instance profile profile_name and role role_name.
The inverse of
_ensure_instance_profileplus its role. Only call this for a pair this provider created —StandardMode._owns_instance_profileandDetachedMode._owns_bastion_profileare the two gates. A caller-supplied profile belongs to the caller, and deleting it would break every other workload using it.IAM enforces the teardown order: a profile holding a role cannot be deleted, and a role that is still in a profile or has policies attached cannot be deleted either. So it goes role-out-of-profile, profile, policies-off-role, role. Getting this wrong yields
DeleteConflictrather than a partial success, which is why the order is not a matter of taste. It is also the order substrate’s CloudFormation gets wrong — it deletes the profile while the role is still in it — so this is worth keeping in one place.Both attachment kinds are stripped.
delete_rolerefuses while either a managed policy or an inline policy remains, and the two are listed and removed by different API calls; the bastion role carries an inline policy while the SSM worker role carries a managed one, so handling only one kind would strand whichever role used the other.Every step tolerates
NoSuchEntity: cleanup runs on paths that may already have partially completed, and a missing resource is the desired end state rather than an error.Parameters
- sessionboto3.Session
AWS session used to build the IAM client.
- profile_namestr
Name of the instance profile to delete.
- role_namestr
Name of the role to remove from it and then delete.
Returns
- bool
True if the pair is gone (including “was already gone”), False if something could not be deleted. Never raises: a cleanup failure must not mask whatever the caller was originally doing.
- parsl_ephemeral_provider.utils.aws.delete_launch_template(ec2_client: Any, template_id: str) None[source]
Delete a launch template, tolerating one that is already gone.
Deleting the template does not affect instances launched from it, so this is safe to call before those instances have terminated.
Parameters
- ec2_clientAny
A boto3 EC2 client.
- template_idstr
ID of the template to delete.
- parsl_ephemeral_provider.utils.aws.delete_resource(resource_id: str, session: Session, resource_type: str, region: str | None = None, force: bool = False) bool[source]
Delete an AWS resource.
Parameters
- resource_idstr
Resource ID to delete
- sessionboto3.Session
Boto3 session to use
- resource_typestr
Type of resource to delete
- regionOptional[str], optional
AWS region, by default None
- forcebool, optional
Whether to force deletion even if resource is in use, by default False
Returns
- bool
True if the resource was deleted, False otherwise
Raises
- ResourceDeletionError
If deletion fails
- ResourceNotFoundError
If the resource is not found
- parsl_ephemeral_provider.utils.aws.delete_spot_interruption_notifier(events_client: Any, sqs_client: Any, rule_name: str | None, queue_url: str | None) None[source]
Tear down what
create_spot_interruption_notifier()built.Order matters: the target has to go before the rule, because EventBridge refuses to delete a rule that still has one. Every step logs rather than raises – this runs from cleanup paths, where a rule that is already gone is the desired end state and must not stop the queue from being deleted too.
Parameters
- events_clientAny
A boto3 EventBridge client.
- sqs_clientAny
A boto3 SQS client.
- rule_nameOptional[str]
Rule to delete. Ignored when None.
- queue_urlOptional[str]
Queue to delete. Ignored when None.
- parsl_ephemeral_provider.utils.aws.delete_ssm_instance_profile(session: Session, name_suffix: str) bool[source]
Delete the SSM role and instance profile named for name_suffix.
The inverse of
get_or_create_ssm_instance_profile. Only call this for a pair this provider created — seeStandardMode._owns_instance_profile. A caller-supplied profile belongs to the caller, and deleting it would break every other workload using it.Parameters
- sessionboto3.Session
AWS session used to build the IAM client.
- name_suffixstr
The same discriminator passed to
get_or_create_ssm_instance_profile— normally the provider ID.
Returns
- bool
True if the pair is gone (including “was already gone”), False if something could not be deleted.
- parsl_ephemeral_provider.utils.aws.describe_ec2_fleet(ec2_client: Any, fleet_id: str) Dict[str, Any] | None[source]
Return the fleet’s
FleetData, or None if EC2 has forgotten it.The ID is always passed explicitly, and not merely as an optimisation: AWS documents that “if a fleet is of type instant, you must specify the fleet ID in the request, otherwise the fleet does not appear in the response”. Verified –
describe_fleets()with noFleetIdsreturned an empty list while an instant fleet was active.Parameters
- ec2_clientAny
A boto3 EC2 client.
- fleet_idstr
Fleet to describe.
Returns
- Optional[Dict[str, Any]]
The
FleetDatadocument, or None when the fleet no longer exists.
- parsl_ephemeral_provider.utils.aws.describe_instance_capacity(session: Session, instance_type: str) Tuple[int | None, float | None][source]
Look up an instance type’s vCPU count and memory in GB.
Parsl’s
ExecutionProviderdeclarescores_per_nodeandmem_per_nodeso an executor can size its worker pool: HTEX divides them by its per-worker requirements to pickworkers_per_node, and falls back to a hardcoded guess of 1 when both areNone. EC2 already knows the real numbers, so there is no reason to make the caller supply them.Failure is not an error. This is an optimisation hint, and a provider that cannot reach EC2 during
__init__should still construct — so any exception yields(None, None), which is exactly the base class’s default.Parameters
- sessionboto3.Session
Session used to call
ec2:DescribeInstanceTypes.- instance_typestr
Instance type to describe, e.g.
"t3.micro".
Returns
- Tuple[Optional[int], Optional[float]]
(vcpus, memory_gb), or(None, None)if the lookup failed.
- parsl_ephemeral_provider.utils.aws.encode_user_data(user_data: str) str[source]
Base64-encode user_data for an API that does not do it for you.
botocore installs
base64_encode_user_dataonbefore-parameter-build.ec2.RunInstancesonly – verified by inspectingbotocore.handlers.BUILTIN_HANDLERS, where that operation andautoscaling.CreateLaunchConfigurationare the sole entries.CreateLaunchTemplateis not among them, so a plaintext script passed there is stored verbatim, handed to cloud-init base64-decoded, and produces garbage that fails silently – the instance boots fine and simply never runs the worker.Encoding twice is the other half of the trap, so callers must not hand already-encoded data to
RunInstances.Parameters
- user_datastr
The plaintext user data script.
Returns
- str
The base64-encoded form.
- parsl_ephemeral_provider.utils.aws.get_cf_template(template_name: str) str[source]
Load a CloudFormation template from the templates directory.
Uses
importlib.resourcesso the template is found both in an installed wheel and in an editable/source checkout. The previous implementation calledpkg_resources.resource_stringwith the import placed outside its owntry— so once setuptools 81 removedpkg_resourcestheexcept ModuleNotFoundErrorfallback became unreachable and every call raised, taking down DetachedMode.initialize() with it. It also fell back to a placeholder template declaring noOutputs, which the bastion path then indexed forBastionHostId— a confusing failure several steps removed from the missing file (#112).Parameters
- template_namestr
Name of the template file (e.g., ‘bastion.yml’)
Returns
- str
CloudFormation template content
Raises
- FileNotFoundError
If the template is not found in the package or on the filesystem
- parsl_ephemeral_provider.utils.aws.get_default_ami(region: str, architecture: str = 'x86_64', session: Session | None = None) str[source]
Resolve the latest Amazon Linux 2023 AMI for a region and architecture.
Resolution order:
AWS’s public SSM Parameter Store alias
/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-<arch>, which AWS repoints at every new AL2023 release. This is the only source that stays correct without maintenance.DEFAULT_AMI_MAPPING, retained purely so offline test runs against moto or substrate need no network. It is not a reliable source of live AMIs – see the note inconstants.py– and is x86_64-only, so it is skipped for arm64 rather than returning an image that cannot boot.
Parameters
- regionstr
AWS region.
- architecturestr, optional
"x86_64"(default) or"arm64". Usearchitecture_for_instance_type()to derive it from an instance type.- sessionboto3.Session, optional
Session to query SSM with. A new one is created for
regionwhen omitted; pass an existing session to reuse its credentials and any custom endpoint.
Returns
- str
AMI ID.
Raises
- AMINotFoundError
If SSM cannot be reached and no usable fallback exists for the region and architecture.
- parsl_ephemeral_provider.utils.aws.get_ec2_fleet_instance_ids(ec2_client: Any, fleet_id: str) List[str][source]
Return the IDs of instances belonging to fleet_id.
Goes through
describe_instancesfiltered on theaws:ec2:fleet-idtag EC2 applies to every fleet-launched instance, because the two obvious routes do not work for an instant fleet – verified against real EC2:describe_fleet_instancesrefuses it outright withUnsupported: “Describe fleet instances is not supported by this type of fleet.”describe_fleetsdoes return anInstanceslist, but only reflects the original launch; it does not drop instances that have since terminated.
Terminated instances are excluded, so the result answers “what is this fleet still running” rather than “what did it ever launch”.
Parameters
- ec2_clientAny
A boto3 EC2 client.
- fleet_idstr
Fleet whose instances to list.
Returns
- List[str]
Instance IDs that are not terminated. Empty if the fleet launched nothing, or everything it launched is gone.
- parsl_ephemeral_provider.utils.aws.get_or_create_iam_role(iam_client: Any, role_name: str, assume_role_policy: Dict[str, Any], policy_arns: List[str], tags: List[Dict[str, str]] | None = None, description: str = '') str[source]
Get or create an IAM role idempotently.
Checks whether the role already exists and returns its ARN without modifying it. If the role does not exist, creates it, attaches the supplied managed-policy ARNs, and returns the new ARN.
Parameters
- iam_clientAny
A boto3 IAM client.
- role_namestr
Name of the IAM role.
- assume_role_policyDict[str, Any]
Trust-relationship policy document (Python dict, not JSON string).
- policy_arnsList[str]
Managed policy ARNs to attach.
- tagsOptional[List[Dict[str, str]]], optional
Tags to apply when creating the role.
- descriptionstr, optional
Role description.
Returns
- str
ARN of the existing or newly created role.
Raises
- ResourceCreationError
If role creation or retrieval fails.
- parsl_ephemeral_provider.utils.aws.get_or_create_ssm_instance_profile(session: Session, name_suffix: str, iam_instance_profile_arn: str | None = None, auto_create: bool = False) str | None[source]
Resolve an IAM instance profile ARN granting SSM access, or None.
SSM
SendCommand— used by warm-pool and one-shot dispatch — needs the instance to carry a profile with theAmazonSSMManagedInstanceCorepolicy. Without it the SSM agent never registers and every command dispatch times out.Resolution order:
iam_instance_profile_arnif supplied → used directly.auto_create→ get-or-create a profile holdingAmazonSSMManagedInstanceCore.Otherwise →
None; the caller launches instances without a profile.
Both the create and the attach steps are idempotent, so concurrent callers sharing a
name_suffixconverge on the same profile.Parameters
- sessionboto3.Session
AWS session used to build the IAM client.
- name_suffixstr
Discriminator appended to the role and profile names — normally the provider ID, so resources are traceable back to their provider.
- iam_instance_profile_arnOptional[str], optional
Pre-existing profile ARN to use verbatim, by default None.
- auto_createbool, optional
Whether to create a profile when none was supplied, by default False.
Returns
- Optional[str]
ARN of the resolved instance profile, or None when neither an explicit ARN was given nor auto-creation requested.
Raises
- ResourceCreationError
If the profile cannot be created or retrieved.
- parsl_ephemeral_provider.utils.aws.get_resources_by_tags(tags: Dict[str, str], session: Session, region: str | None = None, resource_type: str | None = None) List[Dict[str, Any]][source]
Get AWS resources by tags.
Parameters
- tagsDict[str, str]
Tags to filter resources by
- sessionboto3.Session
Boto3 session to use
- regionOptional[str], optional
AWS region, by default None
- resource_typeOptional[str], optional
Resource type to filter by, by default None
Returns
- List[Dict[str, Any]]
List of resources matching the tags
Raises
- AWSConnectionError
If connection to AWS services fails
- parsl_ephemeral_provider.utils.aws.normalize_ec2_fleet_allocation_strategy(strategy: str) str[source]
Translate an allocation strategy to the spelling CreateFleet takes.
The mirror image of
normalize_spot_fleet_allocation_strategy():CreateFleetaccepts only kebab-case, and rejects the camelCase spellingRequestSpotFleetdemands. The provider’sspot_allocation_strategykwarg is documented in kebab-case, so the common case is a pass-through – but a caller who supplied the camelCase form (or read it off the legacy constant) is converted rather than punished.Validating here matters more than it does on the legacy path, because EC2 does not catch this for you until real capacity is requested: verified against real EC2 that both
DryRun=TrueandTotalTargetCapacity=0accept"priceCapacityOptimized", anddescribe_fleetsthen shows the bad value stored verbatim.Parameters
- strategystr
Allocation strategy in either spelling.
Returns
- str
The kebab-case spelling
CreateFleetaccepts.
Raises
- ValueError
If the strategy is not one EC2 recognises, or is not a string.
- parsl_ephemeral_provider.utils.aws.normalize_spot_fleet_allocation_strategy(strategy: str) str[source]
Translate an allocation strategy to the spelling RequestSpotFleet takes.
The two fleet APIs disagree on the casing of the same enum, and each rejects the other’s spelling. Verified against real EC2 in us-east-1 –
RequestSpotFleetwith"price-capacity-optimized"returnsInvalidParameterValue, andCreateFleetwith"priceCapacityOptimized"returnsInvalidParameter.The provider’s
spot_allocation_strategykwarg is documented in kebab-case, so it needs converting at the RequestSpotFleet boundary. Values already in camelCase pass through, so a caller who supplied the API-native spelling is not punished for it.Parameters
- strategystr
Allocation strategy in either spelling, e.g.
"price-capacity-optimized"or"priceCapacityOptimized".
Returns
- str
The camelCase spelling
RequestSpotFleetaccepts.
Raises
- ValueError
If the strategy is not one EC2 recognises, or is not a string. Raised here rather than letting EC2 reject it, because a spot fleet request fails several seconds and one IAM role later.
- parsl_ephemeral_provider.utils.aws.resolve_manager_session(provider: Any, credential_manager: Any) Session[source]
Return the session a compute manager should use.
The caller’s own session wins. Only when the provider has none does this fall back to building one from the credential manager.
All four compute managers previously went straight to
credential_manager.create_boto3_session(), discardingprovider.sessionentirely — so a caller who passed an explicitly configured session (temporary role credentials, a chosen profile, a LocalStackendpoint_url) had it silently replaced by one built from ambient environment credentials, possibly pointing at a different account (#117). It also meant an injected test double was ignored and the manager reached real AWS; a unit test created a live ECS cluster this way.This mirrors the fix already applied to the state stores, which had the same defect.
Parameters
- providerAny
The provider (or operating mode) the manager was constructed with.
- credential_managerAny
Fallback used when the provider carries no session.
Returns
- boto3.Session
The caller’s session if it has one, else a newly built session.
- parsl_ephemeral_provider.utils.aws.ssm_instance_profile_names(name_suffix: str) Tuple[str, str][source]
Return the
(role_name, profile_name)pair for name_suffix.The names are derived, not stored, so the creator and the deleter cannot drift apart.
get_or_create_ssm_instance_profileanddelete_ssm_instance_profileare the two callers.
- parsl_ephemeral_provider.utils.aws.wait_for_resource(resource_id: str, waiter_name: str, service_client: Any, waiter_config: Dict[str, Any] | None = None, resource_name: str = 'resource', delay: int = 5, max_attempts: int = 60) None[source]
Wait for a resource to reach the desired state.
Parameters
- resource_idstr
Resource ID to wait for
- waiter_namestr
Name of the waiter to use
- service_clientAny
Boto3 service client
- waiter_configOptional[Dict[str, Any]], optional
Waiter configuration, by default None
- resource_namestr, optional
Name of the resource for logging purposes, by default “resource”
- delayint, optional
Seconds between waiter attempts, by default 5
- max_attemptsint, optional
Maximum number of waiter attempts, by default 60
Raises
- ResourceCreationError
If the resource fails to reach the desired state