bac033e214bd58a4ad7455b431aabbbfe0c6bef1
[arvados.git] / services / api / script / salvage_collection.rb
1 #!/usr/bin/env ruby
2
3 # Take two input parameters: a collection uuid and reason
4 # Get "src_collection" with the given uuid
5 # Create a new collection with:
6 #   src_collection.manifest_text as "invalid_manifest_text.txt"
7 #   Locators from src_collection.manifest_text as "salvaged_data"
8 # Update src_collection:
9 #   Set src_collection.manifest_text to: ""
10 #   Append to src_collection.name: " (reason; salvaged data at new_collection.uuid)"
11 #   Set portable_data_hash to "d41d8cd98f00b204e9800998ecf8427e+0"
12
13 require 'trollop'
14
15 opts = Trollop::options do
16   banner ''
17   banner "Usage: salvage_collection.rb " +
18     "{uuid} {reason}"
19   banner ''
20   opt :uuid, <<-eos
21 uuid of the collection to be salvaged.
22   eos
23   opt :reason, <<-eos
24 Reason for salvaging.
25   eos
26 end
27
28 if ARGV.count < 1
29   Trollop::die "required uuid argument is missing"
30 end
31
32 uuid, reason = ARGV
33
34 require File.dirname(__FILE__) + '/../config/environment'
35 require 'arvados/keep'
36 include ApplicationHelper
37 require 'tempfile'
38
39 def salvage_collection uuid, reason
40   act_as_system_user do
41     src_collection = Collection.find_by_uuid uuid
42     if !src_collection
43       $stderr.puts "No collection found for #{uuid}. Returning."
44       return
45     end
46
47     begin
48       src_manifest = src_collection.manifest_text || ''
49
50       # Get all the locators from the original manifest
51       locators = []
52       src_manifest.each_line do |line|
53         line.split(' ').each do |word|
54           if match = Keep::Locator::LOCATOR_REGEXP.match(word)
55             word = word.split('+')[0..1].join('+')  # get rid of any hints
56             locators << word
57           end
58         end
59       end
60       locators << 'd41d8cd98f00b204e9800998ecf8427e+0' if !locators.any?
61
62       # create new collection using 'arv-put' with original manifest_text as the data
63       temp_file = Tempfile.new('temp')
64       temp_file.write(src_manifest)
65       temp_file.close
66
67       created = %x(arv-put --use-filename invalid_manifest_text.txt #{temp_file.path})
68
69       temp_file.unlink
70
71       created.rstrip!
72       match = created.match HasUuid::UUID_REGEX
73       raise "uuid not found" if !match
74
75       # update this new collection manifest to reference all locators from the original manifest
76       new_collection = Collection.find_by_uuid created
77
78       new_manifest = new_collection['manifest_text']
79       new_manifest = new_manifest.gsub(/\+A[^+]*/, '')
80       total_size = 0
81       locators.each do |locator|
82         total_size += locator.split('+')[1].to_i
83       end
84       new_manifest += (". #{locators.join(' ')} 0:#{total_size}:salvaged_data\n")
85
86       new_collection.name = "salvaged from #{src_collection.uuid}, #{src_collection.portable_data_hash}"
87       new_collection.manifest_text = new_manifest
88       new_collection.portable_data_hash = Digest::MD5.hexdigest(new_manifest)
89
90       new_collection.save!
91
92       $stderr.puts "Salvaged manifest and data for #{uuid} are in #{new_collection.uuid}."
93       puts "Created new collection #{created}"
94     rescue => error
95       $stderr.puts "Error creating collection for #{uuid}: #{error}"
96       return
97     end
98
99     begin
100       # update src_collection collection name, pdh, and manifest_text
101       src_collection.name = (src_collection.name || '') + ' (' + (reason || '') + '; salvaged data at ' + created + ')'
102       src_collection.manifest_text = ''
103       src_collection.portable_data_hash = 'd41d8cd98f00b204e9800998ecf8427e+0'
104       src_collection.save!
105       $stderr.puts "Collection #{uuid} emptied and renamed to #{src_collection.name.inspect}."
106     rescue => error
107       $stderr.puts "Error salvaging collection #{uuid}: #{error}"
108     end
109   end
110 end
111
112 # Salvage the collection with the given uuid
113 salvage_collection uuid, reason