15680: Update mockkeep.put to accept num_retries arg.
[arvados.git] / services / api / lib / tasks / symbols.rake
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 require 'current_api_client'
6
7 include CurrentApiClient
8
9 def has_symbols? x
10   if x.is_a? Hash
11     x.each do |k,v|
12       return true if has_symbols?(k) or has_symbols?(v)
13     end
14   elsif x.is_a? Array
15     x.each do |k|
16       return true if has_symbols?(k)
17     end
18   elsif x.is_a? Symbol
19     return true
20   elsif x.is_a? String
21     return true if x.start_with?(':') && !x.start_with?('::')
22   end
23   false
24 end
25
26 def check_for_serialized_symbols rec
27   jsonb_cols = rec.class.columns.select{|c| c.type == :jsonb}.collect{|j| j.name}
28   (jsonb_cols + rec.class.serialized_attributes.keys).uniq.each do |colname|
29     if has_symbols? rec.attributes[colname]
30       st = recursive_stringify rec.attributes[colname]
31       puts "Found value potentially containing Ruby symbols in #{colname} attribute of #{rec.uuid}, current value is\n#{rec.attributes[colname].to_s[0..1024]}\nrake symbols:stringify will update it to:\n#{st.to_s[0..1024]}\n\n"
32     end
33   end
34 end
35
36 def recursive_stringify x
37   if x.is_a? Hash
38     Hash[x.collect do |k,v|
39            [recursive_stringify(k), recursive_stringify(v)]
40          end]
41   elsif x.is_a? Array
42     x.collect do |k|
43       recursive_stringify k
44     end
45   elsif x.is_a? Symbol
46     x.to_s
47   elsif x.is_a? String and x.start_with?(':') and !x.start_with?('::')
48     x[1..-1]
49   else
50     x
51   end
52 end
53
54 def stringify_serialized_symbols rec
55   # ensure_serialized_attribute_type should prevent symbols from
56   # getting into the database in the first place. If someone managed
57   # to get them into the database (perhaps using an older version)
58   # we'll convert symbols to strings when loading from the
59   # database. (Otherwise, loading and saving an object with existing
60   # symbols in a serialized field will crash.)
61   jsonb_cols = rec.class.columns.select{|c| c.type == :jsonb}.collect{|j| j.name}
62   (jsonb_cols + rec.class.serialized_attributes.keys).uniq.each do |colname|
63     if has_symbols? rec.attributes[colname]
64       begin
65         st = recursive_stringify rec.attributes[colname]
66         puts "Updating #{colname} attribute of #{rec.uuid} from\n#{rec.attributes[colname].to_s[0..1024]}\nto\n#{st.to_s[0..1024]}\n\n"
67         rec.write_attribute(colname, st)
68         rec.save!
69       rescue => e
70         puts "Failed to update #{rec.uuid}: #{e}"
71       end
72     end
73   end
74 end
75
76 namespace :symbols do
77   desc 'Warn about serialized values starting with ":" that may be symbols'
78   task check: :environment do
79     [ApiClientAuthorization, ApiClient,
80      AuthorizedKey, Collection,
81      Container, ContainerRequest, Group,
82      Human, Job, JobTask, KeepDisk, KeepService, Link,
83      Node, PipelineInstance, PipelineTemplate,
84      Repository, Specimen, Trait, User, VirtualMachine,
85      Workflow].each do |klass|
86       act_as_system_user do
87         klass.all.each do |c|
88           check_for_serialized_symbols c
89         end
90       end
91     end
92   end
93
94   task stringify: :environment do
95     [ApiClientAuthorization, ApiClient,
96      AuthorizedKey, Collection,
97      Container, ContainerRequest, Group,
98      Human, Job, JobTask, KeepDisk, KeepService, Link,
99      Node, PipelineInstance, PipelineTemplate,
100      Repository, Specimen, Trait, User, VirtualMachine,
101      Workflow].each do |klass|
102       act_as_system_user do
103         klass.all.each do |c|
104           stringify_serialized_symbols c
105         end
106       end
107     end
108   end
109 end