move authorized_keys#get_all_logins to virtual_machines#get_all_logins
[arvados.git] / services / keep / keep.rb
index f38ceeddde4ae0d3f2fbbd919683131a86ed298b..500461883142defbee94f88c650387da12bfbd2b 100755 (executable)
@@ -3,8 +3,14 @@
 require 'sinatra/base'
 require 'digest/md5'
 require 'digest/sha1'
+require 'arvados'
 
 class Keep < Sinatra::Base
+  @@ssl_flag = false
+  def self.ssl_flag
+    @@ssl_flag
+  end
+
   configure do
     mime_type :binary, 'application/octet-stream'
     enable :logging
@@ -39,14 +45,10 @@ class Keep < Sinatra::Base
     self.class.debuglog *args
   end
 
-  def keepdirs
-    @@keepdirs
-  end
-
   def self.keepdirs
     return @@keepdirs if defined? @@keepdirs
     # Configure backing store directories
-    keepdirs = []
+    @@keepdirs = []
     rootdir = (ENV['KEEP_ROOT'] || '/').sub /\/$/, ''
     `mount`.split("\n").each do |mountline|
       dev, on_txt, mountpoint, type_txt, fstype, opts = mountline.split
@@ -56,22 +58,45 @@ class Keep < Sinatra::Base
           debuglog 2, "dir #{mountpoint} is in #{rootdir}/"
           keepdir = "#{mountpoint.sub /\/$/, ''}/keep"
           if File.exists? "#{keepdir}/."
-            keepdirs << { :root => "#{keepdir}", :readonly => false }
+            kd = {
+              :root => keepdir,
+              :arvados => {},
+              :arvados_file => File.join(keepdir, 'arvados_keep_disk.json'),
+              :readonly => false,
+              :device => dev,
+              :device_inode => File.stat(dev).ino
+            }
             if opts.gsub(/[\(\)]/, '').split(',').index('ro')
-              keepdirs[-1][:readonly] = true
+              kd[:readonly] = true
             end
-            debuglog 0, "keepdir #{keepdirs[-1].inspect}"
+            debuglog 2, "keepdir #{kd.inspect}"
+            begin
+              kd[:arvados] = JSON.parse(File.read(kd[:arvados_file]), symbolize_names: true)
+            rescue
+              debuglog 0, "keepdir #{kd.inspect} is new (no #{kd[:arvados_file]})"
+            end
+            @@keepdirs << kd
           end
         end
       end
     end
-    @@keepdirs = keepdirs
+    Dir.open('/dev/disk/by-uuid/').each do |fs_uuid|
+      next if fs_uuid.match /^\./
+      fs_root_inode = File.stat("/dev/disk/by-uuid/#{fs_uuid}").ino
+      @@keepdirs.each do |kd|
+        if kd[:device_inode] == fs_root_inode
+          kd[:filesystem_uuid] = fs_uuid
+          debuglog 0, "keepdir #{kd.reject { |k,v| k==:arvados }.inspect}"
+        end
+      end
+    end
+    @@keepdirs
   end
   self.keepdirs
 
   def find_backfile(hash, opts)
     subdir = hash[0..2]
-    keepdirs.each do |keepdir|
+    @@keepdirs.each do |keepdir|
       backfile = "#{keepdir[:root]}/#{subdir}/#{hash}"
       if File.exists? backfile
         data = nil
@@ -103,6 +128,7 @@ class Keep < Sinatra::Base
     else
       pass
     end
+    self.class.ping_arvados
   end
 
   put '/:locator' do |locator|
@@ -120,7 +146,7 @@ class Keep < Sinatra::Base
     else
       wrote = nil
       subdir = hash[0..2]
-      keepdirs.each do |keepdir|
+      @@keepdirs.each do |keepdir|
         next if keepdir[:readonly]
         backdir = "#{keepdir[:root]}/#{subdir}"
         if !File.exists? backdir
@@ -156,7 +182,47 @@ class Keep < Sinatra::Base
         body 'Fail'
       end
     end
+    self.class.ping_arvados
+  end
+
+  protected
+
+  def self.ping_arvados
+    return if defined? @@last_ping_at and @@last_ping_at > Time.now - 300
+    @@last_ping_at = Time.now
+    begin
+      @@arvados ||= Arvados.new(api_token: '')
+      @@keepdirs.each do |kd|
+        ack = @@arvados.keep_disk.ping(uuid: kd[:arvados][:uuid],
+                                       service_port: settings.port,
+                                       service_ssl_flag: Keep.ssl_flag,
+                                       ping_secret: kd[:arvados][:ping_secret],
+                                       is_readable: true,
+                                       is_writable: !kd[:readonly],
+                                       filesystem_uuid: kd[:filesystem_uuid])
+        if ack and ack[:last_ping_at]
+          debuglog 0, "device #{kd[:device]} uuid #{ack[:uuid]} last_ping_at #{ack[:last_ping_at]}"
+          if kd[:arvados].empty?
+            File.open(kd[:arvados_file]+'.tmp', 'a+', 0600) do end
+            File.open(kd[:arvados_file]+'.tmp', 'r+', 0600) do |f|
+              if f.flock File::LOCK_EX
+                f.seek 0, File::SEEK_SET
+                f.truncate 0
+                f.write ack.to_json
+                File.rename kd[:arvados_file]+'.tmp', kd[:arvados_file]
+                kd[:arvados] = ack
+              end
+            end
+          end
+        else
+          debuglog 0, "device #{kd[:device]} ping fail"
+        end
+      end
+    rescue Exception => e
+      debuglog 0, "ping_arvados: #{e.inspect}"
+    end
   end
+  self.ping_arvados
 
   if app_file == $0
     run! do |server|
@@ -166,6 +232,7 @@ class Keep < Sinatra::Base
           :private_key_file => ENV['SSL_KEY'],
           :verify_peer => false
         }
+        @@ssl_flag = true
         server.ssl = true
         server.ssl_options = ssl_options
       end