|
1 | 1 | Backups::Plugin.hook helpers: %i[client_helper query_helper uid_helper] do |
2 | 2 | def call(virtual_server) |
3 | | - recovery_points = |
| 3 | + |
| 4 | + # Get VmRestorePoint for Virtual Server |
| 5 | + vm_recovery_points = |
4 | 6 | api_get( |
5 | 7 | build_query(:vmrestorepoint, HierarchyObjRef: "\"#{virtual_server.metadata[:veeam_uid]}\"") |
6 | 8 | ).dig(:QueryResult, :Entities, :VmRestorePoints, :VmRestorePoint) |
7 | 9 |
|
8 | | - [recovery_points].flatten.compact.map do |recovery_point_hash| |
9 | | - build_recovery_point(size: 0, # Unable to get size via EM API |
10 | | - created_at: Time.parse(recovery_point_hash[:CreationTimeUTC]), |
11 | | - updated_at: Time.parse(recovery_point_hash[:CreationTimeUTC]), |
| 10 | + # Iterate over Jobs => Backup => restorePoints => vmRestorePoints |
| 11 | + virtual_server.metadata[:veeam_related_job_ids].flat_map do |job_id| |
| 12 | + |
| 13 | + # Get Job's name by its ID |
| 14 | + unless job_name = api_get("jobs/#{job_id}") |
| 15 | + .dig(:EntityRef, :Name) |
| 16 | + logger.error("Unable to get Name of Job by ID: '#{job_id}'") |
| 17 | + next |
| 18 | + end |
| 19 | + |
| 20 | + # Find Backup which name matches Job's name |
| 21 | + unless backup_id = get_backup_id(job_name) |
| 22 | + logger.error("Unable to find Backup for Job named '#{job_name}'") |
| 23 | + next |
| 24 | + end |
| 25 | + |
| 26 | + # Get restorePoints for Backup |
| 27 | + get_recovery_points("backups", backup_id, "restorePoints") |
| 28 | + .uniq { |r| r[:UID] } |
| 29 | + .flat_map do |restore_point_hash| |
| 30 | + unless rp_id = uid_to_identifier("RestorePoint", restore_point_hash[:UID]) |
| 31 | + logger.error("Unable to get RestorePoint ID") |
| 32 | + next |
| 33 | + end |
| 34 | + |
| 35 | + # Get vmRestorePoints for restorePoints |
| 36 | + get_recovery_points("restorePoints", rp_id, "vmRestorePoints") |
| 37 | + .flatten |
| 38 | + .compact.map do |vm_restore_point_hash| |
| 39 | + |
| 40 | + # Skip vmRestorePoint if it isn't in VmRestorePoint for Virtual Server |
| 41 | + next unless vm_recovery_points.any? {|vm_rp| vm_rp[:UID].eql? vm_restore_point_hash[:UID]} |
| 42 | + |
| 43 | + # Restore point date is right after '@' rightmost occurrence |
| 44 | + vm_restore_point_date = vm_restore_point_hash[:Name].rpartition('@')[2] |
| 45 | + |
| 46 | + build_recovery_point(size: 0, # Unable to get size via EM API |
| 47 | + created_at: vm_restore_point_date, |
| 48 | + updated_at: vm_restore_point_date, |
12 | 49 | state: :built).tap do |rp| |
13 | | - rp.metadata[:veeam_id] = uid_to_identifier(:VmRestorePoint, recovery_point_hash[:UID]) |
| 50 | + rp.metadata[:veeam_id] = uid_to_identifier("VmRestorePoint", vm_restore_point_hash[:UID]) |
| 51 | + end |
| 52 | + end |
14 | 53 | end |
15 | | - end |
| 54 | + end.compact |
| 55 | + end |
| 56 | + |
| 57 | + private |
| 58 | + |
| 59 | + def get_backup_id(backup_name) |
| 60 | + uid_to_identifier( |
| 61 | + :Backup, |
| 62 | + api_get(build_query(:backup, { name: "\"#{backup_name}\"" }, entities: false)) |
| 63 | + .dig(:QueryResult, :Refs, :Ref, :UID) |
| 64 | + ) |
| 65 | + end |
| 66 | + |
| 67 | + def get_recovery_points(resource_type, resource_id, points_type) |
| 68 | + points = api_get("/#{resource_type}/#{resource_id}/#{points_type}") |
| 69 | + .dig(:EntityReferences, :Ref) |
| 70 | + |
| 71 | + return unless points |
| 72 | + |
| 73 | + points.is_a?(Hash) ? [points] : points |
16 | 74 | end |
17 | 75 | end |
0 commit comments