frogml 1.1.62__py3-none-any.whl → 1.2.19__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.
- frogml/__init__.py +3 -1
- frogml/_proto/jfml/hosting_gateway/v1/build_upload_url_pb2.py +3 -3
- frogml/_proto/jfml/hosting_gateway/v1/build_upload_url_pb2.pyi +6 -4
- frogml/_proto/jfml/hosting_gateway/v1/hosting_gateway_service_pb2.py +3 -3
- frogml/_proto/jfml/hosting_gateway/v1/hosting_gateway_service_pb2.pyi +8 -9
- frogml/_proto/jfml/model_version/v1/artifact_pb2.py +3 -3
- frogml/_proto/jfml/model_version/v1/artifact_pb2.pyi +8 -9
- frogml/_proto/jfml/model_version/v1/build_spec_pb2.py +3 -3
- frogml/_proto/jfml/model_version/v1/build_spec_pb2.pyi +24 -20
- frogml/_proto/jfml/model_version/v1/model_repository_spec_pb2.py +3 -3
- frogml/_proto/jfml/model_version/v1/model_repository_spec_pb2.pyi +6 -9
- frogml/_proto/jfml/model_version/v1/model_version_framework_pb2.py +3 -3
- frogml/_proto/jfml/model_version/v1/model_version_framework_pb2.pyi +13 -10
- frogml/_proto/jfml/model_version/v1/model_version_manager_service_pb2.py +3 -3
- frogml/_proto/jfml/model_version/v1/model_version_manager_service_pb2.pyi +43 -30
- frogml/_proto/jfml/model_version/v1/model_version_pb2.py +11 -11
- frogml/_proto/jfml/model_version/v1/model_version_pb2.pyi +48 -32
- frogml/_proto/qwak/administration/account/v1/account_pb2.py +25 -23
- frogml/_proto/qwak/administration/account/v1/account_pb2.pyi +55 -21
- frogml/_proto/qwak/administration/account/v1/account_service_pb2.py +3 -3
- frogml/_proto/qwak/administration/account/v1/account_service_pb2.pyi +63 -36
- frogml/_proto/qwak/administration/account/v1/jfrog_tenant_details_pb2.py +5 -5
- frogml/_proto/qwak/administration/account/v1/jfrog_tenant_details_pb2.pyi +35 -22
- frogml/_proto/qwak/administration/account/v1/personalization_pb2.py +3 -3
- frogml/_proto/qwak/administration/account/v1/personalization_pb2.pyi +7 -9
- frogml/_proto/qwak/administration/account/v1/preferences_pb2.py +3 -3
- frogml/_proto/qwak/administration/account/v1/preferences_pb2.pyi +6 -8
- frogml/_proto/qwak/administration/account/v1/terms_pb2.py +3 -3
- frogml/_proto/qwak/administration/account/v1/terms_pb2.pyi +16 -11
- frogml/_proto/qwak/administration/authenticated_user/v1/authenticated_user_service_pb2.py +3 -3
- frogml/_proto/qwak/administration/authenticated_user/v1/authenticated_user_service_pb2.pyi +20 -14
- frogml/_proto/qwak/administration/authenticated_user/v1/credentials_pb2.py +3 -3
- frogml/_proto/qwak/administration/authenticated_user/v1/credentials_pb2.pyi +11 -12
- frogml/_proto/qwak/administration/authenticated_user/v1/details_pb2.py +3 -3
- frogml/_proto/qwak/administration/authenticated_user/v1/details_pb2.pyi +18 -15
- frogml/_proto/qwak/administration/cluster/v2/cluster_pb2.py +3 -3
- frogml/_proto/qwak/administration/cluster/v2/cluster_pb2.pyi +62 -39
- frogml/_proto/qwak/administration/runtime_configuration/v0/container_registry_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/container_registry_config_pb2.pyi +12 -13
- frogml/_proto/qwak/administration/runtime_configuration/v0/creds/auth_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/creds/auth_pb2.pyi +5 -8
- frogml/_proto/qwak/administration/runtime_configuration/v0/creds/secret_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/creds/secret_pb2.pyi +8 -10
- frogml/_proto/qwak/administration/runtime_configuration/v0/data_catalog_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/data_catalog_config_pb2.pyi +11 -11
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/databricks/auth_pb2.py +11 -7
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/databricks/auth_pb2.pyi +58 -12
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/elasticsearch_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/elasticsearch_config_pb2.pyi +8 -11
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/kafka_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/kafka_config_pb2.pyi +12 -12
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/prometheus_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/prometheus_config_pb2.pyi +8 -10
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/redis_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/redis_config_pb2.pyi +8 -11
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/victoriametrics_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/external/victoriametrics_config_pb2.pyi +6 -9
- frogml/_proto/qwak/administration/runtime_configuration/v0/feature_store_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/feature_store_config_pb2.pyi +13 -14
- frogml/_proto/qwak/administration/runtime_configuration/v0/hosting/aws/auth_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/hosting/aws/auth_pb2.pyi +29 -25
- frogml/_proto/qwak/administration/runtime_configuration/v0/hosting/azure/auth_pb2.py +11 -7
- frogml/_proto/qwak/administration/runtime_configuration/v0/hosting/azure/auth_pb2.pyi +57 -17
- frogml/_proto/qwak/administration/runtime_configuration/v0/hosting_config_pb2.py +5 -5
- frogml/_proto/qwak/administration/runtime_configuration/v0/hosting_config_pb2.pyi +29 -24
- frogml/_proto/qwak/administration/runtime_configuration/v0/logs_storage_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/logs_storage_config_pb2.pyi +6 -9
- frogml/_proto/qwak/administration/runtime_configuration/v0/model_analytics_storage_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/model_analytics_storage_config_pb2.pyi +6 -9
- frogml/_proto/qwak/administration/runtime_configuration/v0/network_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/network_config_pb2.pyi +22 -21
- frogml/_proto/qwak/administration/runtime_configuration/v0/object_storage_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/object_storage_config_pb2.pyi +12 -12
- frogml/_proto/qwak/administration/runtime_configuration/v0/observability_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/observability_config_pb2.pyi +13 -14
- frogml/_proto/qwak/administration/runtime_configuration/v0/runtime_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/runtime_config_pb2.pyi +5 -8
- frogml/_proto/qwak/administration/runtime_configuration/v0/sql_engine_config_pb2.py +3 -3
- frogml/_proto/qwak/administration/runtime_configuration/v0/sql_engine_config_pb2.pyi +11 -11
- frogml/_proto/qwak/administration/v0/authentication/authentication_service_pb2.py +3 -3
- frogml/_proto/qwak/administration/v0/authentication/authentication_service_pb2.pyi +14 -13
- frogml/_proto/qwak/administration/v0/environments/configuration_pb2.py +3 -3
- frogml/_proto/qwak/administration/v0/environments/configuration_pb2.pyi +33 -20
- frogml/_proto/qwak/administration/v0/environments/environment_pb2.py +5 -5
- frogml/_proto/qwak/administration/v0/environments/environment_pb2.pyi +17 -8
- frogml/_proto/qwak/administration/v0/environments/environment_service_pb2.py +5 -5
- frogml/_proto/qwak/administration/v0/environments/environment_service_pb2.pyi +46 -26
- frogml/_proto/qwak/administration/v0/environments/personalization_pb2.py +3 -3
- frogml/_proto/qwak/administration/v0/environments/personalization_pb2.pyi +7 -9
- frogml/_proto/qwak/administration/v0/users/user_pb2.py +7 -7
- frogml/_proto/qwak/administration/v0/users/user_pb2.pyi +18 -11
- frogml/_proto/qwak/admiral/secret/v0/secret_pb2.py +21 -19
- frogml/_proto/qwak/admiral/secret/v0/secret_pb2.pyi +65 -24
- frogml/_proto/qwak/admiral/secret/v0/secret_service_pb2.py +3 -3
- frogml/_proto/qwak/admiral/secret/v0/secret_service_pb2.pyi +16 -12
- frogml/_proto/qwak/admiral/secret/v0/system_secret_service_pb2.py +3 -3
- frogml/_proto/qwak/admiral/secret/v0/system_secret_service_pb2.pyi +19 -14
- frogml/_proto/qwak/admiral/user_application_instance/v0/user_application_instance_pb2.py +3 -3
- frogml/_proto/qwak/admiral/user_application_instance/v0/user_application_instance_pb2.pyi +83 -48
- frogml/_proto/qwak/admiral/user_application_instance/v0/user_application_instance_service_pb2.py +3 -3
- frogml/_proto/qwak/admiral/user_application_instance/v0/user_application_instance_service_pb2.pyi +25 -16
- frogml/_proto/qwak/analytics/analytics_pb2.py +3 -3
- frogml/_proto/qwak/analytics/analytics_pb2.pyi +33 -16
- frogml/_proto/qwak/analytics/analytics_service_pb2.py +3 -3
- frogml/_proto/qwak/analytics/analytics_service_pb2.pyi +46 -26
- frogml/_proto/qwak/artifactory_settings/artifactory_settings_pb2.py +3 -3
- frogml/_proto/qwak/artifactory_settings/artifactory_settings_pb2.pyi +7 -9
- frogml/_proto/qwak/audience/v1/audience_api_pb2.py +3 -3
- frogml/_proto/qwak/audience/v1/audience_api_pb2.pyi +25 -17
- frogml/_proto/qwak/audience/v1/audience_pb2.py +5 -5
- frogml/_proto/qwak/audience/v1/audience_pb2.pyi +38 -23
- frogml/_proto/qwak/auto_scaling/v1/auto_scaling_pb2.py +3 -3
- frogml/_proto/qwak/auto_scaling/v1/auto_scaling_pb2.pyi +22 -13
- frogml/_proto/qwak/auto_scaling/v1/auto_scaling_service_pb2.py +3 -3
- frogml/_proto/qwak/auto_scaling/v1/auto_scaling_service_pb2.pyi +8 -9
- frogml/_proto/qwak/automation/v1/action_pb2.py +17 -17
- frogml/_proto/qwak/automation/v1/action_pb2.pyi +76 -47
- frogml/_proto/qwak/automation/v1/auto_scaling_pb2.py +3 -3
- frogml/_proto/qwak/automation/v1/auto_scaling_pb2.pyi +22 -13
- frogml/_proto/qwak/automation/v1/automation_execution_pb2.py +3 -3
- frogml/_proto/qwak/automation/v1/automation_execution_pb2.pyi +23 -13
- frogml/_proto/qwak/automation/v1/automation_management_service_pb2.py +5 -5
- frogml/_proto/qwak/automation/v1/automation_management_service_pb2.pyi +56 -32
- frogml/_proto/qwak/automation/v1/automation_pb2.py +3 -3
- frogml/_proto/qwak/automation/v1/automation_pb2.pyi +28 -25
- frogml/_proto/qwak/automation/v1/common_pb2.py +3 -3
- frogml/_proto/qwak/automation/v1/common_pb2.pyi +8 -5
- frogml/_proto/qwak/automation/v1/notification_pb2.py +7 -7
- frogml/_proto/qwak/automation/v1/notification_pb2.pyi +14 -8
- frogml/_proto/qwak/automation/v1/trigger_pb2.py +3 -3
- frogml/_proto/qwak/automation/v1/trigger_pb2.pyi +17 -16
- frogml/_proto/qwak/batch_job/v1/batch_job_events_pb2.py +13 -13
- frogml/_proto/qwak/batch_job/v1/batch_job_events_pb2.pyi +22 -14
- frogml/_proto/qwak/batch_job/v1/batch_job_resources_pb2.py +3 -3
- frogml/_proto/qwak/batch_job/v1/batch_job_resources_pb2.pyi +4 -2
- frogml/_proto/qwak/batch_job/v1/batch_job_service_pb2.py +127 -127
- frogml/_proto/qwak/batch_job/v1/batch_job_service_pb2.pyi +196 -101
- frogml/_proto/qwak/build/v1/build_api_pb2.py +17 -17
- frogml/_proto/qwak/build/v1/build_api_pb2.pyi +87 -46
- frogml/_proto/qwak/build/v1/build_pb2.py +9 -9
- frogml/_proto/qwak/build/v1/build_pb2.pyi +187 -118
- frogml/_proto/qwak/build_settings/build_settings_api_pb2.py +3 -3
- frogml/_proto/qwak/build_settings/build_settings_api_pb2.pyi +15 -13
- frogml/_proto/qwak/build_settings/build_settings_pb2.py +3 -3
- frogml/_proto/qwak/build_settings/build_settings_pb2.pyi +24 -19
- frogml/_proto/qwak/builds/build_pb2.py +49 -48
- frogml/_proto/qwak/builds/build_pb2.pyi +113 -53
- frogml/_proto/qwak/builds/build_url_pb2.py +5 -5
- frogml/_proto/qwak/builds/build_url_pb2.pyi +39 -21
- frogml/_proto/qwak/builds/build_values_pb2.py +82 -0
- frogml/_proto/qwak/builds/build_values_pb2.pyi +582 -0
- frogml/_proto/qwak/builds/build_values_pb2_grpc.py +4 -0
- frogml/_proto/qwak/builds/builds_orchestrator_service_pb2.py +80 -52
- frogml/_proto/qwak/builds/builds_orchestrator_service_pb2.pyi +261 -40
- frogml/_proto/qwak/builds/builds_orchestrator_service_pb2_grpc.py +66 -0
- frogml/_proto/qwak/builds/builds_pb2.py +7 -7
- frogml/_proto/qwak/builds/builds_pb2.pyi +177 -105
- frogml/_proto/qwak/builds/internal_builds_orchestrator_service_pb2.py +3 -3
- frogml/_proto/qwak/builds/internal_builds_orchestrator_service_pb2.pyi +12 -10
- frogml/_proto/qwak/data_versioning/data_versioning_pb2.py +3 -3
- frogml/_proto/qwak/data_versioning/data_versioning_pb2.pyi +8 -10
- frogml/_proto/qwak/data_versioning/data_versioning_service_pb2.py +3 -3
- frogml/_proto/qwak/data_versioning/data_versioning_service_pb2.pyi +12 -11
- frogml/_proto/qwak/deployment/alert_pb2.py +5 -5
- frogml/_proto/qwak/deployment/alert_pb2.pyi +31 -20
- frogml/_proto/qwak/deployment/alert_service_pb2.py +7 -7
- frogml/_proto/qwak/deployment/alert_service_pb2.pyi +34 -21
- frogml/_proto/qwak/deployment/deployment_messages_pb2.py +3 -3
- frogml/_proto/qwak/deployment/deployment_messages_pb2.pyi +9 -11
- frogml/_proto/qwak/deployment/deployment_pb2.py +33 -33
- frogml/_proto/qwak/deployment/deployment_pb2.pyi +225 -139
- frogml/_proto/qwak/deployment/deployment_service_pb2.py +81 -81
- frogml/_proto/qwak/deployment/deployment_service_pb2.pyi +139 -78
- frogml/_proto/qwak/ecosystem/jfrog/v0/jfrog_tenant_info_service_pb2.py +3 -3
- frogml/_proto/qwak/ecosystem/jfrog/v0/jfrog_tenant_info_service_pb2.pyi +11 -9
- frogml/_proto/qwak/ecosystem/jfrog/v0/jfrog_tenant_pb2.py +3 -3
- frogml/_proto/qwak/ecosystem/jfrog/v0/jfrog_tenant_pb2.pyi +6 -8
- frogml/_proto/qwak/ecosystem/jfrog/v0/token_pb2.py +41 -31
- frogml/_proto/qwak/ecosystem/jfrog/v0/token_pb2.pyi +168 -36
- frogml/_proto/qwak/ecosystem/jfrog/v0/token_service_pb2.py +3 -3
- frogml/_proto/qwak/ecosystem/jfrog/v0/token_service_pb2.pyi +29 -19
- frogml/_proto/qwak/ecosystem/v0/auth_pb2.py +28 -0
- frogml/_proto/qwak/ecosystem/v0/auth_pb2.pyi +35 -0
- frogml/_proto/qwak/ecosystem/v0/auth_pb2_grpc.py +4 -0
- frogml/_proto/qwak/ecosystem/v0/azure_credentials_pb2.py +37 -0
- frogml/_proto/qwak/ecosystem/v0/azure_credentials_pb2.pyi +119 -0
- frogml/_proto/qwak/ecosystem/v0/azure_credentials_pb2_grpc.py +4 -0
- frogml/_proto/qwak/ecosystem/v0/credentials_pb2.py +11 -10
- frogml/_proto/qwak/ecosystem/v0/credentials_pb2.pyi +21 -15
- frogml/_proto/qwak/ecosystem/v0/ecosystem_pb2.py +11 -11
- frogml/_proto/qwak/ecosystem/v0/ecosystem_pb2.pyi +63 -40
- frogml/_proto/qwak/ecosystem/v0/ecosystem_runtime_service_pb2.py +5 -5
- frogml/_proto/qwak/ecosystem/v0/ecosystem_runtime_service_pb2.pyi +74 -41
- frogml/_proto/qwak/execution/v1/backfill_pb2.py +3 -3
- frogml/_proto/qwak/execution/v1/backfill_pb2.pyi +34 -24
- frogml/_proto/qwak/execution/v1/batch_pb2.py +3 -3
- frogml/_proto/qwak/execution/v1/batch_pb2.pyi +16 -13
- frogml/_proto/qwak/execution/v1/deletion_pb2.py +3 -3
- frogml/_proto/qwak/execution/v1/deletion_pb2.pyi +9 -9
- frogml/_proto/qwak/execution/v1/execution_pb2.py +3 -3
- frogml/_proto/qwak/execution/v1/execution_pb2.pyi +28 -12
- frogml/_proto/qwak/execution/v1/execution_service_pb2.py +5 -5
- frogml/_proto/qwak/execution/v1/execution_service_pb2.pyi +69 -43
- frogml/_proto/qwak/execution/v1/internal/deployment/platform_details_pb2.py +3 -3
- frogml/_proto/qwak/execution/v1/internal/deployment/platform_details_pb2.pyi +4 -7
- frogml/_proto/qwak/execution/v1/jobs/job_pb2.py +5 -5
- frogml/_proto/qwak/execution/v1/jobs/job_pb2.pyi +45 -22
- frogml/_proto/qwak/execution/v1/jobs/job_service_pb2.py +3 -3
- frogml/_proto/qwak/execution/v1/jobs/job_service_pb2.pyi +62 -37
- frogml/_proto/qwak/execution/v1/jobs/reports/report_pb2.py +5 -5
- frogml/_proto/qwak/execution/v1/jobs/reports/report_pb2.pyi +49 -29
- frogml/_proto/qwak/execution/v1/state/execution_state_pb2.py +3 -3
- frogml/_proto/qwak/execution/v1/state/execution_state_pb2.pyi +6 -9
- frogml/_proto/qwak/execution/v1/state/execution_state_service_pb2.py +3 -3
- frogml/_proto/qwak/execution/v1/state/execution_state_service_pb2.pyi +27 -19
- frogml/_proto/qwak/execution/v1/state/featureset_state_pb2.py +3 -3
- frogml/_proto/qwak/execution/v1/state/featureset_state_pb2.pyi +4 -7
- frogml/_proto/qwak/execution/v1/state/spark_execution_state_pb2.py +5 -5
- frogml/_proto/qwak/execution/v1/state/spark_execution_state_pb2.pyi +13 -7
- frogml/_proto/qwak/execution/v1/streaming_aggregation_pb2.py +21 -14
- frogml/_proto/qwak/execution/v1/streaming_aggregation_pb2.pyi +83 -11
- frogml/_proto/qwak/execution/v1/streaming_pb2.py +3 -3
- frogml/_proto/qwak/execution/v1/streaming_pb2.pyi +10 -10
- frogml/_proto/qwak/feature_store/entities/entity_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/entities/entity_pb2.pyi +29 -16
- frogml/_proto/qwak/feature_store/entities/entity_service_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/entities/entity_service_pb2.pyi +37 -22
- frogml/_proto/qwak/feature_store/features/aggregation_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/features/aggregation_pb2.pyi +39 -21
- frogml/_proto/qwak/feature_store/features/deployment_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/features/deployment_pb2.pyi +51 -27
- frogml/_proto/qwak/feature_store/features/deployment_service_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/features/deployment_service_pb2.pyi +5 -7
- frogml/_proto/qwak/feature_store/features/execution_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/features/execution_pb2.pyi +18 -13
- frogml/_proto/qwak/feature_store/features/feature_set_attribute_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/features/feature_set_attribute_pb2.pyi +6 -8
- frogml/_proto/qwak/feature_store/features/feature_set_pb2.py +21 -21
- frogml/_proto/qwak/feature_store/features/feature_set_pb2.pyi +85 -48
- frogml/_proto/qwak/feature_store/features/feature_set_service_pb2.py +9 -9
- frogml/_proto/qwak/feature_store/features/feature_set_service_pb2.pyi +107 -53
- frogml/_proto/qwak/feature_store/features/feature_set_state_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/features/feature_set_state_pb2.pyi +46 -23
- frogml/_proto/qwak/feature_store/features/feature_set_state_service_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/features/feature_set_state_service_pb2.pyi +27 -17
- frogml/_proto/qwak/feature_store/features/feature_set_types_pb2.py +73 -71
- frogml/_proto/qwak/feature_store/features/feature_set_types_pb2.pyi +181 -99
- frogml/_proto/qwak/feature_store/features/monitoring_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/features/monitoring_pb2.pyi +11 -11
- frogml/_proto/qwak/feature_store/features/real_time_feature_extractor_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/features/real_time_feature_extractor_pb2.pyi +63 -37
- frogml/_proto/qwak/feature_store/jobs/job_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/jobs/job_pb2.pyi +26 -14
- frogml/_proto/qwak/feature_store/jobs/job_service_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/jobs/job_service_pb2.pyi +36 -25
- frogml/_proto/qwak/feature_store/jobs/v1/job_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/jobs/v1/job_pb2.pyi +23 -12
- frogml/_proto/qwak/feature_store/jobs/v1/job_service_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/jobs/v1/job_service_pb2.pyi +51 -30
- frogml/_proto/qwak/feature_store/platform/platform_details_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/platform/platform_details_pb2.pyi +11 -11
- frogml/_proto/qwak/feature_store/reports/report_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/reports/report_pb2.pyi +28 -18
- frogml/_proto/qwak/feature_store/repository/common/platform_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/repository/common/platform_pb2.pyi +13 -12
- frogml/_proto/qwak/feature_store/serving/management_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/serving/management_pb2.pyi +10 -10
- frogml/_proto/qwak/feature_store/serving/metadata_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/serving/metadata_pb2.pyi +21 -15
- frogml/_proto/qwak/feature_store/serving/serving_pb2.py +13 -13
- frogml/_proto/qwak/feature_store/serving/serving_pb2.pyi +67 -37
- frogml/_proto/qwak/feature_store/serving/v1/value_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/serving/v1/value_pb2.pyi +8 -10
- frogml/_proto/qwak/feature_store/sinks/sink_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/sinks/sink_pb2.pyi +20 -16
- frogml/_proto/qwak/feature_store/sources/batch_pb2.py +83 -77
- frogml/_proto/qwak/feature_store/sources/batch_pb2.pyi +188 -62
- frogml/_proto/qwak/feature_store/sources/data_source_attribute_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/sources/data_source_attribute_pb2.pyi +6 -8
- frogml/_proto/qwak/feature_store/sources/data_source_pb2.py +7 -7
- frogml/_proto/qwak/feature_store/sources/data_source_pb2.pyi +37 -30
- frogml/_proto/qwak/feature_store/sources/data_source_service_pb2.py +5 -5
- frogml/_proto/qwak/feature_store/sources/data_source_service_pb2.pyi +45 -25
- frogml/_proto/qwak/feature_store/sources/streaming_pb2.py +11 -11
- frogml/_proto/qwak/feature_store/sources/streaming_pb2.pyi +41 -21
- frogml/_proto/qwak/feature_store/v1/common/jfrog_artifact/jfrog_artifact_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/v1/common/jfrog_artifact/jfrog_artifact_pb2.pyi +4 -7
- frogml/_proto/qwak/feature_store/v1/common/source_code/source_code_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/v1/common/source_code/source_code_pb2.pyi +17 -17
- frogml/_proto/qwak/feature_store/v1/internal/data_source/data_source_service_pb2.py +5 -5
- frogml/_proto/qwak/feature_store/v1/internal/data_source/data_source_service_pb2.pyi +15 -13
- frogml/_proto/qwak/feature_store/v1/internal/featureset/featureset_token_service_pb2.py +3 -3
- frogml/_proto/qwak/feature_store/v1/internal/featureset/featureset_token_service_pb2.pyi +6 -8
- frogml/_proto/qwak/features_operator/v1/features_operator_pb2.py +3 -3
- frogml/_proto/qwak/features_operator/v1/features_operator_pb2.pyi +15 -11
- frogml/_proto/qwak/features_operator/v1/features_operator_service_pb2.py +3 -3
- frogml/_proto/qwak/features_operator/v1/features_operator_service_pb2.pyi +18 -16
- frogml/_proto/qwak/features_operator/v2/features_operator_pb2.py +3 -3
- frogml/_proto/qwak/features_operator/v2/features_operator_pb2.pyi +16 -11
- frogml/_proto/qwak/features_operator/v2/features_operator_service_pb2.py +3 -3
- frogml/_proto/qwak/features_operator/v2/features_operator_service_pb2.pyi +20 -19
- frogml/_proto/qwak/features_operator/v3/features_operator_async_service_pb2.py +3 -3
- frogml/_proto/qwak/features_operator/v3/features_operator_async_service_pb2.pyi +41 -34
- frogml/_proto/qwak/features_operator/v3/features_operator_pb2.py +3 -3
- frogml/_proto/qwak/features_operator/v3/features_operator_pb2.pyi +19 -13
- frogml/_proto/qwak/file_versioning/file_versioning_pb2.py +5 -5
- frogml/_proto/qwak/file_versioning/file_versioning_pb2.pyi +8 -5
- frogml/_proto/qwak/file_versioning/file_versioning_service_pb2.py +3 -3
- frogml/_proto/qwak/file_versioning/file_versioning_service_pb2.pyi +12 -11
- frogml/_proto/qwak/fitness_service/constructs_pb2.py +5 -5
- frogml/_proto/qwak/fitness_service/constructs_pb2.pyi +51 -16
- frogml/_proto/qwak/fitness_service/fitness_pb2.py +3 -3
- frogml/_proto/qwak/fitness_service/fitness_pb2.pyi +24 -18
- frogml/_proto/qwak/fitness_service/fitness_service_pb2.py +3 -3
- frogml/_proto/qwak/fitness_service/fitness_service_pb2.pyi +18 -13
- frogml/_proto/qwak/fitness_service/status_pb2.py +3 -3
- frogml/_proto/qwak/fitness_service/status_pb2.pyi +26 -16
- frogml/_proto/qwak/inference/feedback/feedback_pb2.py +3 -3
- frogml/_proto/qwak/inference/feedback/feedback_pb2.pyi +28 -15
- frogml/_proto/qwak/instance_template/instance_template_pb2.py +11 -11
- frogml/_proto/qwak/instance_template/instance_template_pb2.pyi +13 -7
- frogml/_proto/qwak/instance_template/instance_template_service_pb2.py +3 -3
- frogml/_proto/qwak/instance_template/instance_template_service_pb2.pyi +12 -12
- frogml/_proto/qwak/integration/hugging_face_integration_pb2.py +3 -3
- frogml/_proto/qwak/integration/hugging_face_integration_pb2.pyi +19 -17
- frogml/_proto/qwak/integration/integration_pb2.py +3 -3
- frogml/_proto/qwak/integration/integration_pb2.pyi +50 -32
- frogml/_proto/qwak/integration/integration_service_pb2.py +3 -3
- frogml/_proto/qwak/integration/integration_service_pb2.pyi +39 -23
- frogml/_proto/qwak/integration/open_a_i_integration_pb2.py +3 -3
- frogml/_proto/qwak/integration/open_a_i_integration_pb2.pyi +20 -17
- frogml/_proto/qwak/integration/opsgenie_integration_pb2.py +5 -5
- frogml/_proto/qwak/integration/opsgenie_integration_pb2.pyi +29 -16
- frogml/_proto/qwak/integration/pagerduty_integration_pb2.py +5 -5
- frogml/_proto/qwak/integration/pagerduty_integration_pb2.pyi +39 -26
- frogml/_proto/qwak/integration/slack_app_integration_pb2.py +5 -5
- frogml/_proto/qwak/integration/slack_app_integration_pb2.pyi +30 -20
- frogml/_proto/qwak/jfrog/gateway/v0/repository_pb2.py +3 -3
- frogml/_proto/qwak/jfrog/gateway/v0/repository_pb2.pyi +19 -16
- frogml/_proto/qwak/jfrog/gateway/v0/repository_service_pb2.py +3 -3
- frogml/_proto/qwak/jfrog/gateway/v0/repository_service_pb2.pyi +11 -11
- frogml/_proto/qwak/kube_deployment_captain/alert_pb2.py +5 -5
- frogml/_proto/qwak/kube_deployment_captain/alert_pb2.pyi +25 -15
- frogml/_proto/qwak/kube_deployment_captain/alerting_pb2.py +3 -3
- frogml/_proto/qwak/kube_deployment_captain/alerting_pb2.pyi +14 -12
- frogml/_proto/qwak/kube_deployment_captain/batch_job_pb2.py +67 -67
- frogml/_proto/qwak/kube_deployment_captain/batch_job_pb2.pyi +106 -59
- frogml/_proto/qwak/kube_deployment_captain/deployment_pb2.py +3 -3
- frogml/_proto/qwak/kube_deployment_captain/deployment_pb2.pyi +63 -40
- frogml/_proto/qwak/kube_deployment_captain/feature_set_deployment_pb2.py +7 -7
- frogml/_proto/qwak/kube_deployment_captain/feature_set_deployment_pb2.pyi +63 -39
- frogml/_proto/qwak/kube_deployment_captain/kube_deployment_captain_service_pb2.py +17 -17
- frogml/_proto/qwak/kube_deployment_captain/kube_deployment_captain_service_pb2.pyi +146 -72
- frogml/_proto/qwak/kube_deployment_captain/traffic_mapping_pb2.py +3 -3
- frogml/_proto/qwak/kube_deployment_captain/traffic_mapping_pb2.pyi +8 -10
- frogml/_proto/qwak/logging/log_filter_pb2.py +3 -3
- frogml/_proto/qwak/logging/log_filter_pb2.pyi +18 -13
- frogml/_proto/qwak/logging/log_line_pb2.py +5 -5
- frogml/_proto/qwak/logging/log_line_pb2.pyi +7 -8
- frogml/_proto/qwak/logging/log_reader_service_pb2.py +3 -3
- frogml/_proto/qwak/logging/log_reader_service_pb2.pyi +19 -18
- frogml/_proto/qwak/logging/log_source_pb2.py +3 -3
- frogml/_proto/qwak/logging/log_source_pb2.pyi +39 -29
- frogml/_proto/qwak/model_descriptor/open_ai_descriptor_pb2.py +3 -3
- frogml/_proto/qwak/model_descriptor/open_ai_descriptor_pb2.pyi +48 -44
- frogml/_proto/qwak/model_group/model_group_pb2.py +24 -16
- frogml/_proto/qwak/model_group/model_group_pb2.pyi +90 -12
- frogml/_proto/qwak/model_group/model_group_pb2_grpc.py +37 -0
- frogml/_proto/qwak/model_group/model_group_repository_details_pb2.py +3 -3
- frogml/_proto/qwak/model_group/model_group_repository_details_pb2.pyi +28 -18
- frogml/_proto/qwak/models/models_pb2.py +38 -28
- frogml/_proto/qwak/models/models_pb2.pyi +229 -84
- frogml/_proto/qwak/models/models_pb2_grpc.py +34 -0
- frogml/_proto/qwak/models/models_query_pb2.py +3 -3
- frogml/_proto/qwak/models/models_query_pb2.pyi +18 -13
- frogml/_proto/qwak/monitoring/v0/alerting_channel_management_service_pb2.py +3 -3
- frogml/_proto/qwak/monitoring/v0/alerting_channel_management_service_pb2.pyi +31 -18
- frogml/_proto/qwak/monitoring/v0/alerting_channel_pb2.py +3 -3
- frogml/_proto/qwak/monitoring/v0/alerting_channel_pb2.pyi +62 -28
- frogml/_proto/qwak/monitoring/v0/alerting_channel_sync_service_pb2.py +3 -3
- frogml/_proto/qwak/monitoring/v0/alerting_channel_sync_service_pb2.pyi +18 -14
- frogml/_proto/qwak/offline/serving/v1/feature_values_pb2.py +3 -3
- frogml/_proto/qwak/offline/serving/v1/feature_values_pb2.pyi +5 -7
- frogml/_proto/qwak/offline/serving/v1/offline_serving_async_service_pb2.py +3 -3
- frogml/_proto/qwak/offline/serving/v1/offline_serving_async_service_pb2.pyi +43 -23
- frogml/_proto/qwak/offline/serving/v1/options_pb2.py +3 -3
- frogml/_proto/qwak/offline/serving/v1/options_pb2.pyi +4 -7
- frogml/_proto/qwak/offline/serving/v1/population_pb2.py +3 -3
- frogml/_proto/qwak/offline/serving/v1/population_pb2.pyi +18 -15
- frogml/_proto/qwak/projects/jfrog_project_spec_pb2.py +3 -3
- frogml/_proto/qwak/projects/jfrog_project_spec_pb2.pyi +6 -9
- frogml/_proto/qwak/projects/projects_pb2.py +22 -20
- frogml/_proto/qwak/projects/projects_pb2.pyi +74 -36
- frogml/_proto/qwak/secret_service/secret_service_pb2.py +3 -3
- frogml/_proto/qwak/secret_service/secret_service_pb2.pyi +13 -11
- frogml/_proto/qwak/self_service/account/v0/account_membership_pb2.py +7 -7
- frogml/_proto/qwak/self_service/account/v0/account_membership_pb2.pyi +44 -22
- frogml/_proto/qwak/self_service/account/v0/account_membership_service_pb2.py +3 -3
- frogml/_proto/qwak/self_service/account/v0/account_membership_service_pb2.pyi +48 -24
- frogml/_proto/qwak/self_service/account/v0/account_status_pb2.py +5 -5
- frogml/_proto/qwak/self_service/account/v0/account_status_pb2.pyi +30 -23
- frogml/_proto/qwak/self_service/account/v0/managing_account_pb2.py +31 -25
- frogml/_proto/qwak/self_service/account/v0/managing_account_pb2.pyi +84 -22
- frogml/_proto/qwak/self_service/account/v0/managing_account_service_pb2.py +3 -3
- frogml/_proto/qwak/self_service/account/v0/managing_account_service_pb2.pyi +25 -16
- frogml/_proto/qwak/self_service/user/v1/api_key_pb2.py +3 -3
- frogml/_proto/qwak/self_service/user/v1/api_key_pb2.pyi +4 -7
- frogml/_proto/qwak/self_service/user/v1/user_pb2.py +3 -3
- frogml/_proto/qwak/self_service/user/v1/user_pb2.pyi +16 -16
- frogml/_proto/qwak/self_service/user/v1/user_service_pb2.py +5 -5
- frogml/_proto/qwak/self_service/user/v1/user_service_pb2.pyi +27 -14
- frogml/_proto/qwak/service_discovery/service_discovery_location_pb2.py +3 -3
- frogml/_proto/qwak/service_discovery/service_discovery_location_pb2.pyi +11 -11
- frogml/_proto/qwak/service_discovery/service_discovery_location_service_pb2.py +3 -3
- frogml/_proto/qwak/service_discovery/service_discovery_location_service_pb2.pyi +6 -8
- frogml/_proto/qwak/traffic/v1/traffic_api_pb2.py +3 -3
- frogml/_proto/qwak/traffic/v1/traffic_api_pb2.pyi +19 -14
- frogml/_proto/qwak/traffic/v1/traffic_pb2.py +3 -3
- frogml/_proto/qwak/traffic/v1/traffic_pb2.pyi +35 -22
- frogml/_proto/qwak/user_application/common/v0/resources_pb2.py +9 -9
- frogml/_proto/qwak/user_application/common/v0/resources_pb2.pyi +53 -19
- frogml/_proto/qwak/user_application/v0/user_application_pb2.py +7 -7
- frogml/_proto/qwak/user_application/v0/user_application_pb2.pyi +8 -5
- frogml/core/automations/batch_execution_action.py +4 -1
- frogml/core/clients/batch_job_management/client.py +1 -0
- frogml/core/clients/batch_job_management/executions_config.py +2 -0
- frogml/core/clients/build_orchestrator/build_model_request_getter.py +6 -2
- frogml/core/clients/build_orchestrator/client.py +56 -5
- frogml/core/clients/feature_store/management_client.py +159 -220
- frogml/core/clients/feature_store/operator_client.py +21 -2
- frogml/core/clients/jfrog_gateway/client.py +0 -20
- frogml/core/clients/model_group_management/client.py +20 -1
- frogml/core/exceptions/__init__.py +1 -0
- frogml/core/exceptions/frogml_grpc_address_exception.py +9 -0
- frogml/core/exceptions/frogml_token_exception.py +7 -0
- frogml/core/feature_store/_common/source_code_spec.py +60 -14
- frogml/core/feature_store/data_sources/attributes.py +5 -8
- frogml/core/feature_store/data_sources/source_authentication.py +5 -6
- frogml/core/feature_store/data_sources/time_partition_columns.py +28 -41
- frogml/core/feature_store/execution/backfill.py +17 -28
- frogml/core/feature_store/feature_sets/transformations/__init__.py +0 -2
- frogml/core/feature_store/feature_sets/transformations/transformations.py +0 -69
- frogml/core/feature_store/validations/validation_decorators.py +72 -0
- frogml/core/inner/build_config/build_config_v1.py +4 -5
- frogml/core/inner/build_logic/phases/phase_010_fetch_model/post_fetch_validation_step.py +10 -10
- frogml/core/inner/build_logic/phases/phase_020_remote_register_frogml_build/upload_step.py +92 -43
- frogml/core/inner/const.py +2 -0
- frogml/core/inner/di_configuration/__init__.py +1 -67
- frogml/core/inner/di_configuration/account.py +4 -5
- frogml/core/inner/di_configuration/containers.py +7 -0
- frogml/core/inner/di_configuration/dependency_wiring.py +95 -0
- frogml/core/inner/tool/auth/TOKEN_ROTATION.md +51 -0
- frogml/core/inner/tool/auth/__init__.py +3 -0
- frogml/core/inner/tool/auth/auth_client.py +192 -0
- frogml/core/inner/tool/auth/token_maintainer.py +119 -0
- frogml/core/inner/tool/grpc/grpc_auth.py +22 -23
- frogml/core/inner/tool/grpc/grpc_tools.py +126 -6
- frogml/core/inner/tool/grpc/grpc_try_wrapping.py +123 -5
- frogml/core/model_loggers/artifact_logger.py +5 -4
- frogml/core/utils/proto_utils.py +0 -40
- frogml/feature_store/_common/artifact_utils.py +10 -8
- frogml/feature_store/_common/packaging.py +40 -22
- frogml/feature_store/_common/source_code_spec_factory.py +59 -9
- frogml/feature_store/data_sources/__init__.py +2 -0
- frogml/feature_store/data_sources/base.py +20 -21
- frogml/feature_store/data_sources/batch/_batch.py +0 -3
- frogml/feature_store/data_sources/batch/_jdbc.py +6 -7
- frogml/feature_store/data_sources/batch/athena.py +6 -7
- frogml/feature_store/data_sources/batch/big_query.py +8 -5
- frogml/feature_store/data_sources/batch/clickhouse.py +8 -8
- frogml/feature_store/data_sources/batch/csv.py +2 -4
- frogml/feature_store/data_sources/batch/elastic_search.py +2 -4
- frogml/feature_store/data_sources/batch/filesystem/aws.py +21 -22
- frogml/feature_store/data_sources/batch/filesystem/base_config.py +3 -3
- frogml/feature_store/data_sources/batch/filesystem/gcp.py +3 -7
- frogml/feature_store/data_sources/batch/mongodb.py +2 -4
- frogml/feature_store/data_sources/batch/mysql.py +2 -3
- frogml/feature_store/data_sources/batch/parquet.py +6 -6
- frogml/feature_store/data_sources/batch/postgres.py +2 -3
- frogml/feature_store/data_sources/batch/redshift.py +8 -6
- frogml/feature_store/data_sources/batch/snowflake.py +17 -11
- frogml/feature_store/data_sources/batch/unity_catalog.py +113 -0
- frogml/feature_store/data_sources/batch/vertica.py +10 -6
- frogml/feature_store/data_sources/streaming/_streaming.py +0 -2
- frogml/feature_store/data_sources/streaming/kafka/authentication.py +13 -19
- frogml/feature_store/data_sources/streaming/kafka/deserialization.py +22 -23
- frogml/feature_store/data_sources/streaming/kafka/kafka.py +13 -14
- frogml/feature_store/feature_sets/base_feature_set.py +1 -0
- frogml/feature_store/online/client.py +20 -4
- frogml/feature_store/validations/validator.py +11 -3
- frogml/sdk/frogml_client/builds/build.py +8 -7
- frogml/sdk/frogml_client/client.py +3 -71
- frogml/sdk/model_version/__init__.py +0 -2
- frogml/sdk/model_version/catboost/__init__.py +3 -0
- frogml/sdk/model_version/files/__init__.py +4 -0
- frogml/sdk/model_version/huggingface/__init__.py +9 -3
- frogml/sdk/model_version/model_loggers/base_model_version_manager.py +5 -0
- frogml/sdk/model_version/onnx/__init__.py +3 -0
- frogml/sdk/model_version/pytorch/__init__.py +3 -0
- frogml/sdk/model_version/scikit_learn/__init__.py +3 -0
- frogml/sdk/model_version/utils/files_tools.py +2 -3
- frogml/sdk/model_version/utils/jml/customer_client.py +47 -14
- frogml/sdk/model_version/utils/model_log_config.py +5 -0
- frogml/sdk/model_version/utils/storage.py +57 -41
- frogml/storage/artifactory/_artifactory_api.py +6 -0
- frogml/storage/authentication/login/_login_cli.py +21 -21
- frogml/storage/authentication/models/_auth_config.py +22 -1
- frogml/storage/authentication/utils/_authentication_utils.py +31 -34
- frogml/storage/constants.py +19 -0
- frogml/storage/frog_ml.py +10 -20
- frogml/storage/models/frogml_dataset_version.py +3 -3
- frogml/storage/models/frogml_model_version.py +6 -3
- frogml/storage/utils/_input_checks_utility.py +3 -1
- {frogml-1.1.62.dist-info → frogml-1.2.19.dist-info}/METADATA +39 -9
- {frogml-1.1.62.dist-info → frogml-1.2.19.dist-info}/RECORD +525 -512
- frogml_services_mock/mocks/authentication_service.py +3 -3
- frogml_services_mock/mocks/build_orchestrator_service_api.py +5 -2
- frogml_services_mock/mocks/ecosystem_service_api.py +15 -3
- frogml_services_mock/mocks/feature_store_data_sources_manager_api.py +55 -14
- frogml_services_mock/mocks/feature_store_entities_manager_api.py +31 -30
- frogml_services_mock/mocks/features_operator_v3_service.py +20 -0
- frogml_services_mock/mocks/frogml_mocks.py +1 -1
- frogml_services_mock/mocks/project_manager_service.py +31 -56
- frogml_services_mock/services_mock.py +42 -35
- frogml/core/clients/project/__init__.py +0 -0
- frogml/core/clients/project/client.py +0 -72
- frogml/core/inner/tool/auth.py +0 -84
- frogml/sdk/frogml_client/projects/__init__.py +0 -0
- frogml/sdk/frogml_client/projects/project.py +0 -56
- {frogml-1.1.62.dist-info → frogml-1.2.19.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Callable, Optional, Union
|
|
3
|
+
from urllib.parse import urljoin
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from cachetools import LRUCache, TTLCache, cached, cachedmethod
|
|
7
|
+
from frogml.core.exceptions import FrogmlLoginException
|
|
8
|
+
from frogml.core.exceptions.frogml_token_exception import FrogMLTokenException
|
|
9
|
+
from frogml.core.inner.tool.auth.token_maintainer import TokenMaintainer
|
|
10
|
+
from frogml.storage.authentication.models import AuthConfig, BearerAuth, EmptyAuth
|
|
11
|
+
from frogml.storage.authentication.utils import get_credentials
|
|
12
|
+
from frogml.storage.constants import (
|
|
13
|
+
JF_ACCESS_TOKEN_RELOAD_INTERVAL_SECONDS,
|
|
14
|
+
JF_SHORT_TOKEN_ROTATION_GENERATION_TIMEOUT_SECONDS,
|
|
15
|
+
JF_SHORT_TOKEN_ROTATION_GENERATION_TIMEOUT_SECONDS_DEFAULT,
|
|
16
|
+
JF_SHORT_TOKEN_ROTATION_GRACE_PERIOD_SECONDS,
|
|
17
|
+
JF_SHORT_TOKEN_ROTATION_GRACE_PERIOD_SECONDS_DEFAULT,
|
|
18
|
+
JF_SHORT_TOKEN_ROTATION_INTERVAL_SECONDS,
|
|
19
|
+
JF_SHORT_TOKEN_ROTATION_INTERVAL_SECONDS_DEFAULT,
|
|
20
|
+
JF_USE_SHORT_TOKEN_ROTATION,
|
|
21
|
+
JF_USE_SHORT_TOKEN_ROTATION_DEFAULT,
|
|
22
|
+
)
|
|
23
|
+
from requests import Response
|
|
24
|
+
from requests.exceptions import RequestException
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FrogMLAuthClient:
|
|
28
|
+
__MIN_TOKEN_LENGTH: int = 64
|
|
29
|
+
|
|
30
|
+
def __init__(self, auth_config: Optional[AuthConfig] = None):
|
|
31
|
+
self.__auth_config: Optional[AuthConfig] = auth_config
|
|
32
|
+
self.__token: Optional[str] = None
|
|
33
|
+
self.__tenant_id: Optional[str] = None
|
|
34
|
+
|
|
35
|
+
# Initialize instance-level caches
|
|
36
|
+
self.__token_maintainer_cache = LRUCache(maxsize=1)
|
|
37
|
+
self.__tenant_id_cache = LRUCache(maxsize=1)
|
|
38
|
+
self.__jpd_id_cache = LRUCache(maxsize=10)
|
|
39
|
+
|
|
40
|
+
self.__base_token_retriever: Callable[[], str] = (
|
|
41
|
+
self.__get_base_token_retriever()
|
|
42
|
+
)
|
|
43
|
+
self.__use_token_maintainer: bool = self.__should_use_token_maintainer()
|
|
44
|
+
|
|
45
|
+
# best-effort to prime the token maintainer (if used)
|
|
46
|
+
if self.__use_token_maintainer:
|
|
47
|
+
self.get_token()
|
|
48
|
+
|
|
49
|
+
def __should_use_token_maintainer(self) -> bool:
|
|
50
|
+
return (
|
|
51
|
+
str(
|
|
52
|
+
os.getenv(
|
|
53
|
+
JF_USE_SHORT_TOKEN_ROTATION, JF_USE_SHORT_TOKEN_ROTATION_DEFAULT
|
|
54
|
+
)
|
|
55
|
+
).upper()
|
|
56
|
+
== "TRUE"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def get_token(self) -> str:
|
|
60
|
+
base_token: str = self.__base_token_retriever()
|
|
61
|
+
|
|
62
|
+
if not self.__use_token_maintainer:
|
|
63
|
+
return base_token
|
|
64
|
+
|
|
65
|
+
return self._get_token_maintainer(base_token).get_token()
|
|
66
|
+
|
|
67
|
+
@cachedmethod(
|
|
68
|
+
cache=lambda self: self.__token_maintainer_cache,
|
|
69
|
+
)
|
|
70
|
+
def _get_token_maintainer(self, base_token: str) -> TokenMaintainer:
|
|
71
|
+
token_rotation_interval_seconds: int = int(
|
|
72
|
+
os.getenv(
|
|
73
|
+
JF_SHORT_TOKEN_ROTATION_INTERVAL_SECONDS,
|
|
74
|
+
JF_SHORT_TOKEN_ROTATION_INTERVAL_SECONDS_DEFAULT,
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
token_rotation_grace_period_seconds: int = int(
|
|
78
|
+
os.getenv(
|
|
79
|
+
JF_SHORT_TOKEN_ROTATION_GRACE_PERIOD_SECONDS,
|
|
80
|
+
JF_SHORT_TOKEN_ROTATION_GRACE_PERIOD_SECONDS_DEFAULT,
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
token_rotation_generation_timeout_seconds: int = int(
|
|
84
|
+
os.getenv(
|
|
85
|
+
JF_SHORT_TOKEN_ROTATION_GENERATION_TIMEOUT_SECONDS,
|
|
86
|
+
JF_SHORT_TOKEN_ROTATION_GENERATION_TIMEOUT_SECONDS_DEFAULT,
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
return TokenMaintainer(
|
|
91
|
+
base_token=base_token,
|
|
92
|
+
base_url=self.get_base_url(),
|
|
93
|
+
token_rotation_interval_seconds=token_rotation_interval_seconds,
|
|
94
|
+
token_rotation_grace_period_seconds=token_rotation_grace_period_seconds,
|
|
95
|
+
token_rotation_generation_timeout_seconds=token_rotation_generation_timeout_seconds,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def get_base_token(self) -> str:
|
|
99
|
+
auth: Union[EmptyAuth, BearerAuth] = self.get_auth()
|
|
100
|
+
|
|
101
|
+
if isinstance(auth, BearerAuth):
|
|
102
|
+
self.validate_token(auth.token)
|
|
103
|
+
self.__token = auth.token
|
|
104
|
+
|
|
105
|
+
else:
|
|
106
|
+
raise FrogMLTokenException(
|
|
107
|
+
message="Token not found in the authentication configurations."
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
return self.__token
|
|
111
|
+
|
|
112
|
+
@cachedmethod(lambda self: self.__tenant_id_cache)
|
|
113
|
+
def get_tenant_id(self) -> str:
|
|
114
|
+
base_url: str = self.get_base_url()
|
|
115
|
+
url: str = urljoin(base_url, "/ui/api/v1/system/auth/screen/footer")
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
response: Response = requests.get(url, timeout=15, auth=self.get_auth())
|
|
119
|
+
response.raise_for_status() # Raises an HTTPError for bad responses
|
|
120
|
+
response_data: dict = response.json()
|
|
121
|
+
|
|
122
|
+
if "serverId" in response_data:
|
|
123
|
+
self.__tenant_id = response_data["serverId"]
|
|
124
|
+
else:
|
|
125
|
+
self.__tenant_id = self.__get_jpd_id(base_url)
|
|
126
|
+
|
|
127
|
+
return self.__tenant_id
|
|
128
|
+
|
|
129
|
+
except (RequestException, ValueError) as exc:
|
|
130
|
+
raise FrogmlLoginException(
|
|
131
|
+
"Failed to authenticate with JFrog. Please check your credentials"
|
|
132
|
+
) from exc
|
|
133
|
+
|
|
134
|
+
def get_base_url(self) -> str:
|
|
135
|
+
artifactory_url, _ = get_credentials(self.__auth_config)
|
|
136
|
+
return self.__remove_artifactory_path_from_url(artifactory_url)
|
|
137
|
+
|
|
138
|
+
def get_auth(self) -> Union[EmptyAuth, BearerAuth]:
|
|
139
|
+
return get_credentials(self.__auth_config)[1]
|
|
140
|
+
|
|
141
|
+
def validate_token(self, token: Optional[str]):
|
|
142
|
+
if token is None or len(token) <= self.__MIN_TOKEN_LENGTH or token.isspace():
|
|
143
|
+
raise FrogmlLoginException(
|
|
144
|
+
"Authentication with JFrog failed: Only JWT Access Tokens are supported. "
|
|
145
|
+
"Please ensure you are using a valid JWT Access Token."
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
@cachedmethod(cache=lambda self: self.__jpd_id_cache)
|
|
149
|
+
def __get_jpd_id(self, base_url: str) -> str:
|
|
150
|
+
url: str = urljoin(base_url, "/jfconnect/api/v1/system/jpd_id")
|
|
151
|
+
response: Response = requests.get(url=url, timeout=15, auth=self.get_auth())
|
|
152
|
+
|
|
153
|
+
if response.status_code == 200:
|
|
154
|
+
return response.text
|
|
155
|
+
|
|
156
|
+
if response.status_code == 401:
|
|
157
|
+
raise FrogmlLoginException(
|
|
158
|
+
"Failed to authenticate with JFrog. Please check your credentials"
|
|
159
|
+
)
|
|
160
|
+
else:
|
|
161
|
+
raise FrogmlLoginException(
|
|
162
|
+
"Failed to authenticate with JFrog. Please check your artifactory configuration"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
def __get_base_token_retriever(self) -> Callable[[], str]:
|
|
166
|
+
if JF_ACCESS_TOKEN_RELOAD_INTERVAL_SECONDS not in os.environ:
|
|
167
|
+
# no reload interval configured, preserve the original behavior of reading each time
|
|
168
|
+
return self.get_base_token
|
|
169
|
+
|
|
170
|
+
# base token reload interval is configured, wrap the basic retrieval with a cache
|
|
171
|
+
try:
|
|
172
|
+
ttl: int = int(os.getenv(JF_ACCESS_TOKEN_RELOAD_INTERVAL_SECONDS))
|
|
173
|
+
except ValueError:
|
|
174
|
+
raise FrogmlLoginException(
|
|
175
|
+
f"Value of {JF_ACCESS_TOKEN_RELOAD_INTERVAL_SECONDS} should be an integer"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
cache: TTLCache = TTLCache(ttl=ttl, maxsize=1)
|
|
179
|
+
|
|
180
|
+
# Use a constant key since this is a nested function with no parameters
|
|
181
|
+
@cached(cache=cache)
|
|
182
|
+
def get_token() -> str:
|
|
183
|
+
return self.get_base_token()
|
|
184
|
+
|
|
185
|
+
return get_token
|
|
186
|
+
|
|
187
|
+
@staticmethod
|
|
188
|
+
def __remove_artifactory_path_from_url(artifactory_url: str) -> str:
|
|
189
|
+
# Remove '/artifactory' from the URL
|
|
190
|
+
base_url: str = artifactory_url.replace("/artifactory", "", 1)
|
|
191
|
+
# Remove trailing slash if exists
|
|
192
|
+
return base_url.rstrip("/")
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
import time
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
from urllib.parse import urljoin
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from frogml.core.exceptions import FrogmlLoginException
|
|
8
|
+
from frogml.storage.authentication.models import BearerAuth
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field, PrivateAttr
|
|
10
|
+
from requests import Response
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TokenMaintainer(BaseModel):
|
|
14
|
+
model_config = ConfigDict(frozen=True)
|
|
15
|
+
|
|
16
|
+
token_rotation_interval_seconds: int = Field(ge=0)
|
|
17
|
+
token_rotation_grace_period_seconds: int = Field(ge=0)
|
|
18
|
+
token_rotation_generation_timeout_seconds: int = Field(ge=0)
|
|
19
|
+
base_token: str
|
|
20
|
+
base_url: str
|
|
21
|
+
__token_scope: str = ""
|
|
22
|
+
__curr_token: Optional[str] = None
|
|
23
|
+
__curr_token_cache_expiration: float
|
|
24
|
+
__lock: threading.RLock = PrivateAttr(default_factory=threading.RLock)
|
|
25
|
+
__refreshing: bool = False
|
|
26
|
+
|
|
27
|
+
def model_post_init(self, context: Any, /) -> None:
|
|
28
|
+
self.__curr_token_cache_expiration = (
|
|
29
|
+
-2
|
|
30
|
+
* (
|
|
31
|
+
self.token_rotation_interval_seconds
|
|
32
|
+
+ self.token_rotation_grace_period_seconds
|
|
33
|
+
)
|
|
34
|
+
- 1.0
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
self.__extract_token_scope()
|
|
38
|
+
|
|
39
|
+
def get_token(self) -> str:
|
|
40
|
+
curr_time = time.monotonic()
|
|
41
|
+
|
|
42
|
+
if curr_time > self.__curr_token_cache_expiration:
|
|
43
|
+
# need to refresh (either because it's about to expire it was never loaded)
|
|
44
|
+
# note that this does not necessarily mean the current value can't be used
|
|
45
|
+
self.trigger_background_load()
|
|
46
|
+
|
|
47
|
+
if (
|
|
48
|
+
curr_time
|
|
49
|
+
> self.__curr_token_cache_expiration
|
|
50
|
+
+ self.token_rotation_grace_period_seconds
|
|
51
|
+
):
|
|
52
|
+
# the current value is either no longer valid (passed its grace) or was never loaded, return the base token
|
|
53
|
+
return self.base_token
|
|
54
|
+
|
|
55
|
+
return self.__curr_token
|
|
56
|
+
|
|
57
|
+
def __refresh(self):
|
|
58
|
+
next_curr_value_expiration: float = (
|
|
59
|
+
time.monotonic() + self.token_rotation_interval_seconds
|
|
60
|
+
)
|
|
61
|
+
try:
|
|
62
|
+
token = self.__generate_token()
|
|
63
|
+
with self.__lock:
|
|
64
|
+
self.__curr_token = token
|
|
65
|
+
self.__curr_token_cache_expiration = next_curr_value_expiration
|
|
66
|
+
finally:
|
|
67
|
+
with self.__lock:
|
|
68
|
+
self.__refreshing = False
|
|
69
|
+
|
|
70
|
+
def __generate_token(self) -> str:
|
|
71
|
+
try:
|
|
72
|
+
url: str = urljoin(self.base_url, "/access/api/v1/tokens")
|
|
73
|
+
token_life_duration: int = int(
|
|
74
|
+
self.token_rotation_interval_seconds
|
|
75
|
+
+ self.token_rotation_grace_period_seconds
|
|
76
|
+
)
|
|
77
|
+
resp: Response = requests.post(
|
|
78
|
+
url,
|
|
79
|
+
data={"expires_in": token_life_duration, "scope": self.__token_scope},
|
|
80
|
+
auth=BearerAuth(self.base_token),
|
|
81
|
+
timeout=self.token_rotation_generation_timeout_seconds,
|
|
82
|
+
)
|
|
83
|
+
resp.raise_for_status()
|
|
84
|
+
return resp.json()["access_token"]
|
|
85
|
+
except Exception as e:
|
|
86
|
+
raise FrogmlLoginException("Failed to generate token: {}".format(e)) from e
|
|
87
|
+
|
|
88
|
+
def trigger_background_load(self):
|
|
89
|
+
with self.__lock:
|
|
90
|
+
if self.__refreshing:
|
|
91
|
+
# another refresh is ongoing, do not disturb it
|
|
92
|
+
return
|
|
93
|
+
# first start a thread for refreshing the token,
|
|
94
|
+
# then mark self as refreshing (to prevent a phantom refresh)
|
|
95
|
+
threading.Thread(target=self.__refresh, daemon=True).start()
|
|
96
|
+
self.__refreshing = True
|
|
97
|
+
|
|
98
|
+
def __extract_token_scope(self):
|
|
99
|
+
# parsing the base token to get its scope (which is used for generating new ones)
|
|
100
|
+
# note that here it does not matter whether the token is valid or not, we care
|
|
101
|
+
# only about the scope
|
|
102
|
+
try:
|
|
103
|
+
import jwt
|
|
104
|
+
|
|
105
|
+
parsed_token = jwt.decode(
|
|
106
|
+
self.base_token,
|
|
107
|
+
options={
|
|
108
|
+
"verify_signature": False
|
|
109
|
+
}, # NOSONAR(S5659) we only parse the token, no authentication happens here
|
|
110
|
+
)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
raise FrogmlLoginException(
|
|
113
|
+
"Failed to decode JWT token: {}".format(e)
|
|
114
|
+
) from e
|
|
115
|
+
|
|
116
|
+
if "scp" not in parsed_token:
|
|
117
|
+
raise FrogmlLoginException("Invalid token - missing scp claim")
|
|
118
|
+
|
|
119
|
+
self.__token_scope = parsed_token["scp"]
|
|
@@ -1,42 +1,41 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING, Callable, Optional, Tuple
|
|
2
|
-
|
|
3
1
|
import grpc
|
|
2
|
+
from typing_extensions import Self
|
|
4
3
|
|
|
5
4
|
from frogml.core.inner.const import FrogMLConstants
|
|
6
|
-
|
|
7
|
-
if TYPE_CHECKING:
|
|
8
|
-
from frogml.core.inner.tool.auth import FrogMLAuthClient
|
|
9
|
-
|
|
10
|
-
_SIGNATURE_HEADER_KEY = "authorization"
|
|
5
|
+
from frogml.core.inner.tool.auth import FrogMLAuthClient
|
|
11
6
|
|
|
12
7
|
|
|
13
8
|
class FrogMLAuthMetadataPlugin(grpc.AuthMetadataPlugin):
|
|
14
|
-
def __init__(self):
|
|
15
|
-
self.
|
|
9
|
+
def __init__(self: Self, should_pass_jf_tenant_id: bool = True):
|
|
10
|
+
self.__auth_client = FrogMLAuthClient()
|
|
11
|
+
self.__should_pass_jf_tenant_id: bool = should_pass_jf_tenant_id
|
|
16
12
|
|
|
17
13
|
def __call__(
|
|
18
14
|
self,
|
|
19
15
|
context: grpc.AuthMetadataContext,
|
|
20
|
-
callback:
|
|
16
|
+
callback: grpc.AuthMetadataPluginCallback,
|
|
21
17
|
):
|
|
22
18
|
"""Implements authentication by passing metadata to a callback.
|
|
23
19
|
|
|
24
20
|
Args:
|
|
25
21
|
context: An AuthMetadataContext providing information on the RPC that
|
|
26
22
|
the plugin is being called to authenticate.
|
|
27
|
-
callback: A callback that accepts a
|
|
23
|
+
callback: A callback that accepts a sequence of metadata key/value pairs and a None
|
|
28
24
|
parameter.
|
|
29
25
|
"""
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
)
|
|
26
|
+
token: str = self.__auth_client.get_token()
|
|
27
|
+
metadata: list[tuple[str, str]] = [
|
|
28
|
+
(FrogMLConstants.SIGNATURE_HEADER_KEY, f"Bearer {token}")
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
if self.__should_pass_jf_tenant_id:
|
|
32
|
+
jfrog_tenant_id: str = self.__auth_client.get_tenant_id()
|
|
33
|
+
metadata.append(
|
|
34
|
+
(FrogMLConstants.JFROG_TENANT_HEADER_KEY.lower(), jfrog_tenant_id)
|
|
35
|
+
)
|
|
36
|
+
|
|
42
37
|
callback(metadata, None)
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def should_pass_jf_tenant_id(self: Self) -> bool:
|
|
41
|
+
return self.__should_pass_jf_tenant_id
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import re
|
|
2
3
|
import time
|
|
3
4
|
from abc import ABC, abstractmethod
|
|
4
5
|
from random import randint
|
|
5
6
|
from typing import Callable, Optional, Tuple
|
|
7
|
+
from urllib.parse import urlparse, ParseResult
|
|
6
8
|
|
|
7
9
|
import grpc
|
|
8
10
|
|
|
9
|
-
from frogml.core.exceptions import FrogmlException
|
|
11
|
+
from frogml.core.exceptions import FrogmlGrpcAddressException, FrogmlException
|
|
10
12
|
from frogml.core.inner.tool.grpc.grpc_auth import FrogMLAuthMetadataPlugin
|
|
11
13
|
|
|
12
14
|
logger = logging.getLogger()
|
|
15
|
+
HOSTNAME_REGEX: str = r"^(?!-)(?:[A-Za-z0-9-]{1,63}\.)*[A-Za-z0-9-]{1,63}(?<!-)$"
|
|
13
16
|
|
|
14
17
|
|
|
15
18
|
def create_grpc_channel(
|
|
@@ -23,6 +26,7 @@ def create_grpc_channel(
|
|
|
23
26
|
max_attempts=4,
|
|
24
27
|
status_for_retry=(grpc.StatusCode.UNAVAILABLE,),
|
|
25
28
|
attempt=0,
|
|
29
|
+
should_pass_jf_tenant_id: bool = True,
|
|
26
30
|
) -> grpc.Channel:
|
|
27
31
|
"""
|
|
28
32
|
Create a gRPC channel
|
|
@@ -36,16 +40,17 @@ def create_grpc_channel(
|
|
|
36
40
|
options: An optional list of key-value pairs (channel_arguments in gRPC Core runtime) to configure the channel.
|
|
37
41
|
backoff_options: dictionary - init_backoff_ms: default 50, max_backoff_ms: default 500, multiplier: default 2
|
|
38
42
|
max_attempts: max number of retry attempts
|
|
39
|
-
attempt: current retry attempts
|
|
40
43
|
status_for_retry: grpc statuses to retry upon
|
|
44
|
+
attempt: current retry attempts
|
|
45
|
+
should_pass_jf_tenant_id: Whether to pass JFrog tenant ID in metadata (if auth is enabled)
|
|
41
46
|
Returns: Returns a grpc.Channel
|
|
42
47
|
"""
|
|
43
48
|
if backoff_options is None:
|
|
44
49
|
backoff_options = {}
|
|
45
50
|
|
|
46
51
|
if not url:
|
|
47
|
-
raise
|
|
48
|
-
"Unable to create gRPC channel. URL has not been defined."
|
|
52
|
+
raise FrogmlGrpcAddressException(
|
|
53
|
+
"Unable to create gRPC channel. URL has not been defined.", url
|
|
49
54
|
)
|
|
50
55
|
|
|
51
56
|
if enable_ssl or url.endswith(":443"):
|
|
@@ -53,7 +58,9 @@ def create_grpc_channel(
|
|
|
53
58
|
|
|
54
59
|
if enable_auth:
|
|
55
60
|
if auth_metadata_plugin is None:
|
|
56
|
-
auth_metadata_plugin = FrogMLAuthMetadataPlugin(
|
|
61
|
+
auth_metadata_plugin = FrogMLAuthMetadataPlugin(
|
|
62
|
+
should_pass_jf_tenant_id
|
|
63
|
+
)
|
|
57
64
|
|
|
58
65
|
credentials = grpc.composite_channel_credentials(
|
|
59
66
|
credentials, grpc.metadata_call_credentials(auth_metadata_plugin)
|
|
@@ -99,7 +106,7 @@ def create_grpc_channel(
|
|
|
99
106
|
return intercept_channel
|
|
100
107
|
except grpc.FutureTimeoutError as e:
|
|
101
108
|
raise FrogmlException(
|
|
102
|
-
f"Connection timed out while attempting to connect to {url}, with: {repr(e)}"
|
|
109
|
+
f"Connection timed out while attempting to connect to {url}, with: {repr(e)}",
|
|
103
110
|
) from e
|
|
104
111
|
|
|
105
112
|
|
|
@@ -114,6 +121,7 @@ def create_grpc_channel_or_none(
|
|
|
114
121
|
max_attempts=2,
|
|
115
122
|
status_for_retry=(grpc.StatusCode.UNAVAILABLE,),
|
|
116
123
|
attempt=0,
|
|
124
|
+
should_pass_jf_tenant_id: bool = True,
|
|
117
125
|
) -> Callable[[Optional[str], Optional[bool]], Optional[grpc.Channel]]:
|
|
118
126
|
final_backoff_options = backoff_options if backoff_options else {}
|
|
119
127
|
|
|
@@ -132,6 +140,7 @@ def create_grpc_channel_or_none(
|
|
|
132
140
|
max_attempts,
|
|
133
141
|
status_for_retry,
|
|
134
142
|
attempt,
|
|
143
|
+
should_pass_jf_tenant_id,
|
|
135
144
|
)
|
|
136
145
|
except Exception as e:
|
|
137
146
|
logger.debug(f"create_grpc_channel error: {repr(e)}")
|
|
@@ -140,6 +149,117 @@ def create_grpc_channel_or_none(
|
|
|
140
149
|
return deferred_channel
|
|
141
150
|
|
|
142
151
|
|
|
152
|
+
def validate_grpc_address(
|
|
153
|
+
grpc_address: str,
|
|
154
|
+
is_port_specification_allowed: bool = False,
|
|
155
|
+
is_url_scheme_allowed: bool = False,
|
|
156
|
+
):
|
|
157
|
+
"""
|
|
158
|
+
Validate gRPC address format
|
|
159
|
+
Args:
|
|
160
|
+
grpc_address (str): gRPC address to validate
|
|
161
|
+
is_port_specification_allowed (bool): Whether to allow port specification in the address
|
|
162
|
+
is_url_scheme_allowed (bool): Whether to allow URL scheme in the address
|
|
163
|
+
Raises:
|
|
164
|
+
FrogmlGrpcAddressException: If the gRPC address is invalid
|
|
165
|
+
"""
|
|
166
|
+
parsed_grpc_address: ParseResult = parse_address(grpc_address)
|
|
167
|
+
hostname: str = get_hostname_from_address(parsed_grpc_address)
|
|
168
|
+
validate_paths_are_not_included_in_address(parsed_grpc_address)
|
|
169
|
+
|
|
170
|
+
if not is_url_scheme_allowed:
|
|
171
|
+
__validate_url_scheme_not_included_in_address(parsed_grpc_address)
|
|
172
|
+
|
|
173
|
+
if not is_port_specification_allowed:
|
|
174
|
+
__validate_port_not_included_in_address(parsed_grpc_address)
|
|
175
|
+
|
|
176
|
+
if not is_valid_hostname(hostname):
|
|
177
|
+
raise FrogmlGrpcAddressException(
|
|
178
|
+
"gRPC address must be a simple hostname or fully qualified domain name.",
|
|
179
|
+
parsed_grpc_address,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def validate_paths_are_not_included_in_address(
|
|
184
|
+
parsed_grpc_address: ParseResult,
|
|
185
|
+
) -> None:
|
|
186
|
+
has_invalid_path: bool = (
|
|
187
|
+
parsed_grpc_address.path not in {"", "/"}
|
|
188
|
+
or parsed_grpc_address.query
|
|
189
|
+
or parsed_grpc_address.fragment
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
if has_invalid_path:
|
|
193
|
+
raise FrogmlGrpcAddressException(
|
|
194
|
+
"gRPC address must not contain paths, queries, or fragments.",
|
|
195
|
+
parsed_grpc_address,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def get_hostname_from_address(parsed_grpc_address: ParseResult) -> str:
|
|
200
|
+
hostname: Optional[str] = parsed_grpc_address.hostname
|
|
201
|
+
if not hostname:
|
|
202
|
+
raise FrogmlGrpcAddressException(
|
|
203
|
+
"gRPC address must contain a valid hostname.", parsed_grpc_address
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
return hostname
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def __validate_url_scheme_not_included_in_address(
|
|
210
|
+
parsed_grpc_address: ParseResult,
|
|
211
|
+
) -> None:
|
|
212
|
+
if parsed_grpc_address.scheme:
|
|
213
|
+
raise FrogmlGrpcAddressException(
|
|
214
|
+
"URL scheme is not allowed in the gRPC address.", parsed_grpc_address
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def __validate_port_not_included_in_address(parsed_grpc_address: ParseResult):
|
|
219
|
+
try:
|
|
220
|
+
port: Optional[int] = parsed_grpc_address.port
|
|
221
|
+
except ValueError as exc:
|
|
222
|
+
raise FrogmlGrpcAddressException(
|
|
223
|
+
"Invalid port specification in the gRPC address.", parsed_grpc_address
|
|
224
|
+
) from exc
|
|
225
|
+
|
|
226
|
+
if port:
|
|
227
|
+
raise FrogmlGrpcAddressException(
|
|
228
|
+
"Port specification is not allowed in the gRPC address.",
|
|
229
|
+
parsed_grpc_address,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def parse_address(grpc_address: str) -> ParseResult:
|
|
234
|
+
if not grpc_address or not grpc_address.strip():
|
|
235
|
+
raise FrogmlGrpcAddressException(
|
|
236
|
+
"gRPC address must not be empty or whitespace.", grpc_address
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
trimmed_address: str = grpc_address.strip()
|
|
240
|
+
parsed_address: ParseResult = urlparse(
|
|
241
|
+
trimmed_address if "://" in trimmed_address else f"//{trimmed_address}"
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
return parsed_address
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def is_valid_hostname(hostname: str) -> bool:
|
|
248
|
+
"""
|
|
249
|
+
Validate that the supplied hostname conforms to RFC-style label rules:
|
|
250
|
+
anchored pattern enforces full-string validation, negative lookahead/lookbehind block
|
|
251
|
+
leading or trailing hyphens per label, and each dot-separated label must be 1-63
|
|
252
|
+
alphanumeric/hyphen characters.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
hostname (str): The hostname to validate.
|
|
256
|
+
Returns:
|
|
257
|
+
bool: True if the hostname is valid, False otherwise.
|
|
258
|
+
"""
|
|
259
|
+
hostname_pattern: re.Pattern = re.compile(HOSTNAME_REGEX)
|
|
260
|
+
return bool(hostname_pattern.fullmatch(hostname))
|
|
261
|
+
|
|
262
|
+
|
|
143
263
|
class SleepingPolicy(ABC):
|
|
144
264
|
@abstractmethod
|
|
145
265
|
def sleep(self, try_i: int):
|