eryph-compute 0.1.1
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +47 -0
- data/LICENSE +21 -0
- data/README.md +144 -0
- data/eryph-clientruntime.gemspec +42 -0
- data/eryph-compute.gemspec +44 -0
- data/lib/eryph/clientruntime/client_credentials_lookup.rb +295 -0
- data/lib/eryph/clientruntime/config_store.rb +206 -0
- data/lib/eryph/clientruntime/config_stores_reader.rb +211 -0
- data/lib/eryph/clientruntime/endpoint_lookup.rb +226 -0
- data/lib/eryph/clientruntime/environment.rb +440 -0
- data/lib/eryph/clientruntime/local_identity_provider_info.rb +153 -0
- data/lib/eryph/clientruntime/token_provider.rb +275 -0
- data/lib/eryph/clientruntime/version.rb +6 -0
- data/lib/eryph/clientruntime.rb +79 -0
- data/lib/eryph/compute/client.rb +442 -0
- data/lib/eryph/compute/generated/Gemfile +9 -0
- data/lib/eryph/compute/generated/README.md +206 -0
- data/lib/eryph/compute/generated/Rakefile +10 -0
- data/lib/eryph/compute/generated/compute_client.gemspec +41 -0
- data/lib/eryph/compute/generated/docs/ApiVersion.md +20 -0
- data/lib/eryph/compute/generated/docs/ApiVersionResponse.md +18 -0
- data/lib/eryph/compute/generated/docs/Catlet.md +32 -0
- data/lib/eryph/compute/generated/docs/CatletConfigOperationResult.md +18 -0
- data/lib/eryph/compute/generated/docs/CatletConfigValidationResult.md +20 -0
- data/lib/eryph/compute/generated/docs/CatletConfiguration.md +18 -0
- data/lib/eryph/compute/generated/docs/CatletDrive.md +20 -0
- data/lib/eryph/compute/generated/docs/CatletDriveType.md +15 -0
- data/lib/eryph/compute/generated/docs/CatletList.md +18 -0
- data/lib/eryph/compute/generated/docs/CatletNetwork.md +30 -0
- data/lib/eryph/compute/generated/docs/CatletNetworkAdapter.md +20 -0
- data/lib/eryph/compute/generated/docs/CatletStatus.md +15 -0
- data/lib/eryph/compute/generated/docs/CatletStopMode.md +15 -0
- data/lib/eryph/compute/generated/docs/CatletsApi.md +863 -0
- data/lib/eryph/compute/generated/docs/DiskStatus.md +15 -0
- data/lib/eryph/compute/generated/docs/ExpandCatletConfigRequestBody.md +22 -0
- data/lib/eryph/compute/generated/docs/ExpandNewCatletConfigRequest.md +22 -0
- data/lib/eryph/compute/generated/docs/FloatingNetworkPort.md +26 -0
- data/lib/eryph/compute/generated/docs/Gene.md +30 -0
- data/lib/eryph/compute/generated/docs/GeneList.md +18 -0
- data/lib/eryph/compute/generated/docs/GeneType.md +15 -0
- data/lib/eryph/compute/generated/docs/GeneWithUsage.md +34 -0
- data/lib/eryph/compute/generated/docs/GenesApi.md +281 -0
- data/lib/eryph/compute/generated/docs/NewCatletRequest.md +20 -0
- data/lib/eryph/compute/generated/docs/NewProjectMemberBody.md +22 -0
- data/lib/eryph/compute/generated/docs/NewProjectRequest.md +20 -0
- data/lib/eryph/compute/generated/docs/NewVirtualDiskRequest.md +30 -0
- data/lib/eryph/compute/generated/docs/Operation.md +32 -0
- data/lib/eryph/compute/generated/docs/OperationList.md +18 -0
- data/lib/eryph/compute/generated/docs/OperationLogEntry.md +24 -0
- data/lib/eryph/compute/generated/docs/OperationResource.md +22 -0
- data/lib/eryph/compute/generated/docs/OperationResult.md +18 -0
- data/lib/eryph/compute/generated/docs/OperationStatus.md +15 -0
- data/lib/eryph/compute/generated/docs/OperationTask.md +30 -0
- data/lib/eryph/compute/generated/docs/OperationTaskReference.md +22 -0
- data/lib/eryph/compute/generated/docs/OperationTaskStatus.md +15 -0
- data/lib/eryph/compute/generated/docs/OperationsApi.md +157 -0
- data/lib/eryph/compute/generated/docs/PopulateCatletConfigVariablesRequest.md +20 -0
- data/lib/eryph/compute/generated/docs/ProblemDetails.md +26 -0
- data/lib/eryph/compute/generated/docs/Project.md +22 -0
- data/lib/eryph/compute/generated/docs/ProjectList.md +18 -0
- data/lib/eryph/compute/generated/docs/ProjectMemberRole.md +26 -0
- data/lib/eryph/compute/generated/docs/ProjectMemberRoleList.md +18 -0
- data/lib/eryph/compute/generated/docs/ProjectMembersApi.md +293 -0
- data/lib/eryph/compute/generated/docs/ProjectsApi.md +286 -0
- data/lib/eryph/compute/generated/docs/ResourceType.md +15 -0
- data/lib/eryph/compute/generated/docs/StopCatletRequestBody.md +18 -0
- data/lib/eryph/compute/generated/docs/TaskReferenceType.md +15 -0
- data/lib/eryph/compute/generated/docs/UpdateCatletRequestBody.md +20 -0
- data/lib/eryph/compute/generated/docs/UpdateProjectNetworksRequestBody.md +20 -0
- data/lib/eryph/compute/generated/docs/ValidateConfigRequest.md +18 -0
- data/lib/eryph/compute/generated/docs/ValidationIssue.md +20 -0
- data/lib/eryph/compute/generated/docs/VersionApi.md +69 -0
- data/lib/eryph/compute/generated/docs/VirtualDisk.md +42 -0
- data/lib/eryph/compute/generated/docs/VirtualDiskAttachedCatlet.md +20 -0
- data/lib/eryph/compute/generated/docs/VirtualDiskGeneInfo.md +22 -0
- data/lib/eryph/compute/generated/docs/VirtualDiskList.md +18 -0
- data/lib/eryph/compute/generated/docs/VirtualDisksApi.md +291 -0
- data/lib/eryph/compute/generated/docs/VirtualNetwork.md +28 -0
- data/lib/eryph/compute/generated/docs/VirtualNetworkConfiguration.md +18 -0
- data/lib/eryph/compute/generated/docs/VirtualNetworkList.md +18 -0
- data/lib/eryph/compute/generated/docs/VirtualNetworksApi.md +291 -0
- data/lib/eryph/compute/generated/git_push.sh +57 -0
- data/lib/eryph/compute/generated/lib/compute_client/api/catlets_api.rb +812 -0
- data/lib/eryph/compute/generated/lib/compute_client/api/genes_api.rb +262 -0
- data/lib/eryph/compute/generated/lib/compute_client/api/operations_api.rb +154 -0
- data/lib/eryph/compute/generated/lib/compute_client/api/project_members_api.rb +297 -0
- data/lib/eryph/compute/generated/lib/compute_client/api/projects_api.rb +269 -0
- data/lib/eryph/compute/generated/lib/compute_client/api/version_api.rb +79 -0
- data/lib/eryph/compute/generated/lib/compute_client/api/virtual_disks_api.rb +272 -0
- data/lib/eryph/compute/generated/lib/compute_client/api/virtual_networks_api.rb +282 -0
- data/lib/eryph/compute/generated/lib/compute_client/api_client.rb +437 -0
- data/lib/eryph/compute/generated/lib/compute_client/api_error.rb +58 -0
- data/lib/eryph/compute/generated/lib/compute_client/configuration.rb +392 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/api_version.rb +263 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/api_version_response.rb +237 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet.rb +400 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet_config_operation_result.rb +234 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet_config_validation_result.rb +251 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet_configuration.rb +223 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet_drive.rb +270 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet_drive_type.rb +43 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet_list.rb +239 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet_network.rb +318 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet_network_adapter.rb +247 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet_status.rb +43 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/catlet_stop_mode.rb +41 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/disk_status.rb +40 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/expand_catlet_config_request_body.rb +243 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/expand_new_catlet_config_request.rb +243 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/floating_network_port.rb +313 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/gene.rb +415 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/gene_list.rb +239 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/gene_type.rb +41 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/gene_with_usage.rb +439 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/new_catlet_request.rb +233 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/new_project_member_body.rb +273 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/new_project_request.rb +247 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/new_virtual_disk_request.rb +345 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/operation.rb +352 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/operation_list.rb +239 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/operation_log_entry.rb +299 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/operation_resource.rb +311 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/operation_result.rb +242 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/operation_status.rb +42 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/operation_task.rb +366 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/operation_task_reference.rb +311 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/operation_task_status.rb +42 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/populate_catlet_config_variables_request.rb +233 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/problem_details.rb +261 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/project.rb +289 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/project_list.rb +239 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/project_member_role.rb +341 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/project_member_role_list.rb +239 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/resource_type.rb +42 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/stop_catlet_request_body.rb +259 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/task_reference_type.rb +40 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/update_catlet_request_body.rb +233 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/update_project_networks_request_body.rb +233 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/validate_config_request.rb +223 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/validation_issue.rb +249 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/virtual_disk.rb +479 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/virtual_disk_attached_catlet.rb +285 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/virtual_disk_gene_info.rb +289 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/virtual_disk_list.rb +239 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/virtual_network.rb +351 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/virtual_network_configuration.rb +223 -0
- data/lib/eryph/compute/generated/lib/compute_client/models/virtual_network_list.rb +239 -0
- data/lib/eryph/compute/generated/lib/compute_client/version.rb +15 -0
- data/lib/eryph/compute/generated/lib/compute_client.rb +101 -0
- data/lib/eryph/compute/generated/spec/api/catlets_api_spec.rb +182 -0
- data/lib/eryph/compute/generated/spec/api/genes_api_spec.rb +81 -0
- data/lib/eryph/compute/generated/spec/api/operations_api_spec.rb +62 -0
- data/lib/eryph/compute/generated/spec/api/project_members_api_spec.rb +86 -0
- data/lib/eryph/compute/generated/spec/api/projects_api_spec.rb +82 -0
- data/lib/eryph/compute/generated/spec/api/version_api_spec.rb +46 -0
- data/lib/eryph/compute/generated/spec/api/virtual_disks_api_spec.rb +83 -0
- data/lib/eryph/compute/generated/spec/api/virtual_networks_api_spec.rb +84 -0
- data/lib/eryph/compute/generated/spec/models/api_version_response_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/api_version_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/catlet_config_operation_result_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/catlet_config_validation_result_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/catlet_configuration_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/catlet_drive_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/catlet_drive_type_spec.rb +30 -0
- data/lib/eryph/compute/generated/spec/models/catlet_list_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/catlet_network_adapter_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/catlet_network_spec.rb +72 -0
- data/lib/eryph/compute/generated/spec/models/catlet_spec.rb +78 -0
- data/lib/eryph/compute/generated/spec/models/catlet_status_spec.rb +30 -0
- data/lib/eryph/compute/generated/spec/models/catlet_stop_mode_spec.rb +30 -0
- data/lib/eryph/compute/generated/spec/models/disk_status_spec.rb +30 -0
- data/lib/eryph/compute/generated/spec/models/expand_catlet_config_request_body_spec.rb +48 -0
- data/lib/eryph/compute/generated/spec/models/expand_new_catlet_config_request_spec.rb +48 -0
- data/lib/eryph/compute/generated/spec/models/floating_network_port_spec.rb +60 -0
- data/lib/eryph/compute/generated/spec/models/gene_list_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/gene_spec.rb +72 -0
- data/lib/eryph/compute/generated/spec/models/gene_type_spec.rb +30 -0
- data/lib/eryph/compute/generated/spec/models/gene_with_usage_spec.rb +84 -0
- data/lib/eryph/compute/generated/spec/models/new_catlet_request_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/new_project_member_body_spec.rb +48 -0
- data/lib/eryph/compute/generated/spec/models/new_project_request_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/new_virtual_disk_request_spec.rb +72 -0
- data/lib/eryph/compute/generated/spec/models/operation_list_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/operation_log_entry_spec.rb +54 -0
- data/lib/eryph/compute/generated/spec/models/operation_resource_spec.rb +48 -0
- data/lib/eryph/compute/generated/spec/models/operation_result_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/operation_spec.rb +78 -0
- data/lib/eryph/compute/generated/spec/models/operation_status_spec.rb +30 -0
- data/lib/eryph/compute/generated/spec/models/operation_task_reference_spec.rb +48 -0
- data/lib/eryph/compute/generated/spec/models/operation_task_spec.rb +72 -0
- data/lib/eryph/compute/generated/spec/models/operation_task_status_spec.rb +30 -0
- data/lib/eryph/compute/generated/spec/models/populate_catlet_config_variables_request_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/problem_details_spec.rb +60 -0
- data/lib/eryph/compute/generated/spec/models/project_list_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/project_member_role_list_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/project_member_role_spec.rb +60 -0
- data/lib/eryph/compute/generated/spec/models/project_spec.rb +48 -0
- data/lib/eryph/compute/generated/spec/models/resource_type_spec.rb +30 -0
- data/lib/eryph/compute/generated/spec/models/stop_catlet_request_body_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/task_reference_type_spec.rb +30 -0
- data/lib/eryph/compute/generated/spec/models/update_catlet_request_body_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/update_project_networks_request_body_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/validate_config_request_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/validation_issue_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/virtual_disk_attached_catlet_spec.rb +42 -0
- data/lib/eryph/compute/generated/spec/models/virtual_disk_gene_info_spec.rb +48 -0
- data/lib/eryph/compute/generated/spec/models/virtual_disk_list_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/virtual_disk_spec.rb +108 -0
- data/lib/eryph/compute/generated/spec/models/virtual_network_configuration_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/virtual_network_list_spec.rb +36 -0
- data/lib/eryph/compute/generated/spec/models/virtual_network_spec.rb +66 -0
- data/lib/eryph/compute/generated/spec/spec_helper.rb +111 -0
- data/lib/eryph/compute/generated.rb +137 -0
- data/lib/eryph/compute/operation_result.rb +255 -0
- data/lib/eryph/compute/operation_tracker.rb +247 -0
- data/lib/eryph/compute/problem_details_error.rb +139 -0
- data/lib/eryph/compute/version.rb +6 -0
- data/lib/eryph/compute.rb +40 -0
- data/lib/eryph/version.rb +4 -0
- data/lib/eryph.rb +68 -0
- metadata +329 -0
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Eryph
|
4
|
+
module Compute
|
5
|
+
# Advanced operation tracker with fluent callback registration
|
6
|
+
# Provides more control over operation tracking than the basic wait_for_operation
|
7
|
+
class OperationTracker
|
8
|
+
attr_reader :operation_id, :client
|
9
|
+
|
10
|
+
def initialize(client, operation_id)
|
11
|
+
@client = client
|
12
|
+
@operation_id = operation_id
|
13
|
+
@processed_log_ids = Set.new
|
14
|
+
@processed_task_ids = Set.new
|
15
|
+
@processed_resource_ids = Set.new
|
16
|
+
@last_timestamp = Time.parse('2018-01-01')
|
17
|
+
@callbacks = {}
|
18
|
+
@raw_json = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# Register callback for new log entries
|
22
|
+
# @yield [log_entry] callback for each new log entry
|
23
|
+
# @return [self] for method chaining
|
24
|
+
def on_log_entry(&block)
|
25
|
+
@callbacks[:log_entry] = block
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Register callback for new tasks
|
30
|
+
# @yield [task] callback for each new task discovered
|
31
|
+
# @return [self] for method chaining
|
32
|
+
def on_task_new(&block)
|
33
|
+
@callbacks[:task_new] = block
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
# Register callback for task updates (status/progress changes)
|
38
|
+
# @yield [task] callback for each task update
|
39
|
+
# @return [self] for method chaining
|
40
|
+
def on_task_update(&block)
|
41
|
+
@callbacks[:task_update] = block
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
# Register callback for new resources
|
46
|
+
# @yield [resource] callback for each new resource discovered
|
47
|
+
# @return [self] for method chaining
|
48
|
+
def on_resource_new(&block)
|
49
|
+
@callbacks[:resource_new] = block
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
# Register callback for status changes
|
54
|
+
# @yield [operation] callback for each status update
|
55
|
+
# @return [self] for method chaining
|
56
|
+
def on_status_change(&block)
|
57
|
+
@callbacks[:status_change] = block
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
# Single poll to check current state without blocking
|
62
|
+
# @return [Operation] the current operation state
|
63
|
+
def poll
|
64
|
+
# Get raw JSON using debug_return_type (same approach as Client)
|
65
|
+
begin
|
66
|
+
@raw_json = @client.operations.operations_get(
|
67
|
+
@operation_id,
|
68
|
+
expand: 'logs,tasks,resources',
|
69
|
+
log_time_stamp: @last_timestamp,
|
70
|
+
debug_return_type: 'String'
|
71
|
+
)
|
72
|
+
@client.logger.debug "Raw JSON captured: #{@raw_json ? 'YES' : 'NO'}"
|
73
|
+
rescue StandardError => e
|
74
|
+
@client.logger.debug "Failed to capture raw JSON: #{e.message}"
|
75
|
+
end
|
76
|
+
|
77
|
+
# Get the normal deserialized operation
|
78
|
+
operation = @client.operations.operations_get(
|
79
|
+
@operation_id,
|
80
|
+
expand: 'logs,tasks,resources',
|
81
|
+
log_time_stamp: @last_timestamp
|
82
|
+
)
|
83
|
+
|
84
|
+
process_updates(operation)
|
85
|
+
operation
|
86
|
+
end
|
87
|
+
|
88
|
+
# Track operation until completion with polling
|
89
|
+
# @param timeout [Integer] timeout in seconds (default: 300)
|
90
|
+
# @param poll_interval [Integer] polling interval in seconds (default: 5)
|
91
|
+
# @return [OperationResult] the completed operation result
|
92
|
+
# @raise [Timeout::Error] if the operation times out
|
93
|
+
def track_to_completion(timeout: 300, poll_interval: 5)
|
94
|
+
start_time = Time.now
|
95
|
+
|
96
|
+
@client.logger.info "Tracking operation #{@operation_id} to completion (timeout: #{timeout}s)..."
|
97
|
+
|
98
|
+
loop do
|
99
|
+
operation = poll
|
100
|
+
|
101
|
+
if operation.status == 'Completed'
|
102
|
+
@client.logger.info "Operation #{@operation_id} completed successfully!"
|
103
|
+
@client.logger.info "Raw JSON available: #{@raw_json ? 'YES' : 'NO'}"
|
104
|
+
@client.logger.info "Raw JSON length: #{@raw_json ? @raw_json.length : 'N/A'}"
|
105
|
+
return OperationResult.new(operation, @client, @raw_json)
|
106
|
+
elsif operation.status == 'Failed'
|
107
|
+
@client.logger.error "Operation #{@operation_id} failed: #{operation.status_message}"
|
108
|
+
@client.logger.info "Raw JSON available: #{@raw_json ? 'YES' : 'NO'}"
|
109
|
+
return OperationResult.new(operation, @client, @raw_json)
|
110
|
+
end
|
111
|
+
|
112
|
+
elapsed = Time.now - start_time
|
113
|
+
if elapsed > timeout
|
114
|
+
@client.logger.error "Operation #{@operation_id} timed out after #{timeout} seconds"
|
115
|
+
raise Timeout::Error, "Operation #{@operation_id} timed out after #{timeout} seconds"
|
116
|
+
end
|
117
|
+
|
118
|
+
@client.logger.debug "Operation #{@operation_id} status: #{operation.status} (#{elapsed.round(1)}s elapsed)"
|
119
|
+
sleep poll_interval
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Track with a single callback function (like wait_for_operation)
|
124
|
+
# @param timeout [Integer] timeout in seconds
|
125
|
+
# @param poll_interval [Integer] polling interval in seconds
|
126
|
+
# @yield [event_type, data] callback for operation events
|
127
|
+
# @return [OperationResult] the completed operation result
|
128
|
+
def track(timeout: 300, poll_interval: 5)
|
129
|
+
if block_given?
|
130
|
+
# Set up temporary callback
|
131
|
+
original_callbacks = @callbacks.dup
|
132
|
+
|
133
|
+
@callbacks[:log_entry] = ->(data) { yield(:log_entry, data) }
|
134
|
+
@callbacks[:task_new] = ->(data) { yield(:task_new, data) }
|
135
|
+
@callbacks[:task_update] = ->(data) { yield(:task_update, data) }
|
136
|
+
@callbacks[:resource_new] = ->(data) { yield(:resource_new, data) }
|
137
|
+
@callbacks[:status_change] = ->(data) { yield(:status, data) }
|
138
|
+
|
139
|
+
begin
|
140
|
+
result = track_to_completion(timeout: timeout, poll_interval: poll_interval)
|
141
|
+
ensure
|
142
|
+
# Restore original callbacks
|
143
|
+
@callbacks = original_callbacks
|
144
|
+
end
|
145
|
+
|
146
|
+
result
|
147
|
+
else
|
148
|
+
track_to_completion(timeout: timeout, poll_interval: poll_interval)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Get current operation state without updating tracking state
|
153
|
+
# @return [Operation] the current operation
|
154
|
+
def current_state
|
155
|
+
@client.operations.operations_get(@operation_id)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Reset tracking state (clears processed IDs and timestamp)
|
159
|
+
# @return [self] for method chaining
|
160
|
+
def reset_state
|
161
|
+
@processed_log_ids.clear
|
162
|
+
@processed_task_ids.clear
|
163
|
+
@processed_resource_ids.clear
|
164
|
+
@last_timestamp = Time.parse('2018-01-01')
|
165
|
+
self
|
166
|
+
end
|
167
|
+
|
168
|
+
# Get statistics about what has been processed so far
|
169
|
+
# @return [Hash] statistics hash
|
170
|
+
def stats
|
171
|
+
{
|
172
|
+
operation_id: @operation_id,
|
173
|
+
processed_logs: @processed_log_ids.size,
|
174
|
+
processed_tasks: @processed_task_ids.size,
|
175
|
+
processed_resources: @processed_resource_ids.size,
|
176
|
+
last_timestamp: @last_timestamp,
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
# String representation
|
181
|
+
def to_s
|
182
|
+
"#<OperationTracker operation_id=#{@operation_id} stats=#{stats}>"
|
183
|
+
end
|
184
|
+
|
185
|
+
def inspect
|
186
|
+
to_s
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
# Process updates from a polled operation
|
192
|
+
# @param operation [Operation] the operation to process
|
193
|
+
def process_updates(operation)
|
194
|
+
# Process new logs
|
195
|
+
operation.log_entries&.each do |log_entry|
|
196
|
+
next if @processed_log_ids.include?(log_entry.id)
|
197
|
+
|
198
|
+
@processed_log_ids.add(log_entry.id)
|
199
|
+
@last_timestamp = log_entry.timestamp if log_entry.timestamp > @last_timestamp
|
200
|
+
|
201
|
+
begin
|
202
|
+
@callbacks[:log_entry]&.call(log_entry)
|
203
|
+
rescue StandardError => e
|
204
|
+
@client.logger.error "Error in log_entry callback: #{e.message}"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Process new and updated tasks
|
209
|
+
operation.tasks&.each do |task|
|
210
|
+
if @processed_task_ids.include?(task.id)
|
211
|
+
begin
|
212
|
+
@callbacks[:task_update]&.call(task)
|
213
|
+
rescue StandardError => e
|
214
|
+
@client.logger.error "Error in task_update callback: #{e.message}"
|
215
|
+
end
|
216
|
+
else
|
217
|
+
@processed_task_ids.add(task.id)
|
218
|
+
begin
|
219
|
+
@callbacks[:task_new]&.call(task)
|
220
|
+
rescue StandardError => e
|
221
|
+
@client.logger.error "Error in task_new callback: #{e.message}"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# Process new resources
|
227
|
+
operation.resources&.each do |resource|
|
228
|
+
next if @processed_resource_ids.include?(resource.id)
|
229
|
+
|
230
|
+
@processed_resource_ids.add(resource.id)
|
231
|
+
begin
|
232
|
+
@callbacks[:resource_new]&.call(resource)
|
233
|
+
rescue StandardError => e
|
234
|
+
@client.logger.error "Error in resource_new callback: #{e.message}"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Status update
|
239
|
+
begin
|
240
|
+
@callbacks[:status_change]&.call(operation)
|
241
|
+
rescue StandardError => e
|
242
|
+
@client.logger.error "Error in status_change callback: #{e.message}"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Eryph
|
4
|
+
module Compute
|
5
|
+
# Exception class for API errors that include ProblemDetails in the response
|
6
|
+
# Extends StandardError with parsed problem details information
|
7
|
+
class ProblemDetailsError < StandardError
|
8
|
+
attr_reader :problem_details, :problem_type, :title, :detail, :instance, :problem_status, :code,
|
9
|
+
:response_headers, :response_body
|
10
|
+
|
11
|
+
# Create a new ProblemDetailsError
|
12
|
+
# @param api_error [Object] the original API error (could be ComputeClient::ApiError or similar)
|
13
|
+
# @param problem_details [Object, Hash] the parsed problem details
|
14
|
+
def initialize(api_error, problem_details = nil)
|
15
|
+
# Extract basic error information
|
16
|
+
@code = api_error.respond_to?(:code) ? api_error.code : nil
|
17
|
+
@response_headers = api_error.respond_to?(:response_headers) ? api_error.response_headers : nil
|
18
|
+
@response_body = api_error.respond_to?(:response_body) ? api_error.response_body : nil
|
19
|
+
|
20
|
+
# Initialize with the original error's message or a default
|
21
|
+
original_message = api_error.respond_to?(:message) ? api_error.message : api_error.to_s
|
22
|
+
super(original_message)
|
23
|
+
|
24
|
+
@problem_details = problem_details
|
25
|
+
|
26
|
+
return unless problem_details
|
27
|
+
|
28
|
+
if problem_details.respond_to?(:type)
|
29
|
+
# ComputeClient::ProblemDetails object
|
30
|
+
@problem_type = problem_details.type
|
31
|
+
@title = problem_details.title
|
32
|
+
@detail = problem_details.detail
|
33
|
+
@instance = problem_details.instance
|
34
|
+
@problem_status = problem_details.status
|
35
|
+
elsif problem_details.is_a?(Hash)
|
36
|
+
# Hash representation
|
37
|
+
@problem_type = problem_details[:type] || problem_details['type']
|
38
|
+
@title = problem_details[:title] || problem_details['title']
|
39
|
+
@detail = problem_details[:detail] || problem_details['detail']
|
40
|
+
@instance = problem_details[:instance] || problem_details['instance']
|
41
|
+
@problem_status = problem_details[:status] || problem_details['status']
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Create a ProblemDetailsError from an ApiError by parsing the response body
|
46
|
+
# @param api_error [Object] the original API error
|
47
|
+
# @return [ProblemDetailsError, Object] parsed error or original if not parseable
|
48
|
+
def self.from_api_error(api_error)
|
49
|
+
response_body = api_error.respond_to?(:response_body) ? api_error.response_body : nil
|
50
|
+
problem_details = parse_problem_details(response_body)
|
51
|
+
|
52
|
+
if problem_details
|
53
|
+
new(api_error, problem_details)
|
54
|
+
else
|
55
|
+
api_error
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Parse ProblemDetails from a response body
|
60
|
+
# @param response_body [String] the HTTP response body
|
61
|
+
# @return [Object, Hash, nil] parsed problem details or nil if not parseable
|
62
|
+
def self.parse_problem_details(response_body)
|
63
|
+
return nil if response_body.nil? || response_body.empty?
|
64
|
+
|
65
|
+
begin
|
66
|
+
json_data = JSON.parse(response_body)
|
67
|
+
|
68
|
+
# Check if it looks like a problem details response
|
69
|
+
if json_data.is_a?(Hash) && (json_data.key?('type') || json_data.key?('title'))
|
70
|
+
# Try to create a proper ProblemDetails object if the class is available
|
71
|
+
begin
|
72
|
+
if defined?(ComputeClient::ProblemDetails)
|
73
|
+
ComputeClient::ProblemDetails.build_from_hash(json_data)
|
74
|
+
else
|
75
|
+
# Fall back to hash representation if class not available
|
76
|
+
json_data
|
77
|
+
end
|
78
|
+
rescue StandardError
|
79
|
+
# Fall back to hash representation if object creation fails
|
80
|
+
json_data
|
81
|
+
end
|
82
|
+
end
|
83
|
+
rescue JSON::ParserError
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Check if this error has problem details information
|
89
|
+
# @return [Boolean] true if problem details are available
|
90
|
+
def problem_details?
|
91
|
+
!@problem_details.nil?
|
92
|
+
end
|
93
|
+
|
94
|
+
# Get a user-friendly error message
|
95
|
+
# @return [String] formatted error message
|
96
|
+
def friendly_message
|
97
|
+
if problem_details?
|
98
|
+
parts = []
|
99
|
+
parts << @title if @title && !@title.empty?
|
100
|
+
parts << @detail if @detail && !@detail.empty?
|
101
|
+
|
102
|
+
if parts.empty?
|
103
|
+
"API Error: #{@problem_type || 'Unknown error'}"
|
104
|
+
else
|
105
|
+
parts.join(': ')
|
106
|
+
end
|
107
|
+
else
|
108
|
+
super.message
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Override message to provide better error information
|
113
|
+
def message
|
114
|
+
if problem_details?
|
115
|
+
msg = friendly_message
|
116
|
+
msg += "\nProblem Type: #{@problem_type}" if @problem_type
|
117
|
+
msg += "\nInstance: #{@instance}" if @instance
|
118
|
+
msg += "\nHTTP Status: #{code}" if code
|
119
|
+
msg
|
120
|
+
else
|
121
|
+
super
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# String representation
|
126
|
+
def to_s
|
127
|
+
friendly_message
|
128
|
+
end
|
129
|
+
|
130
|
+
def inspect
|
131
|
+
if problem_details?
|
132
|
+
"#<ProblemDetailsError problem_type=#{@problem_type.inspect} title=#{@title.inspect} status=#{code}>"
|
133
|
+
else
|
134
|
+
super
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Eryph Compute Client
|
2
|
+
# High-level client for the Eryph Compute API
|
3
|
+
|
4
|
+
require_relative 'compute/version'
|
5
|
+
require_relative 'compute/operation_result'
|
6
|
+
require_relative 'compute/operation_tracker'
|
7
|
+
require_relative 'compute/problem_details_error'
|
8
|
+
require_relative 'compute/client'
|
9
|
+
|
10
|
+
module Eryph
|
11
|
+
# Compute API client module
|
12
|
+
module Compute
|
13
|
+
# Error raised when compute API operations fail
|
14
|
+
class ComputeError < StandardError; end
|
15
|
+
|
16
|
+
# Error raised when API responses are invalid
|
17
|
+
class ApiError < ComputeError
|
18
|
+
# @return [Integer] HTTP response code
|
19
|
+
attr_reader :code
|
20
|
+
|
21
|
+
# @return [String] response body
|
22
|
+
attr_reader :response_body
|
23
|
+
|
24
|
+
# @return [Hash] response headers
|
25
|
+
attr_reader :response_headers
|
26
|
+
|
27
|
+
# Initialize API error
|
28
|
+
# @param message [String] error message
|
29
|
+
# @param code [Integer] HTTP response code
|
30
|
+
# @param response_body [String] response body
|
31
|
+
# @param response_headers [Hash] response headers
|
32
|
+
def initialize(message, code: nil, response_body: nil, response_headers: nil)
|
33
|
+
super(message)
|
34
|
+
@code = code
|
35
|
+
@response_body = response_body
|
36
|
+
@response_headers = response_headers
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/eryph.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Eryph Ruby Compute Client
|
2
|
+
# Main entry point for the Eryph compute client library
|
3
|
+
|
4
|
+
require_relative 'eryph/version'
|
5
|
+
require_relative 'eryph/clientruntime'
|
6
|
+
require_relative 'eryph/compute'
|
7
|
+
|
8
|
+
# Only load generated client if dependencies are available
|
9
|
+
begin
|
10
|
+
require_relative 'eryph/compute/generated'
|
11
|
+
rescue LoadError => e
|
12
|
+
# Generated client dependencies not available, API clients will fall back to placeholder mode
|
13
|
+
warn "Warning: Generated compute client not available (#{e.message}). Run generate.ps1 to create the API client."
|
14
|
+
end
|
15
|
+
|
16
|
+
module Eryph
|
17
|
+
class << self
|
18
|
+
# Create compute client with automatic or specific credential discovery
|
19
|
+
# @param config_name [String, nil] configuration name for specific config, nil for automatic discovery
|
20
|
+
# @param client_id [String, nil] specific client ID to use
|
21
|
+
# @param options [Hash] additional options
|
22
|
+
# @option options [Logger] :logger logger instance
|
23
|
+
# @option options [Array<String>] :scopes OAuth2 scopes
|
24
|
+
# @option options [Hash] :ssl_config SSL configuration options
|
25
|
+
# @option options [Environment] :environment environment for dependency injection
|
26
|
+
# @return [Compute::Client] a new compute client instance
|
27
|
+
# @example Automatic discovery
|
28
|
+
# client = Eryph.compute_client
|
29
|
+
# @example Specific configuration
|
30
|
+
# client = Eryph.compute_client('zero')
|
31
|
+
# @example Specific client ID
|
32
|
+
# client = Eryph.compute_client('myconfig', client_id: 'my-client-id')
|
33
|
+
# @example With options
|
34
|
+
# client = Eryph.compute_client(logger: my_logger, ssl_config: { verify_ssl: false })
|
35
|
+
def compute_client(config_name = nil, client_id: nil, **options)
|
36
|
+
Compute::Client.new(
|
37
|
+
config_name,
|
38
|
+
client_id: client_id,
|
39
|
+
logger: options[:logger],
|
40
|
+
scopes: options[:scopes],
|
41
|
+
ssl_config: options[:ssl_config] || {},
|
42
|
+
environment: options[:environment]
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Test if credentials are available for the specified configuration
|
47
|
+
# @param config_name [String, nil] configuration name, nil for automatic discovery
|
48
|
+
# @return [Boolean] true if credentials are available
|
49
|
+
# @example
|
50
|
+
# Eryph.credentials_available? # automatic discovery
|
51
|
+
# Eryph.credentials_available?('zero') # specific config
|
52
|
+
def credentials_available?(config_name = nil)
|
53
|
+
ClientRuntime.credentials_available?(config_name: config_name)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Check if eryph-zero is running locally
|
57
|
+
# @return [Boolean] true if eryph-zero is running
|
58
|
+
def zero_running?
|
59
|
+
ClientRuntime.zero_running?
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get endpoints from running eryph-zero instance
|
63
|
+
# @return [Hash] endpoint name -> URL mapping
|
64
|
+
def zero_endpoints
|
65
|
+
ClientRuntime.zero_endpoints
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|