render 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- render/__init__.py +98 -0
- render/client/__init__.py +119 -0
- render/client/client.py +110 -0
- render/client/errors.py +39 -0
- render/client/sse.py +90 -0
- render/client/sse_sync.py +20 -0
- render/client/tests/__init__.py +0 -0
- render/client/tests/test_client.py +379 -0
- render/client/tests/test_method_parity.py +118 -0
- render/client/tests/test_render.py +52 -0
- render/client/tests/test_sse.py +67 -0
- render/client/tests/test_util.py +303 -0
- render/client/tests/test_util_sync.py +73 -0
- render/client/tests/test_workflows_sync.py +313 -0
- render/client/types.py +52 -0
- render/client/util.py +285 -0
- render/client/util_sync.py +83 -0
- render/client/workflows.py +363 -0
- render/client/workflows_sync.py +298 -0
- render/experimental/__init__.py +37 -0
- render/experimental/experimental.py +93 -0
- render/experimental/experimental_sync.py +78 -0
- render/experimental/key_value/__init__.py +33 -0
- render/experimental/key_value/api.py +243 -0
- render/experimental/key_value/compare.py +83 -0
- render/experimental/key_value/provider.py +285 -0
- render/experimental/key_value/tests/__init__.py +0 -0
- render/experimental/key_value/tests/test_api.py +371 -0
- render/experimental/key_value/tests/test_compare.py +136 -0
- render/experimental/key_value/tests/test_provider.py +1016 -0
- render/experimental/key_value/types.py +130 -0
- render/experimental/key_value/utils.py +11 -0
- render/experimental/object/__init__.py +38 -0
- render/experimental/object/api.py +250 -0
- render/experimental/object/api_sync.py +250 -0
- render/experimental/object/client.py +545 -0
- render/experimental/object/client_sync.py +547 -0
- render/experimental/object/e2e_helpers.py +78 -0
- render/experimental/object/tests/__init__.py +0 -0
- render/experimental/object/tests/test_client.py +228 -0
- render/experimental/object/tests/test_e2e.py +125 -0
- render/experimental/object/types.py +87 -0
- render/experimental/sandbox/__init__.py +31 -0
- render/experimental/sandbox/_tar.py +278 -0
- render/experimental/sandbox/api.py +518 -0
- render/experimental/sandbox/api_sync.py +514 -0
- render/experimental/sandbox/client.py +168 -0
- render/experimental/sandbox/client_sync.py +170 -0
- render/experimental/sandbox/errors.py +37 -0
- render/experimental/sandbox/files.py +378 -0
- render/experimental/sandbox/tests/__init__.py +0 -0
- render/experimental/sandbox/tests/test_client.py +802 -0
- render/experimental/sandbox/tests/test_download.py +728 -0
- render/experimental/sandbox/tests/test_e2e.py +252 -0
- render/experimental/sandbox/tests/test_tar.py +153 -0
- render/experimental/sandbox/tests/test_types.py +57 -0
- render/experimental/sandbox/types.py +46 -0
- render/public_api/__init__.py +8 -0
- render/public_api/api/__init__.py +1 -0
- render/public_api/api/artifact_sources/__init__.py +1 -0
- render/public_api/api/artifact_sources/add_or_update_artifact_source_secret_file.py +252 -0
- render/public_api/api/artifact_sources/create_artifact_source.py +243 -0
- render/public_api/api/artifact_sources/delete_artifact_source.py +188 -0
- render/public_api/api/artifact_sources/delete_artifact_source_env_var.py +223 -0
- render/public_api/api/artifact_sources/delete_artifact_source_secret_file.py +223 -0
- render/public_api/api/artifact_sources/get_artifact_source.py +185 -0
- render/public_api/api/artifact_sources/get_env_vars_for_artifact_source.py +241 -0
- render/public_api/api/artifact_sources/link_artifact_source_to_env_group.py +215 -0
- render/public_api/api/artifact_sources/list_artifact_sources.py +338 -0
- render/public_api/api/artifact_sources/list_artifacts_in_artifact_source.py +241 -0
- render/public_api/api/artifact_sources/list_secret_files_for_artifact_source.py +241 -0
- render/public_api/api/artifact_sources/retrieve_artifact_source_env_var.py +225 -0
- render/public_api/api/artifact_sources/retrieve_artifact_source_secret_file.py +225 -0
- render/public_api/api/artifact_sources/unlink_artifact_source_from_env_group.py +209 -0
- render/public_api/api/artifact_sources/update_artifact_source.py +244 -0
- render/public_api/api/artifact_sources/update_artifact_source_env_var.py +257 -0
- render/public_api/api/artifact_sources/update_env_vars_for_artifact_source.py +245 -0
- render/public_api/api/artifact_sources/update_secret_files_for_artifact_source.py +255 -0
- render/public_api/api/audit_logs/__init__.py +1 -0
- render/public_api/api/audit_logs/list_organization_audit_logs.py +303 -0
- render/public_api/api/audit_logs/list_owner_audit_logs.py +303 -0
- render/public_api/api/blueprints/__init__.py +1 -0
- render/public_api/api/blueprints/disconnect_blueprint.py +210 -0
- render/public_api/api/blueprints/list_blueprint_syncs.py +241 -0
- render/public_api/api/blueprints/list_blueprints.py +251 -0
- render/public_api/api/blueprints/retrieve_blueprint.py +200 -0
- render/public_api/api/blueprints/update_blueprint.py +222 -0
- render/public_api/api/blueprints/validate_blueprint.py +217 -0
- render/public_api/api/custom_domains/__init__.py +1 -0
- render/public_api/api/custom_domains/create_custom_domain.py +242 -0
- render/public_api/api/custom_domains/delete_custom_domain.py +216 -0
- render/public_api/api/custom_domains/list_custom_domains.py +346 -0
- render/public_api/api/custom_domains/refresh_custom_domain.py +216 -0
- render/public_api/api/custom_domains/retrieve_custom_domain.py +218 -0
- render/public_api/api/dedicated_i_ps/__init__.py +1 -0
- render/public_api/api/dedicated_i_ps/create_dedicated_ip.py +234 -0
- render/public_api/api/dedicated_i_ps/delete_dedicated_ip.py +198 -0
- render/public_api/api/dedicated_i_ps/list_dedicated_ips.py +223 -0
- render/public_api/api/dedicated_i_ps/retrieve_dedicated_ip.py +200 -0
- render/public_api/api/dedicated_i_ps/update_dedicated_ip.py +244 -0
- render/public_api/api/deploys/__init__.py +1 -0
- render/public_api/api/deploys/cancel_deploy.py +216 -0
- render/public_api/api/deploys/create_deploy.py +231 -0
- render/public_api/api/deploys/list_deploys.py +377 -0
- render/public_api/api/deploys/retrieve_deploy.py +213 -0
- render/public_api/api/deploys/rollback_deploy.py +241 -0
- render/public_api/api/disks/__init__.py +1 -0
- render/public_api/api/disks/add_disk.py +222 -0
- render/public_api/api/disks/delete_disk.py +210 -0
- render/public_api/api/disks/list_disks.py +381 -0
- render/public_api/api/disks/list_snapshots.py +214 -0
- render/public_api/api/disks/restore_snapshot.py +255 -0
- render/public_api/api/disks/retrieve_disk.py +200 -0
- render/public_api/api/disks/update_disk.py +243 -0
- render/public_api/api/environment_groups/__init__.py +1 -0
- render/public_api/api/environment_groups/create_env_group.py +199 -0
- render/public_api/api/environment_groups/delete_env_group.py +192 -0
- render/public_api/api/environment_groups/delete_env_group_env_var.py +201 -0
- render/public_api/api/environment_groups/delete_env_group_secret_file.py +201 -0
- render/public_api/api/environment_groups/link_service_to_env_group.py +211 -0
- render/public_api/api/environment_groups/list_env_groups.py +352 -0
- render/public_api/api/environment_groups/retrieve_env_group.py +190 -0
- render/public_api/api/environment_groups/retrieve_env_group_env_var.py +203 -0
- render/public_api/api/environment_groups/retrieve_env_group_secret_file.py +203 -0
- render/public_api/api/environment_groups/unlink_service_from_env_group.py +209 -0
- render/public_api/api/environment_groups/update_env_group.py +212 -0
- render/public_api/api/environment_groups/update_env_group_env_var.py +230 -0
- render/public_api/api/environment_groups/update_env_group_secret_file.py +225 -0
- render/public_api/api/events/__init__.py +1 -0
- render/public_api/api/events/retrieve_event.py +205 -0
- render/public_api/api/key_value/__init__.py +1 -0
- render/public_api/api/key_value/create_key_value.py +199 -0
- render/public_api/api/key_value/delete_key_value.py +188 -0
- render/public_api/api/key_value/list_key_value.py +380 -0
- render/public_api/api/key_value/resume_key_value.py +203 -0
- render/public_api/api/key_value/retrieve_key_value.py +190 -0
- render/public_api/api/key_value/retrieve_key_value_connection_info.py +194 -0
- render/public_api/api/key_value/suspend_key_value.py +203 -0
- render/public_api/api/key_value/update_key_value.py +221 -0
- render/public_api/api/logs/__init__.py +1 -0
- render/public_api/api/logs/delete_owner_log_stream.py +188 -0
- render/public_api/api/logs/delete_resource_log_stream.py +192 -0
- render/public_api/api/logs/get_owner_log_stream.py +205 -0
- render/public_api/api/logs/get_resource_log_stream.py +209 -0
- render/public_api/api/logs/list_logs.py +535 -0
- render/public_api/api/logs/list_logs_values.py +527 -0
- render/public_api/api/logs/list_resource_log_streams.py +317 -0
- render/public_api/api/logs/subscribe_logs.py +527 -0
- render/public_api/api/logs/update_owner_log_stream.py +231 -0
- render/public_api/api/logs/update_resource_log_stream.py +231 -0
- render/public_api/api/maintenance/__init__.py +1 -0
- render/public_api/api/maintenance/list_maintenance.py +249 -0
- render/public_api/api/maintenance/retrieve_maintenance.py +190 -0
- render/public_api/api/maintenance/trigger_maintenance.py +212 -0
- render/public_api/api/maintenance/update_maintenance.py +222 -0
- render/public_api/api/metrics/__init__.py +1 -0
- render/public_api/api/metrics/delete_owner_metrics_stream.py +172 -0
- render/public_api/api/metrics/get_active_connections.py +237 -0
- render/public_api/api/metrics/get_bandwidth.py +237 -0
- render/public_api/api/metrics/get_bandwidth_sources.py +250 -0
- render/public_api/api/metrics/get_cpu.py +287 -0
- render/public_api/api/metrics/get_cpu_limit.py +267 -0
- render/public_api/api/metrics/get_cpu_target.py +267 -0
- render/public_api/api/metrics/get_disk_capacity.py +252 -0
- render/public_api/api/metrics/get_disk_usage.py +252 -0
- render/public_api/api/metrics/get_http_latency.py +297 -0
- render/public_api/api/metrics/get_http_requests.py +302 -0
- render/public_api/api/metrics/get_instance_count.py +252 -0
- render/public_api/api/metrics/get_memory.py +267 -0
- render/public_api/api/metrics/get_memory_limit.py +267 -0
- render/public_api/api/metrics/get_memory_target.py +267 -0
- render/public_api/api/metrics/get_owner_metrics_stream.py +174 -0
- render/public_api/api/metrics/get_replication_lag.py +237 -0
- render/public_api/api/metrics/get_task_runs_completed.py +281 -0
- render/public_api/api/metrics/get_task_runs_queued.py +237 -0
- render/public_api/api/metrics/list_application_filter_values.py +254 -0
- render/public_api/api/metrics/list_http_filter_values.py +282 -0
- render/public_api/api/metrics/list_path_filter_values.py +289 -0
- render/public_api/api/metrics/upsert_owner_metrics_stream.py +192 -0
- render/public_api/api/notification_settings/__init__.py +1 -0
- render/public_api/api/notification_settings/list_notification_overrides.py +255 -0
- render/public_api/api/notification_settings/patch_owner_notification_settings.py +207 -0
- render/public_api/api/notification_settings/patch_service_notification_overrides.py +207 -0
- render/public_api/api/notification_settings/retrieve_owner_notification_settings.py +193 -0
- render/public_api/api/notification_settings/retrieve_service_notification_overrides.py +193 -0
- render/public_api/api/object_storage/__init__.py +1 -0
- render/public_api/api/object_storage/delete_object.py +215 -0
- render/public_api/api/object_storage/get_object.py +221 -0
- render/public_api/api/object_storage/list_objects.py +240 -0
- render/public_api/api/object_storage/put_object.py +248 -0
- render/public_api/api/one_off_jobs/__init__.py +1 -0
- render/public_api/api/one_off_jobs/cancel_job.py +203 -0
- render/public_api/api/one_off_jobs/list_job.py +367 -0
- render/public_api/api/one_off_jobs/post_job.py +216 -0
- render/public_api/api/one_off_jobs/retrieve_job.py +203 -0
- render/public_api/api/postgres/__init__.py +1 -0
- render/public_api/api/postgres/create_postgres.py +199 -0
- render/public_api/api/postgres/create_postgres_export.py +207 -0
- render/public_api/api/postgres/create_postgres_user.py +229 -0
- render/public_api/api/postgres/delete_postgres.py +192 -0
- render/public_api/api/postgres/delete_postgres_user.py +201 -0
- render/public_api/api/postgres/failover_postgres.py +207 -0
- render/public_api/api/postgres/list_available_postgres_parameter_overrides.py +190 -0
- render/public_api/api/postgres/list_postgres.py +418 -0
- render/public_api/api/postgres/list_postgres_export.py +199 -0
- render/public_api/api/postgres/list_postgres_parameter_overrides.py +190 -0
- render/public_api/api/postgres/list_postgres_processes.py +190 -0
- render/public_api/api/postgres/list_postgres_sizes.py +190 -0
- render/public_api/api/postgres/list_postgres_table_scans.py +190 -0
- render/public_api/api/postgres/list_postgres_top_queries.py +194 -0
- render/public_api/api/postgres/list_postgres_users.py +195 -0
- render/public_api/api/postgres/promote_postgres.py +203 -0
- render/public_api/api/postgres/recover_postgres.py +231 -0
- render/public_api/api/postgres/restart_postgres.py +203 -0
- render/public_api/api/postgres/resume_postgres.py +203 -0
- render/public_api/api/postgres/retrieve_postgres.py +190 -0
- render/public_api/api/postgres/retrieve_postgres_connection_info.py +194 -0
- render/public_api/api/postgres/retrieve_postgres_recovery_info.py +194 -0
- render/public_api/api/postgres/setup_postgres_replication.py +231 -0
- render/public_api/api/postgres/suspend_postgres.py +203 -0
- render/public_api/api/postgres/update_postgres.py +217 -0
- render/public_api/api/postgres/update_postgres_parameter_overrides.py +217 -0
- render/public_api/api/projects_environments/__init__.py +1 -0
- render/public_api/api/projects_environments/add_resources_to_environment.py +212 -0
- render/public_api/api/projects_environments/create_environment.py +199 -0
- render/public_api/api/projects_environments/create_project.py +199 -0
- render/public_api/api/projects_environments/delete_environment.py +216 -0
- render/public_api/api/projects_environments/delete_project.py +216 -0
- render/public_api/api/projects_environments/list_environments.py +369 -0
- render/public_api/api/projects_environments/list_projects.py +329 -0
- render/public_api/api/projects_environments/remove_resources_from_environment.py +211 -0
- render/public_api/api/projects_environments/retrieve_environment.py +190 -0
- render/public_api/api/projects_environments/retrieve_project.py +190 -0
- render/public_api/api/projects_environments/update_environment.py +212 -0
- render/public_api/api/projects_environments/update_project.py +224 -0
- render/public_api/api/redis_deprecated/__init__.py +1 -0
- render/public_api/api/redis_deprecated/create_redis.py +199 -0
- render/public_api/api/redis_deprecated/delete_redis.py +188 -0
- render/public_api/api/redis_deprecated/list_redis.py +384 -0
- render/public_api/api/redis_deprecated/resume_redis.py +203 -0
- render/public_api/api/redis_deprecated/retrieve_redis.py +190 -0
- render/public_api/api/redis_deprecated/retrieve_redis_connection_info.py +194 -0
- render/public_api/api/redis_deprecated/suspend_redis.py +203 -0
- render/public_api/api/redis_deprecated/update_redis.py +217 -0
- render/public_api/api/registry_credentials/__init__.py +1 -0
- render/public_api/api/registry_credentials/create_registry_credential.py +209 -0
- render/public_api/api/registry_credentials/delete_registry_credential.py +198 -0
- render/public_api/api/registry_credentials/list_registry_credentials.py +370 -0
- render/public_api/api/registry_credentials/retrieve_registry_credential.py +200 -0
- render/public_api/api/registry_credentials/update_registry_credential.py +241 -0
- render/public_api/api/sandboxes/__init__.py +1 -0
- render/public_api/api/sandboxes/connect_sandbox_files.py +281 -0
- render/public_api/api/sandboxes/connect_sandbox_run.py +271 -0
- render/public_api/api/sandboxes/create_sandbox.py +199 -0
- render/public_api/api/sandboxes/list_sandbox_files.py +244 -0
- render/public_api/api/sandboxes/list_sandbox_groups.py +216 -0
- render/public_api/api/sandboxes/list_sandboxes.py +269 -0
- render/public_api/api/sandboxes/retrieve_sandbox.py +211 -0
- render/public_api/api/sandboxes/retrieve_sandbox_execution.py +224 -0
- render/public_api/api/sandboxes/stream_sandbox_logs.py +274 -0
- render/public_api/api/sandboxes/terminate_sandbox.py +217 -0
- render/public_api/api/sandboxes/update_sandbox_exec.py +258 -0
- render/public_api/api/services/__init__.py +1 -0
- render/public_api/api/services/add_or_update_secret_file.py +252 -0
- render/public_api/api/services/autoscale_service.py +230 -0
- render/public_api/api/services/create_ephemeral_shell.py +217 -0
- render/public_api/api/services/create_service.py +204 -0
- render/public_api/api/services/delete_autoscaling_config.py +198 -0
- render/public_api/api/services/delete_env_var.py +223 -0
- render/public_api/api/services/delete_secret_file.py +223 -0
- render/public_api/api/services/delete_service.py +198 -0
- render/public_api/api/services/get_env_vars_for_service.py +241 -0
- render/public_api/api/services/list_events.py +288 -0
- render/public_api/api/services/list_instances.py +190 -0
- render/public_api/api/services/list_secret_files_for_service.py +241 -0
- render/public_api/api/services/list_services.py +439 -0
- render/public_api/api/services/preview_service.py +227 -0
- render/public_api/api/services/purge_cache.py +203 -0
- render/public_api/api/services/restart_service.py +211 -0
- render/public_api/api/services/resume_service.py +203 -0
- render/public_api/api/services/retrieve_env_var.py +225 -0
- render/public_api/api/services/retrieve_secret_file.py +225 -0
- render/public_api/api/services/retrieve_service.py +190 -0
- render/public_api/api/services/retrieve_service_outbound_ips.py +207 -0
- render/public_api/api/services/scale_service.py +237 -0
- render/public_api/api/services/suspend_service.py +203 -0
- render/public_api/api/services/update_env_var.py +257 -0
- render/public_api/api/services/update_env_vars_for_service.py +241 -0
- render/public_api/api/services/update_secret_files_for_service.py +255 -0
- render/public_api/api/services/update_service.py +227 -0
- render/public_api/api/services_cron_jobs/__init__.py +1 -0
- render/public_api/api/services_cron_jobs/cancel_cron_job_run.py +183 -0
- render/public_api/api/services_cron_jobs/run_cron_job.py +185 -0
- render/public_api/api/services_headers/__init__.py +1 -0
- render/public_api/api/services_headers/add_headers.py +222 -0
- render/public_api/api/services_headers/delete_header.py +211 -0
- render/public_api/api/services_headers/list_headers.py +302 -0
- render/public_api/api/services_headers/update_headers.py +243 -0
- render/public_api/api/services_routes/__init__.py +1 -0
- render/public_api/api/services_routes/add_route.py +227 -0
- render/public_api/api/services_routes/delete_route.py +211 -0
- render/public_api/api/services_routes/list_routes.py +306 -0
- render/public_api/api/services_routes/patch_route.py +259 -0
- render/public_api/api/services_routes/put_routes.py +259 -0
- render/public_api/api/users/__init__.py +1 -0
- render/public_api/api/users/get_user.py +161 -0
- render/public_api/api/webhooks/__init__.py +1 -0
- render/public_api/api/webhooks/create_webhook.py +199 -0
- render/public_api/api/webhooks/delete_webhook.py +183 -0
- render/public_api/api/webhooks/list_webhook_events.py +268 -0
- render/public_api/api/webhooks/list_webhooks.py +237 -0
- render/public_api/api/webhooks/retrieve_webhook.py +185 -0
- render/public_api/api/webhooks/update_webhook.py +212 -0
- render/public_api/api/workflow_tasks_beta/__init__.py +1 -0
- render/public_api/api/workflow_tasks_beta/cancel_task_run.py +188 -0
- render/public_api/api/workflow_tasks_beta/create_task.py +204 -0
- render/public_api/api/workflow_tasks_beta/get_task.py +190 -0
- render/public_api/api/workflow_tasks_beta/get_task_run.py +190 -0
- render/public_api/api/workflow_tasks_beta/list_task_runs.py +317 -0
- render/public_api/api/workflow_tasks_beta/list_tasks.py +298 -0
- render/public_api/api/workflow_tasks_beta/stream_task_runs_events.py +230 -0
- render/public_api/api/workflows_beta/__init__.py +1 -0
- render/public_api/api/workflows_beta/create_workflow.py +199 -0
- render/public_api/api/workflows_beta/create_workflow_version.py +197 -0
- render/public_api/api/workflows_beta/delete_workflow.py +188 -0
- render/public_api/api/workflows_beta/get_workflow.py +190 -0
- render/public_api/api/workflows_beta/get_workflow_version.py +190 -0
- render/public_api/api/workflows_beta/list_workflow_versions.py +275 -0
- render/public_api/api/workflows_beta/list_workflows.py +298 -0
- render/public_api/api/workflows_beta/update_workflow.py +212 -0
- render/public_api/api/workspaces/__init__.py +1 -0
- render/public_api/api/workspaces/list_owners.py +255 -0
- render/public_api/api/workspaces/remove_workspace_member.py +206 -0
- render/public_api/api/workspaces/retrieve_owner.py +207 -0
- render/public_api/api/workspaces/retrieve_owner_members.py +200 -0
- render/public_api/api/workspaces/update_workspace_member.py +235 -0
- render/public_api/client.py +268 -0
- render/public_api/errors.py +16 -0
- render/public_api/models/__init__.py +861 -0
- render/public_api/models/add_headers_response_201.py +72 -0
- render/public_api/models/add_or_update_artifact_source_secret_file_body.py +59 -0
- render/public_api/models/add_or_update_secret_file_body.py +59 -0
- render/public_api/models/artifact.py +145 -0
- render/public_api/models/artifact_fetch_failed.py +67 -0
- render/public_api/models/artifact_source.py +162 -0
- render/public_api/models/artifact_source_changed.py +70 -0
- render/public_api/models/artifact_source_git.py +167 -0
- render/public_api/models/artifact_source_git_region.py +12 -0
- render/public_api/models/artifact_source_git_runtime.py +14 -0
- render/public_api/models/artifact_source_image.py +78 -0
- render/public_api/models/artifact_source_patch_git.py +175 -0
- render/public_api/models/artifact_source_patch_git_region.py +12 -0
- render/public_api/models/artifact_source_patch_git_runtime.py +14 -0
- render/public_api/models/artifact_source_patch_image.py +71 -0
- render/public_api/models/artifact_source_patch_input.py +101 -0
- render/public_api/models/artifact_source_post_input.py +213 -0
- render/public_api/models/artifact_source_service_link.py +67 -0
- render/public_api/models/artifact_source_with_cursor.py +73 -0
- render/public_api/models/audit_log.py +113 -0
- render/public_api/models/audit_log_actor.py +80 -0
- render/public_api/models/audit_log_actor_type.py +10 -0
- render/public_api/models/audit_log_event.py +87 -0
- render/public_api/models/audit_log_metadata.py +49 -0
- render/public_api/models/audit_log_status.py +9 -0
- render/public_api/models/audit_log_with_cursor.py +73 -0
- render/public_api/models/auto_deploy.py +9 -0
- render/public_api/models/auto_deploy_disabled.py +79 -0
- render/public_api/models/auto_deploy_enabled.py +68 -0
- render/public_api/models/auto_deploy_trigger.py +10 -0
- render/public_api/models/autoscaling_config.py +89 -0
- render/public_api/models/autoscaling_config_changed.py +83 -0
- render/public_api/models/autoscaling_criteria.py +73 -0
- render/public_api/models/autoscaling_criteria_percentage.py +68 -0
- render/public_api/models/autoscaling_ended.py +67 -0
- render/public_api/models/autoscaling_started.py +105 -0
- render/public_api/models/background_worker_details.py +256 -0
- render/public_api/models/background_worker_details_patch.py +184 -0
- render/public_api/models/background_worker_details_post.py +266 -0
- render/public_api/models/blueprint.py +128 -0
- render/public_api/models/blueprint_detail.py +150 -0
- render/public_api/models/blueprint_patch.py +77 -0
- render/public_api/models/blueprint_with_cursor.py +74 -0
- render/public_api/models/branch_deleted.py +67 -0
- render/public_api/models/build.py +148 -0
- render/public_api/models/build_config.py +96 -0
- render/public_api/models/build_deploy_end_reason.py +122 -0
- render/public_api/models/build_deploy_end_reason_id.py +59 -0
- render/public_api/models/build_deploy_trigger.py +150 -0
- render/public_api/models/build_ended.py +91 -0
- render/public_api/models/build_filter.py +67 -0
- render/public_api/models/build_plan.py +9 -0
- render/public_api/models/build_runtime.py +14 -0
- render/public_api/models/build_started.py +73 -0
- render/public_api/models/build_status.py +13 -0
- render/public_api/models/cache.py +61 -0
- render/public_api/models/cache_profile.py +10 -0
- render/public_api/models/cidr_block_and_description.py +67 -0
- render/public_api/models/commit_ignored.py +67 -0
- render/public_api/models/commit_ref.py +59 -0
- render/public_api/models/connect_sandbox_files_operation.py +9 -0
- render/public_api/models/connect_sandbox_run_operation.py +9 -0
- render/public_api/models/create_custom_domain_body.py +59 -0
- render/public_api/models/create_deploy_body.py +130 -0
- render/public_api/models/create_deploy_body_clear_cache.py +9 -0
- render/public_api/models/create_ephemeral_shell_body.py +69 -0
- render/public_api/models/create_ephemeral_shell_response_201.py +59 -0
- render/public_api/models/create_registry_credential_body.py +93 -0
- render/public_api/models/create_version.py +70 -0
- render/public_api/models/credential_create_input.py +59 -0
- render/public_api/models/cron_job_details.py +163 -0
- render/public_api/models/cron_job_details_patch.py +138 -0
- render/public_api/models/cron_job_details_post.py +172 -0
- render/public_api/models/cron_job_run.py +123 -0
- render/public_api/models/cron_job_run_ended.py +110 -0
- render/public_api/models/cron_job_run_started.py +59 -0
- render/public_api/models/cron_job_run_status.py +11 -0
- render/public_api/models/custom_domain.py +135 -0
- render/public_api/models/custom_domain_domain_type.py +9 -0
- render/public_api/models/custom_domain_server.py +68 -0
- render/public_api/models/custom_domain_verification_status.py +9 -0
- render/public_api/models/custom_domain_with_cursor.py +73 -0
- render/public_api/models/database_role.py +9 -0
- render/public_api/models/database_status.py +18 -0
- render/public_api/models/dedicated_ip.py +146 -0
- render/public_api/models/dedicated_ip_status.py +14 -0
- render/public_api/models/dedicated_ippatch.py +81 -0
- render/public_api/models/dedicated_ippost.py +100 -0
- render/public_api/models/deploy.py +211 -0
- render/public_api/models/deploy_commit.py +86 -0
- render/public_api/models/deploy_ended.py +102 -0
- render/public_api/models/deploy_image.py +78 -0
- render/public_api/models/deploy_mode.py +9 -0
- render/public_api/models/deploy_started.py +85 -0
- render/public_api/models/deploy_status.py +18 -0
- render/public_api/models/deploy_trigger.py +17 -0
- render/public_api/models/deploy_with_cursor.py +81 -0
- render/public_api/models/disk.py +83 -0
- render/public_api/models/disk_created.py +67 -0
- render/public_api/models/disk_deleted.py +59 -0
- render/public_api/models/disk_details.py +112 -0
- render/public_api/models/disk_patch.py +77 -0
- render/public_api/models/disk_post.py +83 -0
- render/public_api/models/disk_snapshot.py +88 -0
- render/public_api/models/disk_updated.py +75 -0
- render/public_api/models/disk_with_cursor.py +73 -0
- render/public_api/models/docker_details.py +108 -0
- render/public_api/models/docker_details_patch.py +86 -0
- render/public_api/models/docker_details_post.py +86 -0
- render/public_api/models/edge_cache_disabled.py +65 -0
- render/public_api/models/edge_cache_enabled.py +65 -0
- render/public_api/models/edge_cache_purged.py +65 -0
- render/public_api/models/edge_cache_trigger.py +91 -0
- render/public_api/models/env_group.py +162 -0
- render/public_api/models/env_group_link.py +77 -0
- render/public_api/models/env_group_meta.py +126 -0
- render/public_api/models/env_group_patch_input.py +59 -0
- render/public_api/models/env_group_post_input.py +161 -0
- render/public_api/models/env_var.py +67 -0
- render/public_api/models/env_var_generate_value.py +59 -0
- render/public_api/models/env_var_key_generate_value.py +68 -0
- render/public_api/models/env_var_key_value.py +67 -0
- render/public_api/models/env_var_value.py +59 -0
- render/public_api/models/env_var_with_cursor.py +73 -0
- render/public_api/models/environment.py +152 -0
- render/public_api/models/environment_patch_input.py +112 -0
- render/public_api/models/environment_post_input.py +122 -0
- render/public_api/models/environment_resources_post_input.py +59 -0
- render/public_api/models/environment_with_cursor.py +74 -0
- render/public_api/models/error.py +79 -0
- render/public_api/models/error_code.py +10 -0
- render/public_api/models/event.py +1122 -0
- render/public_api/models/event_status.py +10 -0
- render/public_api/models/event_type.py +74 -0
- render/public_api/models/execution.py +144 -0
- render/public_api/models/execution_operation.py +11 -0
- render/public_api/models/execution_type.py +9 -0
- render/public_api/models/failure_reason.py +138 -0
- render/public_api/models/filter_application_values_collection_item.py +78 -0
- render/public_api/models/filter_application_values_collection_item_filter.py +8 -0
- render/public_api/models/filter_http_values_collection_item.py +78 -0
- render/public_api/models/filter_http_values_collection_item_filter.py +9 -0
- render/public_api/models/get_bandwidth_sources_response_200.py +75 -0
- render/public_api/models/get_bandwidth_sources_response_200_data_item.py +101 -0
- render/public_api/models/get_bandwidth_sources_response_200_data_item_labels.py +78 -0
- render/public_api/models/get_bandwidth_sources_response_200_data_item_labels_traffic_source.py +12 -0
- render/public_api/models/get_bandwidth_sources_response_200_data_item_values_item.py +68 -0
- render/public_api/models/get_cpu_aggregation_method.py +10 -0
- render/public_api/models/get_http_requests_aggregate_by.py +9 -0
- render/public_api/models/get_object_output.py +71 -0
- render/public_api/models/get_task_runs_completed_aggregate_by.py +8 -0
- render/public_api/models/get_task_runs_completed_state.py +9 -0
- render/public_api/models/header.py +83 -0
- render/public_api/models/header_input.py +76 -0
- render/public_api/models/header_with_cursor.py +73 -0
- render/public_api/models/image.py +80 -0
- render/public_api/models/image_pull_failed.py +67 -0
- render/public_api/models/initial_deploy_hook_ended.py +59 -0
- render/public_api/models/initial_deploy_hook_started.py +59 -0
- render/public_api/models/instance_count_changed.py +67 -0
- render/public_api/models/instance_type_changed.py +67 -0
- render/public_api/models/internal_routing.py +8 -0
- render/public_api/models/job.py +144 -0
- render/public_api/models/job_run_ended.py +92 -0
- render/public_api/models/job_status.py +12 -0
- render/public_api/models/job_with_cursor.py +73 -0
- render/public_api/models/key_value.py +182 -0
- render/public_api/models/key_value_available.py +44 -0
- render/public_api/models/key_value_config_restart.py +67 -0
- render/public_api/models/key_value_connection_info.py +76 -0
- render/public_api/models/key_value_detail.py +192 -0
- render/public_api/models/key_value_options.py +79 -0
- render/public_api/models/key_value_patch_input.py +138 -0
- render/public_api/models/key_value_plan.py +13 -0
- render/public_api/models/key_value_post_input.py +166 -0
- render/public_api/models/key_value_unhealthy.py +44 -0
- render/public_api/models/key_value_with_cursor.py +73 -0
- render/public_api/models/label.py +68 -0
- render/public_api/models/list_custom_domains_domain_type.py +9 -0
- render/public_api/models/list_custom_domains_verification_status.py +9 -0
- render/public_api/models/list_logs_response_200.py +102 -0
- render/public_api/models/list_logs_values_label.py +13 -0
- render/public_api/models/list_objects_response.py +92 -0
- render/public_api/models/list_postgres_suspended_item.py +9 -0
- render/public_api/models/list_postgres_users_response_200_item.py +86 -0
- render/public_api/models/list_routes_type_item.py +9 -0
- render/public_api/models/list_services_suspended_item.py +9 -0
- render/public_api/models/log.py +100 -0
- render/public_api/models/log_direction.py +9 -0
- render/public_api/models/log_label.py +70 -0
- render/public_api/models/log_label_name.py +22 -0
- render/public_api/models/log_stream_owner_update.py +80 -0
- render/public_api/models/log_stream_preview_setting.py +9 -0
- render/public_api/models/log_stream_resource_update.py +80 -0
- render/public_api/models/log_stream_setting.py +9 -0
- render/public_api/models/maintenance_ended.py +44 -0
- render/public_api/models/maintenance_mode.py +68 -0
- render/public_api/models/maintenance_mode_enabled.py +59 -0
- render/public_api/models/maintenance_mode_uri_updated.py +67 -0
- render/public_api/models/maintenance_run.py +105 -0
- render/public_api/models/maintenance_run_patch.py +69 -0
- render/public_api/models/maintenance_run_with_resource.py +114 -0
- render/public_api/models/maintenance_started.py +65 -0
- render/public_api/models/maintenance_state.py +13 -0
- render/public_api/models/maintenance_trigger.py +91 -0
- render/public_api/models/maxmemory_policy.py +15 -0
- render/public_api/models/metrics_stream.py +77 -0
- render/public_api/models/metrics_stream_input.py +86 -0
- render/public_api/models/native_environment_details.py +78 -0
- render/public_api/models/native_environment_details_patch.py +68 -0
- render/public_api/models/native_environment_details_post.py +68 -0
- render/public_api/models/notification_override.py +78 -0
- render/public_api/models/notification_override_with_cursor.py +73 -0
- render/public_api/models/notification_service_override.py +78 -0
- render/public_api/models/notification_service_override_patch.py +84 -0
- render/public_api/models/notification_setting.py +93 -0
- render/public_api/models/notification_setting_patch.py +85 -0
- render/public_api/models/notify_override.py +11 -0
- render/public_api/models/notify_preview_override.py +10 -0
- render/public_api/models/notify_setting.py +10 -0
- render/public_api/models/notify_setting_v2.py +10 -0
- render/public_api/models/object_metadata.py +77 -0
- render/public_api/models/object_with_cursor.py +73 -0
- render/public_api/models/oom_killed.py +59 -0
- render/public_api/models/otel_provider_type.py +16 -0
- render/public_api/models/outbound_ips.py +81 -0
- render/public_api/models/outbound_ips_type.py +9 -0
- render/public_api/models/owner.py +121 -0
- render/public_api/models/owner_log_stream_setting.py +86 -0
- render/public_api/models/owner_type.py +9 -0
- render/public_api/models/owner_with_cursor.py +81 -0
- render/public_api/models/paid_plan.py +13 -0
- render/public_api/models/patch_route_response_200.py +72 -0
- render/public_api/models/persistence_mode.py +10 -0
- render/public_api/models/pipeline_minutes_exhausted.py +73 -0
- render/public_api/models/plan.py +22 -0
- render/public_api/models/post_job_body.py +70 -0
- render/public_api/models/postgres.py +300 -0
- render/public_api/models/postgres_available.py +44 -0
- render/public_api/models/postgres_available_parameter_override.py +106 -0
- render/public_api/models/postgres_available_parameter_overrides_result.py +75 -0
- render/public_api/models/postgres_backup_completed.py +44 -0
- render/public_api/models/postgres_backup_failed.py +44 -0
- render/public_api/models/postgres_backup_started.py +44 -0
- render/public_api/models/postgres_cluster_leader_changed.py +59 -0
- render/public_api/models/postgres_connection_info.py +103 -0
- render/public_api/models/postgres_connection_pool_changed.py +91 -0
- render/public_api/models/postgres_connection_pool_enabled_changed.py +83 -0
- render/public_api/models/postgres_created.py +72 -0
- render/public_api/models/postgres_detail.py +336 -0
- render/public_api/models/postgres_detail_suspended.py +9 -0
- render/public_api/models/postgres_disk_size_changed.py +91 -0
- render/public_api/models/postgres_export.py +80 -0
- render/public_api/models/postgres_ha_status_changed.py +67 -0
- render/public_api/models/postgres_parameter_overrides.py +44 -0
- render/public_api/models/postgres_parameter_overrides_wrapper.py +65 -0
- render/public_api/models/postgres_patch_input.py +199 -0
- render/public_api/models/postgres_pitr_checkpoint_completed.py +44 -0
- render/public_api/models/postgres_pitr_checkpoint_failed.py +44 -0
- render/public_api/models/postgres_pitr_checkpoint_started.py +44 -0
- render/public_api/models/postgres_plans.py +35 -0
- render/public_api/models/postgres_post_input.py +254 -0
- render/public_api/models/postgres_process.py +185 -0
- render/public_api/models/postgres_processes_result.py +73 -0
- render/public_api/models/postgres_put_parameter_overrides_result.py +82 -0
- render/public_api/models/postgres_query_statistic.py +222 -0
- render/public_api/models/postgres_read_replica_stale.py +44 -0
- render/public_api/models/postgres_read_replicas_changed.py +67 -0
- render/public_api/models/postgres_replication_setup_input.py +96 -0
- render/public_api/models/postgres_restarted.py +72 -0
- render/public_api/models/postgres_size.py +96 -0
- render/public_api/models/postgres_sizes_result.py +73 -0
- render/public_api/models/postgres_suspended.py +9 -0
- render/public_api/models/postgres_table_scan.py +87 -0
- render/public_api/models/postgres_table_scans_result.py +73 -0
- render/public_api/models/postgres_top_queries_result.py +73 -0
- render/public_api/models/postgres_unavailable.py +44 -0
- render/public_api/models/postgres_upgrade_failed.py +67 -0
- render/public_api/models/postgres_upgrade_started.py +91 -0
- render/public_api/models/postgres_upgrade_succeeded.py +67 -0
- render/public_api/models/postgres_version.py +15 -0
- render/public_api/models/postgres_with_cursor.py +73 -0
- render/public_api/models/pre_deploy_ended.py +99 -0
- render/public_api/models/pre_deploy_started.py +67 -0
- render/public_api/models/preview_input.py +94 -0
- render/public_api/models/previews.py +67 -0
- render/public_api/models/previews_generation.py +10 -0
- render/public_api/models/private_service_details.py +282 -0
- render/public_api/models/private_service_details_patch.py +184 -0
- render/public_api/models/private_service_details_post.py +266 -0
- render/public_api/models/project.py +108 -0
- render/public_api/models/project_patch_input.py +60 -0
- render/public_api/models/project_post_environment_input.py +114 -0
- render/public_api/models/project_post_input.py +89 -0
- render/public_api/models/project_with_cursor.py +73 -0
- render/public_api/models/protected_status.py +9 -0
- render/public_api/models/pull_request_previews_enabled.py +9 -0
- render/public_api/models/put_object_input.py +59 -0
- render/public_api/models/put_object_output.py +79 -0
- render/public_api/models/read_replica.py +91 -0
- render/public_api/models/read_replica_input.py +83 -0
- render/public_api/models/recovery_info.py +80 -0
- render/public_api/models/recovery_info_recovery_status.py +10 -0
- render/public_api/models/recovery_input.py +114 -0
- render/public_api/models/redis.py +182 -0
- render/public_api/models/redis_connection_info.py +76 -0
- render/public_api/models/redis_detail.py +192 -0
- render/public_api/models/redis_options.py +79 -0
- render/public_api/models/redis_patch_input.py +138 -0
- render/public_api/models/redis_plan.py +13 -0
- render/public_api/models/redis_post_input.py +166 -0
- render/public_api/models/redis_with_cursor.py +73 -0
- render/public_api/models/region.py +12 -0
- render/public_api/models/registry_credential.py +95 -0
- render/public_api/models/registry_credential_registry.py +12 -0
- render/public_api/models/registry_credential_summary.py +67 -0
- render/public_api/models/render_subdomain_policy.py +9 -0
- render/public_api/models/resource.py +67 -0
- render/public_api/models/resource_log_stream_setting.py +87 -0
- render/public_api/models/resource_ref.py +77 -0
- render/public_api/models/resource_ref_type.py +17 -0
- render/public_api/models/rollback_deploy_body.py +59 -0
- render/public_api/models/route.py +93 -0
- render/public_api/models/route_patch.py +60 -0
- render/public_api/models/route_post.py +88 -0
- render/public_api/models/route_put.py +77 -0
- render/public_api/models/route_type.py +9 -0
- render/public_api/models/route_with_cursor.py +73 -0
- render/public_api/models/run_task.py +96 -0
- render/public_api/models/runtime.py +12 -0
- render/public_api/models/sandbox.py +149 -0
- render/public_api/models/sandbox_connect_request.py +62 -0
- render/public_api/models/sandbox_connect_response.py +98 -0
- render/public_api/models/sandbox_directory_listing.py +82 -0
- render/public_api/models/sandbox_exec_update_request.py +60 -0
- render/public_api/models/sandbox_exec_update_response.py +130 -0
- render/public_api/models/sandbox_file_entry.py +98 -0
- render/public_api/models/sandbox_file_entry_type.py +10 -0
- render/public_api/models/sandbox_group.py +141 -0
- render/public_api/models/sandbox_group_with_cursor.py +74 -0
- render/public_api/models/sandbox_network_policy.py +61 -0
- render/public_api/models/sandbox_network_policy_default.py +9 -0
- render/public_api/models/sandbox_plan.py +10 -0
- render/public_api/models/sandbox_post.py +138 -0
- render/public_api/models/sandbox_post_env.py +44 -0
- render/public_api/models/sandbox_status.py +13 -0
- render/public_api/models/sandbox_with_cursor.py +74 -0
- render/public_api/models/scale_service_body.py +59 -0
- render/public_api/models/schemas_build_filter.py +70 -0
- render/public_api/models/schemas_image.py +96 -0
- render/public_api/models/schemas_user.py +68 -0
- render/public_api/models/secret_file.py +67 -0
- render/public_api/models/secret_file_input.py +67 -0
- render/public_api/models/secret_file_with_cursor.py +73 -0
- render/public_api/models/server_available.py +44 -0
- render/public_api/models/server_failed.py +81 -0
- render/public_api/models/server_hardware_failure.py +44 -0
- render/public_api/models/server_port.py +69 -0
- render/public_api/models/server_port_protocol.py +9 -0
- render/public_api/models/server_restarted.py +66 -0
- render/public_api/models/service_disk.py +78 -0
- render/public_api/models/service_env.py +15 -0
- render/public_api/models/service_event.py +770 -0
- render/public_api/models/service_event_type.py +48 -0
- render/public_api/models/service_event_with_cursor.py +66 -0
- render/public_api/models/service_instance.py +69 -0
- render/public_api/models/service_patch.py +273 -0
- render/public_api/models/service_post.py +357 -0
- render/public_api/models/service_resumed.py +44 -0
- render/public_api/models/service_runtime.py +15 -0
- render/public_api/models/service_suspended.py +44 -0
- render/public_api/models/service_type.py +12 -0
- render/public_api/models/service_type_short.py +12 -0
- render/public_api/models/setup_postgres_replication_response_201.py +44 -0
- render/public_api/models/snapshot_restore_post.py +72 -0
- render/public_api/models/static_site_details.py +183 -0
- render/public_api/models/static_site_details_patch.py +147 -0
- render/public_api/models/static_site_details_post.py +189 -0
- render/public_api/models/status.py +12 -0
- render/public_api/models/stream_sandbox_logs_accept.py +8 -0
- render/public_api/models/stream_task_runs_events_accept.py +8 -0
- render/public_api/models/suspender_added.py +83 -0
- render/public_api/models/suspender_removed.py +83 -0
- render/public_api/models/suspender_type.py +14 -0
- render/public_api/models/sync.py +118 -0
- render/public_api/models/sync_state.py +12 -0
- render/public_api/models/sync_with_cursor.py +74 -0
- render/public_api/models/task.py +97 -0
- render/public_api/models/task_attempt.py +121 -0
- render/public_api/models/task_attempt_details.py +141 -0
- render/public_api/models/task_data_type_1.py +44 -0
- render/public_api/models/task_run.py +168 -0
- render/public_api/models/task_run_details.py +216 -0
- render/public_api/models/task_run_status.py +14 -0
- render/public_api/models/task_run_with_cursor.py +73 -0
- render/public_api/models/task_with_cursor.py +73 -0
- render/public_api/models/team_member.py +102 -0
- render/public_api/models/team_member_role.py +12 -0
- render/public_api/models/team_member_status.py +9 -0
- render/public_api/models/time_series.py +100 -0
- render/public_api/models/time_series_value.py +70 -0
- render/public_api/models/update_env_group_secret_file_body.py +59 -0
- render/public_api/models/update_registry_credential_body.py +85 -0
- render/public_api/models/update_workspace_member_body.py +61 -0
- render/public_api/models/user.py +67 -0
- render/public_api/models/validate_blueprint_request.py +84 -0
- render/public_api/models/validate_blueprint_response.py +105 -0
- render/public_api/models/validation_error.py +88 -0
- render/public_api/models/validation_plan_summary.py +107 -0
- render/public_api/models/web_service_details.py +385 -0
- render/public_api/models/web_service_details_patch.py +270 -0
- render/public_api/models/web_service_details_post.py +354 -0
- render/public_api/models/webhook.py +110 -0
- render/public_api/models/webhook_event.py +115 -0
- render/public_api/models/webhook_event_with_cursor.py +73 -0
- render/public_api/models/webhook_patch_input.py +98 -0
- render/public_api/models/webhook_post_input.py +102 -0
- render/public_api/models/webhook_with_cursor.py +73 -0
- render/public_api/models/workflow.py +163 -0
- render/public_api/models/workflow_create.py +169 -0
- render/public_api/models/workflow_update.py +109 -0
- render/public_api/models/workflow_version.py +95 -0
- render/public_api/models/workflow_version_status.py +13 -0
- render/public_api/models/workflow_version_with_cursor.py +73 -0
- render/public_api/models/workflow_with_cursor.py +73 -0
- render/public_api/models/zero_downtime_redeploy_ended.py +44 -0
- render/public_api/models/zero_downtime_redeploy_started.py +59 -0
- render/public_api/py.typed +1 -0
- render/public_api/types.py +54 -0
- render/py.typed +0 -0
- render/render.py +81 -0
- render/render_async.py +80 -0
- render/version.py +27 -0
- render/workflows/__init__.py +25 -0
- render/workflows/_callback_models.py +194 -0
- render/workflows/_uds_http.py +128 -0
- render/workflows/app.py +263 -0
- render/workflows/cli.py +62 -0
- render/workflows/client.py +354 -0
- render/workflows/context.py +75 -0
- render/workflows/executor.py +86 -0
- render/workflows/runner.py +174 -0
- render/workflows/task.py +348 -0
- render/workflows/tests/__init__.py +0 -0
- render/workflows/tests/test_app.py +343 -0
- render/workflows/tests/test_cli.py +134 -0
- render/workflows/tests/test_client.py +59 -0
- render/workflows/tests/test_context.py +118 -0
- render/workflows/tests/test_end_to_end.py +307 -0
- render/workflows/tests/test_executor.py +221 -0
- render/workflows/tests/test_lazy_imports.py +100 -0
- render/workflows/tests/test_registration.py +293 -0
- render/workflows/tests/test_translate_errors.py +126 -0
- render/workflows/tests/test_uds_http.py +199 -0
- render/workflows/tests/test_version.py +15 -0
- render-1.0.1.dist-info/METADATA +382 -0
- render-1.0.1.dist-info/RECORD +799 -0
- render-1.0.1.dist-info/WHEEL +4 -0
- render-1.0.1.dist-info/entry_points.txt +2 -0
- render-1.0.1.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"""High-level Key Value provider with automatic provisioning and configuration sync."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import os
|
|
5
|
+
import re
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from render.client.errors import RenderError
|
|
9
|
+
from render.public_api.models.database_status import DatabaseStatus
|
|
10
|
+
from render.public_api.models.key_value_plan import KeyValuePlan
|
|
11
|
+
from render.public_api.models.key_value_post_input import KeyValuePOSTInput
|
|
12
|
+
from render.public_api.types import UNSET
|
|
13
|
+
|
|
14
|
+
from .api import KeyValueApi
|
|
15
|
+
from .compare import compare_instance_configuration
|
|
16
|
+
from .types import (
|
|
17
|
+
ConnectionInfo,
|
|
18
|
+
InstanceConfiguration,
|
|
19
|
+
KeyValueInstance,
|
|
20
|
+
NameOwnerIdOptions,
|
|
21
|
+
Options,
|
|
22
|
+
ServiceIdOptions,
|
|
23
|
+
)
|
|
24
|
+
from .utils import _format_error_message, _is_local_dev
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from redis.asyncio import Redis
|
|
28
|
+
|
|
29
|
+
# Matches redis:// and rediss:// URLs with optional credentials
|
|
30
|
+
_CONNECTION_RE = re.compile(
|
|
31
|
+
r"rediss?://((?P<username>[\w.~_-]+):(?P<password>[\w.~_-]+)@)?(?P<host>[\w.~_-]+):(?P<port>[0-9]+)"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Max sleep per iteration; total worst-case wait is ~17 minutes
|
|
35
|
+
_MAX_DELAY_SECONDS = 512
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class KeyValueProvider:
|
|
39
|
+
"""High-level Key Value provider.
|
|
40
|
+
|
|
41
|
+
Manages instance discovery, optional auto-provisioning, automatic
|
|
42
|
+
configuration sync, and Redis client construction. Use this when you want
|
|
43
|
+
the SDK to handle instance lifecycle on your behalf.
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
```python
|
|
47
|
+
from render import RenderAsync
|
|
48
|
+
from render.experimental.key_value import NameOwnerIdOptions
|
|
49
|
+
|
|
50
|
+
render = RenderAsync()
|
|
51
|
+
kv = render.experimental.key_value
|
|
52
|
+
|
|
53
|
+
# Returns a redis.asyncio.Redis client, provisioning the instance if needed
|
|
54
|
+
redis = await kv.new_client(NameOwnerIdOptions(name="my-cache"))
|
|
55
|
+
await redis.set("hello", "world")
|
|
56
|
+
|
|
57
|
+
# Or just get connection details (still provisions the instance if needed)
|
|
58
|
+
info = await kv.connection_info(NameOwnerIdOptions(name="my-cache"))
|
|
59
|
+
print(f"redis://{info.host}:{info.port}")
|
|
60
|
+
```
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(self, api: KeyValueApi, default_owner_id: str | None = None):
|
|
64
|
+
"""
|
|
65
|
+
Args:
|
|
66
|
+
api: Low-level Key Value API client.
|
|
67
|
+
default_owner_id: Fallback owner ID when options don't supply one.
|
|
68
|
+
Typically set from ``RENDER_WORKSPACE_ID``.
|
|
69
|
+
"""
|
|
70
|
+
self._api = api
|
|
71
|
+
self._default_owner_id = default_owner_id
|
|
72
|
+
|
|
73
|
+
async def new_client(self, options: Options, **kwargs: Any) -> "Redis":
|
|
74
|
+
"""Return a configured ``redis.asyncio.Redis`` client for the instance.
|
|
75
|
+
|
|
76
|
+
Looks up the instance by service ID or name, optionally provisions it if
|
|
77
|
+
not found, syncs configuration, then constructs a Redis client from the
|
|
78
|
+
connection URL. Additional keyword arguments are forwarded to
|
|
79
|
+
``redis.asyncio.Redis.from_url()``.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
options: Lookup strategy and optional desired configuration.
|
|
83
|
+
Use :class:`ServiceIdOptions` to look up by service ID, or
|
|
84
|
+
:class:`NameOwnerIdOptions` to look up by name.
|
|
85
|
+
**kwargs: Extra arguments passed through to ``Redis.from_url()``.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
redis.asyncio.Redis: A configured but not yet connected Redis client.
|
|
89
|
+
|
|
90
|
+
Raises:
|
|
91
|
+
ImportError: If ``redis`` is not installed.
|
|
92
|
+
RenderError: If the instance cannot be found, provisioned, or reaches
|
|
93
|
+
an unrecoverable state.
|
|
94
|
+
ClientError: For authorization or validation errors from the Render API.
|
|
95
|
+
ServerError: For Render API server errors.
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
import redis.asyncio as redis_asyncio
|
|
99
|
+
except ImportError as exc:
|
|
100
|
+
raise ImportError(
|
|
101
|
+
"redis-py is required for new_client(). Install it with: pip install redis"
|
|
102
|
+
) from exc
|
|
103
|
+
|
|
104
|
+
url = await self._load_connection_string(options)
|
|
105
|
+
return redis_asyncio.Redis.from_url(url, **kwargs)
|
|
106
|
+
|
|
107
|
+
async def connection_info(self, options: Options) -> ConnectionInfo:
|
|
108
|
+
"""Return parsed connection details for the Key Value instance.
|
|
109
|
+
|
|
110
|
+
Looks up the instance by service ID or name, optionally provisions it if
|
|
111
|
+
not found, and syncs configuration.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
options: Lookup strategy and optional desired configuration.
|
|
115
|
+
Use :class:`ServiceIdOptions` to look up by service ID, or
|
|
116
|
+
:class:`NameOwnerIdOptions` to look up by name.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
ConnectionInfo: Parsed host, port, and optional credentials.
|
|
120
|
+
|
|
121
|
+
Raises:
|
|
122
|
+
RenderError: If the instance cannot be found, provisioned, or the
|
|
123
|
+
connection string is in an unexpected format.
|
|
124
|
+
ClientError: For authorization or validation errors from the Render API.
|
|
125
|
+
ServerError: For Render API server errors.
|
|
126
|
+
"""
|
|
127
|
+
connection_string = await self._load_connection_string(options)
|
|
128
|
+
return _parse_connection_string(connection_string)
|
|
129
|
+
|
|
130
|
+
async def _load_connection_string(self, options: Options) -> str:
|
|
131
|
+
if _is_local_dev():
|
|
132
|
+
return _dev_connection_string()
|
|
133
|
+
|
|
134
|
+
if isinstance(options, ServiceIdOptions):
|
|
135
|
+
details = await self._find_instance_by_service_id(options)
|
|
136
|
+
else:
|
|
137
|
+
details = await self._find_instance_by_name_owner_id(options)
|
|
138
|
+
|
|
139
|
+
return await self._api.get_connection_info(details.id)
|
|
140
|
+
|
|
141
|
+
async def _find_instance_by_service_id(
|
|
142
|
+
self, options: ServiceIdOptions
|
|
143
|
+
) -> KeyValueInstance:
|
|
144
|
+
details = await self._api.find_by_id(options.service_id)
|
|
145
|
+
return await self._ensure_configuration_up_to_date(options, details)
|
|
146
|
+
|
|
147
|
+
async def _find_instance_by_name_owner_id(
|
|
148
|
+
self, options: NameOwnerIdOptions
|
|
149
|
+
) -> KeyValueInstance:
|
|
150
|
+
owner_id = self._resolve_owner_id(options.owner_id)
|
|
151
|
+
details = await self._api.find_by_name(options.name, owner_id)
|
|
152
|
+
|
|
153
|
+
if details is None:
|
|
154
|
+
if options.auto_provision is False:
|
|
155
|
+
raise RenderError(
|
|
156
|
+
_format_error_message(
|
|
157
|
+
f"Unable to locate Key Value named '{options.name}'",
|
|
158
|
+
"Please double-check that the name is correct.\n"
|
|
159
|
+
"If you would like one to be created automatically, ensure "
|
|
160
|
+
"that 'auto_provision_enabled' is not set to False.",
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
config = InstanceConfiguration()
|
|
165
|
+
if isinstance(options.auto_provision, InstanceConfiguration):
|
|
166
|
+
config = options.auto_provision
|
|
167
|
+
return await self._provision_new_instance(options.name, owner_id, config)
|
|
168
|
+
|
|
169
|
+
return await self._ensure_configuration_up_to_date(options, details)
|
|
170
|
+
|
|
171
|
+
async def _provision_new_instance(
|
|
172
|
+
self, name: str, resolved_owner_id: str, config: InstanceConfiguration
|
|
173
|
+
) -> KeyValueInstance:
|
|
174
|
+
body = KeyValuePOSTInput(
|
|
175
|
+
name=name,
|
|
176
|
+
owner_id=resolved_owner_id,
|
|
177
|
+
plan=(
|
|
178
|
+
KeyValuePlan(config.plan)
|
|
179
|
+
if config.plan is not None
|
|
180
|
+
else KeyValuePlan.FREE
|
|
181
|
+
),
|
|
182
|
+
maxmemory_policy=(
|
|
183
|
+
config.maxmemory_policy
|
|
184
|
+
if config.maxmemory_policy is not None
|
|
185
|
+
else UNSET
|
|
186
|
+
),
|
|
187
|
+
ip_allow_list=(
|
|
188
|
+
config.ip_allow_list if config.ip_allow_list is not None else UNSET
|
|
189
|
+
),
|
|
190
|
+
)
|
|
191
|
+
data = await self._api.create_instance(body)
|
|
192
|
+
return await self._wait_for_instance_available(data.id)
|
|
193
|
+
|
|
194
|
+
async def _ensure_configuration_up_to_date(
|
|
195
|
+
self, options: Options, details: KeyValueInstance
|
|
196
|
+
) -> KeyValueInstance:
|
|
197
|
+
if not isinstance(options.auto_provision, InstanceConfiguration):
|
|
198
|
+
return details
|
|
199
|
+
|
|
200
|
+
update = compare_instance_configuration(options.auto_provision, details)
|
|
201
|
+
|
|
202
|
+
if update is not None:
|
|
203
|
+
data = await self._api.update_instance(details.id, update)
|
|
204
|
+
return await self._wait_for_instance_available(data.id)
|
|
205
|
+
|
|
206
|
+
return details
|
|
207
|
+
|
|
208
|
+
async def _wait_for_instance_available(self, key_value_id: str) -> KeyValueInstance:
|
|
209
|
+
"""Poll until the instance status is 'available'.
|
|
210
|
+
|
|
211
|
+
Uses exponential backoff starting at 1 second, doubling each iteration
|
|
212
|
+
up to a cap of 512 seconds per sleep (~17 minutes total worst case).
|
|
213
|
+
"""
|
|
214
|
+
retry_delay = 1.0
|
|
215
|
+
|
|
216
|
+
while retry_delay <= _MAX_DELAY_SECONDS:
|
|
217
|
+
try:
|
|
218
|
+
data = await self._api.find_by_id(key_value_id)
|
|
219
|
+
except RenderError as err:
|
|
220
|
+
raise RenderError(
|
|
221
|
+
_format_error_message(
|
|
222
|
+
"Unable to look up status of Key Value instance.",
|
|
223
|
+
"This is most likely a Render error, please try again.",
|
|
224
|
+
)
|
|
225
|
+
) from err
|
|
226
|
+
|
|
227
|
+
if data.status == DatabaseStatus.AVAILABLE:
|
|
228
|
+
return data
|
|
229
|
+
elif data.status in (
|
|
230
|
+
DatabaseStatus.CREATING,
|
|
231
|
+
DatabaseStatus.CONFIG_RESTART,
|
|
232
|
+
DatabaseStatus.UPDATING_INSTANCE,
|
|
233
|
+
DatabaseStatus.UNAVAILABLE,
|
|
234
|
+
):
|
|
235
|
+
await asyncio.sleep(retry_delay)
|
|
236
|
+
else:
|
|
237
|
+
raise RenderError(
|
|
238
|
+
_format_error_message(
|
|
239
|
+
"The requested Key Value instance is not available.",
|
|
240
|
+
"Please view the Key Value on dashboard.render.com to verify its status.",
|
|
241
|
+
)
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
retry_delay *= 2
|
|
245
|
+
|
|
246
|
+
raise RenderError(
|
|
247
|
+
_format_error_message(
|
|
248
|
+
"Timed out waiting for instance to become available.",
|
|
249
|
+
"Please check the Key Value on dashboard.render.com to make sure it is ready, then try again.",
|
|
250
|
+
)
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
def _resolve_owner_id(self, owner_id: str | None) -> str:
|
|
254
|
+
resolved = owner_id or self._default_owner_id
|
|
255
|
+
if not resolved:
|
|
256
|
+
raise RenderError(
|
|
257
|
+
"owner_id is required. Provide it as a parameter or set the RENDER_WORKSPACE_ID environment variable."
|
|
258
|
+
)
|
|
259
|
+
return resolved
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _parse_connection_string(connection: str) -> ConnectionInfo:
|
|
263
|
+
match = _CONNECTION_RE.search(connection)
|
|
264
|
+
|
|
265
|
+
if not match:
|
|
266
|
+
raise RenderError(
|
|
267
|
+
_format_error_message(
|
|
268
|
+
"The Key Value connection string was in an unexpected format",
|
|
269
|
+
"Please confirm you are on the most recent version of the Render SDK",
|
|
270
|
+
)
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
return ConnectionInfo(
|
|
274
|
+
username=match.group("username"),
|
|
275
|
+
password=match.group("password"),
|
|
276
|
+
host=match.group("host"),
|
|
277
|
+
port=int(match.group("port")),
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _dev_connection_string() -> str:
|
|
282
|
+
host = os.environ.get("RENDER_LOCAL_REDIS_HOST") or "localhost"
|
|
283
|
+
port = os.environ.get("RENDER_LOCAL_REDIS_PORT") or "6379"
|
|
284
|
+
|
|
285
|
+
return f"redis://{host}:{port}"
|
|
File without changes
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"""Tests for KeyValueApi."""
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
from types import SimpleNamespace
|
|
5
|
+
from unittest.mock import AsyncMock, MagicMock
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from render.client.errors import ClientError, ServerError
|
|
10
|
+
from render.experimental.key_value.api import KeyValueApi
|
|
11
|
+
from render.experimental.key_value.types import KeyValueInstance
|
|
12
|
+
from render.public_api.models.database_status import DatabaseStatus
|
|
13
|
+
from render.public_api.models.key_value import KeyValue
|
|
14
|
+
from render.public_api.models.key_value_connection_info import (
|
|
15
|
+
KeyValueConnectionInfo,
|
|
16
|
+
)
|
|
17
|
+
from render.public_api.models.key_value_detail import KeyValueDetail
|
|
18
|
+
from render.public_api.models.key_value_options import KeyValueOptions
|
|
19
|
+
from render.public_api.models.key_value_patch_input import KeyValuePATCHInput
|
|
20
|
+
from render.public_api.models.key_value_plan import KeyValuePlan
|
|
21
|
+
from render.public_api.models.key_value_post_input import KeyValuePOSTInput
|
|
22
|
+
from render.public_api.models.key_value_with_cursor import KeyValueWithCursor
|
|
23
|
+
from render.public_api.models.owner import Owner
|
|
24
|
+
from render.public_api.models.owner_type import OwnerType
|
|
25
|
+
from render.public_api.models.region import Region
|
|
26
|
+
|
|
27
|
+
_NOW = datetime.datetime(2024, 1, 1, tzinfo=datetime.timezone.utc)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def make_key_value_detail(
|
|
31
|
+
id_: str = "red-abc",
|
|
32
|
+
status: DatabaseStatus = DatabaseStatus.AVAILABLE,
|
|
33
|
+
plan: KeyValuePlan = KeyValuePlan.FREE,
|
|
34
|
+
) -> KeyValueDetail:
|
|
35
|
+
owner = Owner(
|
|
36
|
+
id="tea-abc", name="Test", email="test@example.com", type_=OwnerType.TEAM
|
|
37
|
+
)
|
|
38
|
+
return KeyValueDetail(
|
|
39
|
+
id=id_,
|
|
40
|
+
created_at=_NOW,
|
|
41
|
+
updated_at=_NOW,
|
|
42
|
+
status=status,
|
|
43
|
+
region=Region.OREGON,
|
|
44
|
+
plan=plan,
|
|
45
|
+
name="test-kv",
|
|
46
|
+
owner=owner,
|
|
47
|
+
options=KeyValueOptions(),
|
|
48
|
+
ip_allow_list=[],
|
|
49
|
+
version="7.2",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def make_key_value(id_: str = "red-abc") -> KeyValue:
|
|
54
|
+
owner = Owner(
|
|
55
|
+
id="tea-abc", name="Test", email="test@example.com", type_=OwnerType.TEAM
|
|
56
|
+
)
|
|
57
|
+
return KeyValue(
|
|
58
|
+
id=id_,
|
|
59
|
+
created_at=_NOW,
|
|
60
|
+
updated_at=_NOW,
|
|
61
|
+
status=DatabaseStatus.AVAILABLE,
|
|
62
|
+
region=Region.OREGON,
|
|
63
|
+
plan=KeyValuePlan.FREE,
|
|
64
|
+
name="test-kv",
|
|
65
|
+
owner=owner,
|
|
66
|
+
options=KeyValueOptions(),
|
|
67
|
+
ip_allow_list=[],
|
|
68
|
+
version="7.2",
|
|
69
|
+
dashboard_url="https://dashboard.render.com/kv/red-abc",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def ok(parsed):
|
|
74
|
+
return SimpleNamespace(status_code=200, parsed=parsed)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def err(status_code):
|
|
78
|
+
return SimpleNamespace(status_code=status_code, parsed=None)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@pytest.fixture
|
|
82
|
+
def api():
|
|
83
|
+
return KeyValueApi(MagicMock())
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class TestFindById:
|
|
87
|
+
@pytest.mark.asyncio
|
|
88
|
+
async def test_handles_api_token_error(self, api, mocker):
|
|
89
|
+
mocker.patch(
|
|
90
|
+
"render.experimental.key_value.api.retrieve_key_value.asyncio_detailed",
|
|
91
|
+
new_callable=AsyncMock,
|
|
92
|
+
return_value=err(401),
|
|
93
|
+
)
|
|
94
|
+
with pytest.raises(ClientError, match="API Token is not authorized"):
|
|
95
|
+
await api.find_by_id("red-abc")
|
|
96
|
+
|
|
97
|
+
@pytest.mark.asyncio
|
|
98
|
+
async def test_handles_not_found_error(self, api, mocker):
|
|
99
|
+
mocker.patch(
|
|
100
|
+
"render.experimental.key_value.api.retrieve_key_value.asyncio_detailed",
|
|
101
|
+
new_callable=AsyncMock,
|
|
102
|
+
return_value=err(404),
|
|
103
|
+
)
|
|
104
|
+
with pytest.raises(ClientError, match="Unable to locate a Key Value with ID"):
|
|
105
|
+
await api.find_by_id("red-abc")
|
|
106
|
+
|
|
107
|
+
@pytest.mark.asyncio
|
|
108
|
+
async def test_handles_unknown_client_error(self, api, mocker):
|
|
109
|
+
mocker.patch(
|
|
110
|
+
"render.experimental.key_value.api.retrieve_key_value.asyncio_detailed",
|
|
111
|
+
new_callable=AsyncMock,
|
|
112
|
+
return_value=err(429),
|
|
113
|
+
)
|
|
114
|
+
with pytest.raises(ClientError):
|
|
115
|
+
await api.find_by_id("red-abc")
|
|
116
|
+
|
|
117
|
+
@pytest.mark.asyncio
|
|
118
|
+
async def test_handles_server_error(self, api, mocker):
|
|
119
|
+
mocker.patch(
|
|
120
|
+
"render.experimental.key_value.api.retrieve_key_value.asyncio_detailed",
|
|
121
|
+
new_callable=AsyncMock,
|
|
122
|
+
return_value=err(500),
|
|
123
|
+
)
|
|
124
|
+
with pytest.raises(ServerError):
|
|
125
|
+
await api.find_by_id("red-abc")
|
|
126
|
+
|
|
127
|
+
@pytest.mark.asyncio
|
|
128
|
+
async def test_returns_instance_on_success(self, api, mocker):
|
|
129
|
+
detail = make_key_value_detail()
|
|
130
|
+
mocker.patch(
|
|
131
|
+
"render.experimental.key_value.api.retrieve_key_value.asyncio_detailed",
|
|
132
|
+
new_callable=AsyncMock,
|
|
133
|
+
return_value=ok(detail),
|
|
134
|
+
)
|
|
135
|
+
result = await api.find_by_id("red-abc")
|
|
136
|
+
assert isinstance(result, KeyValueInstance)
|
|
137
|
+
assert result.id == detail.id
|
|
138
|
+
assert result.status == detail.status
|
|
139
|
+
assert result.plan == detail.plan
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class TestFindByName:
|
|
143
|
+
@pytest.mark.asyncio
|
|
144
|
+
async def test_handles_api_token_error(self, api, mocker):
|
|
145
|
+
mocker.patch(
|
|
146
|
+
"render.experimental.key_value.api.list_key_value.asyncio_detailed",
|
|
147
|
+
new_callable=AsyncMock,
|
|
148
|
+
return_value=err(401),
|
|
149
|
+
)
|
|
150
|
+
with pytest.raises(ClientError, match="API Token is not authorized"):
|
|
151
|
+
await api.find_by_name("test-redis", "tea-abc")
|
|
152
|
+
|
|
153
|
+
@pytest.mark.asyncio
|
|
154
|
+
async def test_handles_unknown_client_error(self, api, mocker):
|
|
155
|
+
mocker.patch(
|
|
156
|
+
"render.experimental.key_value.api.list_key_value.asyncio_detailed",
|
|
157
|
+
new_callable=AsyncMock,
|
|
158
|
+
return_value=err(429),
|
|
159
|
+
)
|
|
160
|
+
with pytest.raises(ClientError):
|
|
161
|
+
await api.find_by_name("test-redis", "tea-abc")
|
|
162
|
+
|
|
163
|
+
@pytest.mark.asyncio
|
|
164
|
+
async def test_handles_server_error(self, api, mocker):
|
|
165
|
+
mocker.patch(
|
|
166
|
+
"render.experimental.key_value.api.list_key_value.asyncio_detailed",
|
|
167
|
+
new_callable=AsyncMock,
|
|
168
|
+
return_value=err(500),
|
|
169
|
+
)
|
|
170
|
+
with pytest.raises(ServerError):
|
|
171
|
+
await api.find_by_name("test-redis", "tea-abc")
|
|
172
|
+
|
|
173
|
+
@pytest.mark.asyncio
|
|
174
|
+
async def test_returns_none_when_no_results(self, api, mocker):
|
|
175
|
+
mocker.patch(
|
|
176
|
+
"render.experimental.key_value.api.list_key_value.asyncio_detailed",
|
|
177
|
+
new_callable=AsyncMock,
|
|
178
|
+
return_value=ok([]),
|
|
179
|
+
)
|
|
180
|
+
result = await api.find_by_name("test-redis", "tea-abc")
|
|
181
|
+
assert result is None
|
|
182
|
+
|
|
183
|
+
@pytest.mark.asyncio
|
|
184
|
+
async def test_returns_instance_on_success(self, api, mocker):
|
|
185
|
+
kv = make_key_value()
|
|
186
|
+
mocker.patch(
|
|
187
|
+
"render.experimental.key_value.api.list_key_value.asyncio_detailed",
|
|
188
|
+
new_callable=AsyncMock,
|
|
189
|
+
return_value=ok([KeyValueWithCursor(key_value=kv, cursor="abc")]),
|
|
190
|
+
)
|
|
191
|
+
result = await api.find_by_name("test-redis", "tea-abc")
|
|
192
|
+
assert isinstance(result, KeyValueInstance)
|
|
193
|
+
assert result.id == kv.id
|
|
194
|
+
assert result.status == kv.status
|
|
195
|
+
assert result.plan == kv.plan
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class TestGetConnectionInfo:
|
|
199
|
+
@pytest.mark.asyncio
|
|
200
|
+
async def test_handles_api_token_error(self, api, mocker):
|
|
201
|
+
mocker.patch(
|
|
202
|
+
"render.experimental.key_value.api.retrieve_key_value_connection_info.asyncio_detailed",
|
|
203
|
+
new_callable=AsyncMock,
|
|
204
|
+
return_value=err(401),
|
|
205
|
+
)
|
|
206
|
+
with pytest.raises(ClientError, match="API Token is not authorized"):
|
|
207
|
+
await api.get_connection_info("red-abc")
|
|
208
|
+
|
|
209
|
+
@pytest.mark.asyncio
|
|
210
|
+
async def test_handles_unknown_client_error(self, api, mocker):
|
|
211
|
+
mocker.patch(
|
|
212
|
+
"render.experimental.key_value.api.retrieve_key_value_connection_info.asyncio_detailed",
|
|
213
|
+
new_callable=AsyncMock,
|
|
214
|
+
return_value=err(429),
|
|
215
|
+
)
|
|
216
|
+
with pytest.raises(ClientError):
|
|
217
|
+
await api.get_connection_info("red-abc")
|
|
218
|
+
|
|
219
|
+
@pytest.mark.asyncio
|
|
220
|
+
async def test_handles_server_error(self, api, mocker):
|
|
221
|
+
mocker.patch(
|
|
222
|
+
"render.experimental.key_value.api.retrieve_key_value_connection_info.asyncio_detailed",
|
|
223
|
+
new_callable=AsyncMock,
|
|
224
|
+
return_value=err(500),
|
|
225
|
+
)
|
|
226
|
+
with pytest.raises(ServerError):
|
|
227
|
+
await api.get_connection_info("red-abc")
|
|
228
|
+
|
|
229
|
+
@pytest.mark.asyncio
|
|
230
|
+
async def test_returns_internal_url_when_on_render(self, api, mocker, monkeypatch):
|
|
231
|
+
internal = "redis://red-abc:6239"
|
|
232
|
+
external = "rediss://abc:xyz@red-abc.ext:6239"
|
|
233
|
+
mocker.patch(
|
|
234
|
+
"render.experimental.key_value.api.retrieve_key_value_connection_info.asyncio_detailed",
|
|
235
|
+
new_callable=AsyncMock,
|
|
236
|
+
return_value=ok(
|
|
237
|
+
KeyValueConnectionInfo(
|
|
238
|
+
internal_connection_string=internal,
|
|
239
|
+
external_connection_string=external,
|
|
240
|
+
cli_command="redis-cli",
|
|
241
|
+
)
|
|
242
|
+
),
|
|
243
|
+
)
|
|
244
|
+
monkeypatch.setenv("RENDER", "true")
|
|
245
|
+
result = await api.get_connection_info("red-abc")
|
|
246
|
+
assert result == internal
|
|
247
|
+
|
|
248
|
+
@pytest.mark.asyncio
|
|
249
|
+
async def test_returns_external_url_when_not_on_render(
|
|
250
|
+
self, api, mocker, monkeypatch
|
|
251
|
+
):
|
|
252
|
+
internal = "redis://red-abc:6239"
|
|
253
|
+
external = "rediss://abc:xyz@red-abc.ext:6239"
|
|
254
|
+
mocker.patch(
|
|
255
|
+
"render.experimental.key_value.api.retrieve_key_value_connection_info.asyncio_detailed",
|
|
256
|
+
new_callable=AsyncMock,
|
|
257
|
+
return_value=ok(
|
|
258
|
+
KeyValueConnectionInfo(
|
|
259
|
+
internal_connection_string=internal,
|
|
260
|
+
external_connection_string=external,
|
|
261
|
+
cli_command="redis-cli",
|
|
262
|
+
)
|
|
263
|
+
),
|
|
264
|
+
)
|
|
265
|
+
monkeypatch.delenv("RENDER", raising=False)
|
|
266
|
+
result = await api.get_connection_info("red-abc")
|
|
267
|
+
assert result == external
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class TestCreateInstance:
|
|
271
|
+
@pytest.mark.asyncio
|
|
272
|
+
async def test_handles_api_token_error(self, api, mocker):
|
|
273
|
+
mocker.patch(
|
|
274
|
+
"render.experimental.key_value.api.create_key_value.asyncio_detailed",
|
|
275
|
+
new_callable=AsyncMock,
|
|
276
|
+
return_value=err(401),
|
|
277
|
+
)
|
|
278
|
+
body = KeyValuePOSTInput(
|
|
279
|
+
name="test-redis", owner_id="tea-abc", plan=KeyValuePlan.FREE
|
|
280
|
+
)
|
|
281
|
+
with pytest.raises(ClientError, match="API Token is not authorized"):
|
|
282
|
+
await api.create_instance(body)
|
|
283
|
+
|
|
284
|
+
@pytest.mark.asyncio
|
|
285
|
+
async def test_handles_unknown_client_error(self, api, mocker):
|
|
286
|
+
mocker.patch(
|
|
287
|
+
"render.experimental.key_value.api.create_key_value.asyncio_detailed",
|
|
288
|
+
new_callable=AsyncMock,
|
|
289
|
+
return_value=err(429),
|
|
290
|
+
)
|
|
291
|
+
body = KeyValuePOSTInput(
|
|
292
|
+
name="test-redis", owner_id="tea-abc", plan=KeyValuePlan.FREE
|
|
293
|
+
)
|
|
294
|
+
with pytest.raises(ClientError):
|
|
295
|
+
await api.create_instance(body)
|
|
296
|
+
|
|
297
|
+
@pytest.mark.asyncio
|
|
298
|
+
async def test_handles_server_error(self, api, mocker):
|
|
299
|
+
mocker.patch(
|
|
300
|
+
"render.experimental.key_value.api.create_key_value.asyncio_detailed",
|
|
301
|
+
new_callable=AsyncMock,
|
|
302
|
+
return_value=err(500),
|
|
303
|
+
)
|
|
304
|
+
body = KeyValuePOSTInput(
|
|
305
|
+
name="test-redis", owner_id="tea-abc", plan=KeyValuePlan.FREE
|
|
306
|
+
)
|
|
307
|
+
with pytest.raises(ServerError):
|
|
308
|
+
await api.create_instance(body)
|
|
309
|
+
|
|
310
|
+
@pytest.mark.asyncio
|
|
311
|
+
async def test_returns_instance_on_success(self, api, mocker):
|
|
312
|
+
detail = make_key_value_detail()
|
|
313
|
+
mocker.patch(
|
|
314
|
+
"render.experimental.key_value.api.create_key_value.asyncio_detailed",
|
|
315
|
+
new_callable=AsyncMock,
|
|
316
|
+
return_value=ok(detail),
|
|
317
|
+
)
|
|
318
|
+
body = KeyValuePOSTInput(
|
|
319
|
+
name="test-redis", owner_id="tea-abc", plan=KeyValuePlan.FREE
|
|
320
|
+
)
|
|
321
|
+
result = await api.create_instance(body)
|
|
322
|
+
assert isinstance(result, KeyValueInstance)
|
|
323
|
+
assert result.id == detail.id
|
|
324
|
+
assert result.plan == detail.plan
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class TestUpdateInstance:
|
|
328
|
+
@pytest.mark.asyncio
|
|
329
|
+
async def test_handles_api_token_error(self, api, mocker):
|
|
330
|
+
mocker.patch(
|
|
331
|
+
"render.experimental.key_value.api.update_key_value.asyncio_detailed",
|
|
332
|
+
new_callable=AsyncMock,
|
|
333
|
+
return_value=err(401),
|
|
334
|
+
)
|
|
335
|
+
with pytest.raises(ClientError, match="API Token is not authorized"):
|
|
336
|
+
await api.update_instance("red-abc", KeyValuePATCHInput())
|
|
337
|
+
|
|
338
|
+
@pytest.mark.asyncio
|
|
339
|
+
async def test_handles_unknown_client_error(self, api, mocker):
|
|
340
|
+
mocker.patch(
|
|
341
|
+
"render.experimental.key_value.api.update_key_value.asyncio_detailed",
|
|
342
|
+
new_callable=AsyncMock,
|
|
343
|
+
return_value=err(429),
|
|
344
|
+
)
|
|
345
|
+
with pytest.raises(ClientError):
|
|
346
|
+
await api.update_instance("red-abc", KeyValuePATCHInput())
|
|
347
|
+
|
|
348
|
+
@pytest.mark.asyncio
|
|
349
|
+
async def test_handles_server_error(self, api, mocker):
|
|
350
|
+
mocker.patch(
|
|
351
|
+
"render.experimental.key_value.api.update_key_value.asyncio_detailed",
|
|
352
|
+
new_callable=AsyncMock,
|
|
353
|
+
return_value=err(500),
|
|
354
|
+
)
|
|
355
|
+
with pytest.raises(ServerError):
|
|
356
|
+
await api.update_instance("red-abc", KeyValuePATCHInput())
|
|
357
|
+
|
|
358
|
+
@pytest.mark.asyncio
|
|
359
|
+
async def test_returns_instance_on_success(self, api, mocker):
|
|
360
|
+
detail = make_key_value_detail(plan=KeyValuePlan.STARTER)
|
|
361
|
+
mocker.patch(
|
|
362
|
+
"render.experimental.key_value.api.update_key_value.asyncio_detailed",
|
|
363
|
+
new_callable=AsyncMock,
|
|
364
|
+
return_value=ok(detail),
|
|
365
|
+
)
|
|
366
|
+
result = await api.update_instance(
|
|
367
|
+
"red-abc", KeyValuePATCHInput(plan=KeyValuePlan.STARTER)
|
|
368
|
+
)
|
|
369
|
+
assert isinstance(result, KeyValueInstance)
|
|
370
|
+
assert result.id == detail.id
|
|
371
|
+
assert result.plan == KeyValuePlan.STARTER
|