18693: Add row locking.
[arvados.git] / services / api / app / models / keep_service.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 class KeepService < ArvadosModel
6   include HasUuid
7   include KindAndEtag
8   include CommonApiTemplate
9   extend DbCurrentTime
10   extend CurrentApiClient
11
12   SERVER_START_TIME = db_current_time
13
14   api_accessible :user, extend: :common do |t|
15     t.add  :service_host
16     t.add  :service_port
17     t.add  :service_ssl_flag
18     t.add  :service_type
19     t.add  :read_only
20   end
21   api_accessible :superuser, :extend => :user do |t|
22   end
23
24   # return the set of keep services from the database (if this is an
25   # older installation or test system where entries have been added
26   # manually) or, preferably, the cluster config file.
27   def self.all *args
28     if super.count == 0
29       from_config
30     else
31       super
32     end
33   end
34
35   def self.where *args
36     all.where *args
37   end
38
39   protected
40
41   def permission_to_create
42     current_user.andand.is_admin
43   end
44
45   def permission_to_update
46     current_user.andand.is_admin
47   end
48
49   def self.from_config
50     config_time = connection.quote(SERVER_START_TIME)
51     owner = connection.quote(system_user_uuid)
52     values = []
53     id = 1
54     Rails.configuration.Services.Keepstore.InternalURLs.each do |url, info|
55       values << "(#{id}, " + quoted_column_values_from_url(url: url.to_s, rendezvous: info.Rendezvous).join(", ") + ", 'disk', 'f'::bool, #{config_time}, #{config_time}, #{owner}, #{owner}, null)"
56       id += 1
57     end
58     url = Rails.configuration.Services.Keepproxy.ExternalURL.to_s
59     if !url.blank?
60       values << "(#{id}, " + quoted_column_values_from_url(url: url, rendezvous: "").join(", ") + ", 'proxy', 'f'::bool, #{config_time}, #{config_time}, #{owner}, #{owner}, null)"
61       id += 1
62     end
63     if values.length == 0
64       # return empty set as AR relation
65       return unscoped.where('1=0')
66     else
67       sql = "(values #{values.join(", ")}) as keep_services (id, uuid, service_host, service_port, service_ssl_flag, service_type, read_only, created_at, modified_at, owner_uuid, modified_by_user_uuid, modified_by_client_uuid)"
68       return unscoped.from(sql)
69     end
70   end
71
72   private
73
74   def self.quoted_column_values_from_url(url:, rendezvous:)
75     rvz = rendezvous
76     rvz = url if rvz.blank?
77     if /^[a-zA-Z0-9]{15}$/ !~ rvz
78       # If rvz is an URL (either the real service URL, or an alternate
79       # one specified in config in order to preserve rendezvous order
80       # when changing hosts/ports), hash it to get 15 alphanums.
81       rvz = Digest::MD5.hexdigest(rvz)[0..15]
82     end
83     uuid = Rails.configuration.ClusterID + "-bi6l4-" + rvz
84     uri = URI::parse(url)
85     [uuid, uri.host, uri.port].map { |x| connection.quote(x) } + [(uri.scheme == 'https' ? "'t'::bool" : "'f'::bool")]
86   end
87
88 end