[ARVADOS] updated: 034a8c0c581e5c2a72dab66f8cdffea781b014f6
Git user
git at public.curoverse.com
Wed Sep 6 23:23:16 EDT 2017
Summary of changes:
services/api/app/models/arvados_model.rb | 31 +++--
services/api/app/models/group.rb | 2 +-
services/api/app/models/log.rb | 2 +-
services/api/app/models/user.rb | 16 ++-
services/api/db/structure.sql | 198 +++++++++++++++++++++++++++++++
5 files changed, 228 insertions(+), 21 deletions(-)
via 034a8c0c581e5c2a72dab66f8cdffea781b014f6 (commit)
from d950b79a368dab504c32953e511efc1639a44ff7 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 034a8c0c581e5c2a72dab66f8cdffea781b014f6
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date: Wed Sep 6 23:12:41 2017 -0400
12032: Ensure that permission_view is invalidated & refreshed
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <pamstutz at veritasgenetics.com>
diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index f5d20b1..f6e914d 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -260,55 +260,52 @@ class ArvadosModel < ActiveRecord::Base
sql_conds = []
user_uuids = users_list.map { |u| u.uuid }
- User.install_view('permission')
-
- # Check if any of the users are admin.
if users_list.select { |u| u.is_admin }.any?
if !include_trash
# exclude rows that are explicitly trashed.
if self.column_names.include? "owner_uuid"
- sql_conds += ["NOT EXISTS(SELECT 1
+ sql_conds.push "NOT EXISTS(SELECT 1
FROM permission_view
WHERE trashed = 1 AND
- (#{sql_table}.uuid = target_uuid OR #{sql_table}.owner_uuid = target_uuid))"]
+ (#{sql_table}.uuid = target_uuid OR #{sql_table}.owner_uuid = target_uuid))"
else
- sql_conds += ["NOT EXISTS(SELECT 1
+ sql_conds.push "NOT EXISTS(SELECT 1
FROM permission_view
WHERE trashed = 1 AND
- (#{sql_table}.uuid = target_uuid))"]
+ (#{sql_table}.uuid = target_uuid))"
end
end
else
# Can read object (evidently a group or user) whose UUID is listed
# explicitly in user_uuids.
- sql_conds += ["#{sql_table}.uuid IN (:user_uuids)"]
+ sql_conds.push "#{sql_table}.uuid IN (:user_uuids)"
if include_trash
- trashed_check = ""
+ trashed_check = "true"
else
- trashed_check = "trashed = 0 AND"
+ trashed_check = "trashed = 0"
end
- perm_check = "perm_level >= 1"
-
if self.column_names.include? "owner_uuid" and sql_table != "groups"
- owner_check = "OR #{sql_table}.owner_uuid IN (:user_uuids) OR (target_uuid = #{sql_table}.owner_uuid AND target_owner_uuid IS NOT NULL)"
+ owner_check = "OR (target_uuid = #{sql_table}.owner_uuid AND target_owner_uuid IS NOT NULL)"
+ sql_conds.push "#{sql_table}.owner_uuid IN (:user_uuids)"
else
owner_check = ""
end
- sql_conds += ["EXISTS(SELECT 1 FROM permission_view "+
- "WHERE user_uuid IN (:user_uuids) AND #{trashed_check} #{perm_check} AND (target_uuid = #{sql_table}.uuid #{owner_check}))"]
+ sql_conds.push "EXISTS(SELECT 1 FROM permission_view "+
+ "WHERE user_uuid IN (:user_uuids) AND perm_level >= 1 AND #{trashed_check} AND (target_uuid = #{sql_table}.uuid #{owner_check}))"
if sql_table == "links"
# Match any permission link that gives one of the authorized
# users some permission _or_ gives anyone else permission to
# view one of the authorized users.
- sql_conds += ["(#{sql_table}.link_class IN (:permission_link_classes) AND "+
- "(#{sql_table}.head_uuid IN (:user_uuids) OR #{sql_table}.tail_uuid IN (:user_uuids)))"]
+ sql_conds.push "(#{sql_table}.link_class IN (:permission_link_classes) AND "+
+ "(#{sql_table}.head_uuid IN (:user_uuids) OR #{sql_table}.tail_uuid IN (:user_uuids)))"
end
end
+ User.fresh_permission_view
query_on.where(sql_conds.join(' OR '),
user_uuids: user_uuids,
permission_link_classes: ['permission', 'resources'])
diff --git a/services/api/app/models/group.rb b/services/api/app/models/group.rb
index 861800d..fe18367 100644
--- a/services/api/app/models/group.rb
+++ b/services/api/app/models/group.rb
@@ -27,7 +27,7 @@ class Group < ArvadosModel
end
def maybe_invalidate_permissions_cache
- if uuid_changed? or owner_uuid_changed?
+ if uuid_changed? or owner_uuid_changed? or is_trashed_changed?
# This can change users' permissions on other groups as well as
# this one.
invalidate_permissions_cache
diff --git a/services/api/app/models/log.rb b/services/api/app/models/log.rb
index 99d0e28..8664448 100644
--- a/services/api/app/models/log.rb
+++ b/services/api/app/models/log.rb
@@ -68,7 +68,7 @@ class Log < ArvadosModel
end
user_uuids = users_list.map { |u| u.uuid }
- User.install_view('permission')
+ User.fresh_permission_view
joins("LEFT JOIN container_requests ON container_requests.container_uuid=logs.object_uuid").
where("EXISTS(SELECT target_uuid FROM permission_view "+
diff --git a/services/api/app/models/user.rb b/services/api/app/models/user.rb
index 9f053c0..2daa37e 100644
--- a/services/api/app/models/user.rb
+++ b/services/api/app/models/user.rb
@@ -35,6 +35,7 @@ class User < ArvadosModel
user.username.nil? and user.email
}
after_create :add_system_group_permission_link
+ after_create :invalidate_permissions_cache
after_create :auto_setup_new_user, :if => Proc.new { |user|
Rails.configuration.auto_setup_new_users and
(user.uuid != system_user_uuid) and
@@ -150,10 +151,13 @@ class User < ArvadosModel
end
end
+ def invalidate_permissions_cache(timestamp=nil)
+ User.invalidate_permissions_cache
+ end
+
# Return a hash of {user_uuid: group_perms}
def self.all_group_permissions
all_perms = {}
- User.install_view('permission')
ActiveRecord::Base.connection.
exec_query('SELECT user_uuid, target_owner_uuid, perm_level, trashed
FROM permission_view
@@ -172,7 +176,7 @@ class User < ArvadosModel
# objects owned by group_uuid.
def calculate_group_permissions
group_perms = {self.uuid => {:read => true, :write => true, :manage => true}}
- User.install_view('permission')
+ User.fresh_permission_view
ActiveRecord::Base.connection.
exec_query('SELECT target_owner_uuid, perm_level, trashed
FROM permission_view
@@ -207,6 +211,14 @@ class User < ArvadosModel
r
end
+ def self.fresh_permission_view
+ r = Rails.cache.read "#{PERM_CACHE_PREFIX}_fresh"
+ if r.nil?
+ ActiveRecord::Base.connection.exec_query('REFRESH MATERIALIZED VIEW permission_view')
+ Rails.cache.write "#{PERM_CACHE_PREFIX}_fresh", 1, expires_in: PERM_CACHE_TTL
+ end
+ end
+
# create links
def setup(openid_prefix:, repo_name: nil, vm_uuid: nil)
oid_login_perm = create_oid_login_perm openid_prefix
diff --git a/services/api/db/structure.sql b/services/api/db/structure.sql
index 9656e72..77c833a 100644
--- a/services/api/db/structure.sql
+++ b/services/api/db/structure.sql
@@ -790,6 +790,68 @@ ALTER SEQUENCE nodes_id_seq OWNED BY nodes.id;
--
+-- Name: permission_view; Type: MATERIALIZED VIEW; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE MATERIALIZED VIEW permission_view AS
+ WITH RECURSIVE perm_value(name, val) AS (
+ VALUES ('can_read'::text,(1)::smallint), ('can_login'::text,1), ('can_write'::text,2), ('can_manage'::text,3)
+ ), perm_edges(tail_uuid, head_uuid, val, follow, trashed) AS (
+ SELECT links.tail_uuid,
+ links.head_uuid,
+ pv.val,
+ ((pv.val = 3) OR (groups.uuid IS NOT NULL)) AS follow,
+ (0)::smallint AS trashed
+ FROM ((links
+ LEFT JOIN perm_value pv ON ((pv.name = (links.name)::text)))
+ LEFT JOIN groups ON (((pv.val < 3) AND ((groups.uuid)::text = (links.head_uuid)::text))))
+ WHERE ((links.link_class)::text = 'permission'::text)
+ UNION ALL
+ SELECT groups.owner_uuid,
+ groups.uuid,
+ 3,
+ true AS bool,
+ CASE
+ WHEN ((groups.trash_at IS NOT NULL) AND (groups.trash_at < clock_timestamp())) THEN 1
+ ELSE 0
+ END AS "case"
+ FROM groups
+ ), perm(val, follow, user_uuid, target_uuid, trashed, startnode) AS (
+ SELECT (3)::smallint AS val,
+ false AS follow,
+ (users.uuid)::character varying(32) AS user_uuid,
+ (users.uuid)::character varying(32) AS target_uuid,
+ (0)::smallint AS trashed,
+ true AS startnode
+ FROM users
+ UNION
+ SELECT (LEAST((perm_1.val)::integer, edges.val))::smallint AS val,
+ edges.follow,
+ perm_1.user_uuid,
+ (edges.head_uuid)::character varying(32) AS target_uuid,
+ (GREATEST((perm_1.trashed)::integer, edges.trashed))::smallint AS trashed,
+ false AS startnode
+ FROM (perm perm_1
+ JOIN perm_edges edges ON (((perm_1.startnode OR perm_1.follow) AND ((edges.tail_uuid)::text = (perm_1.target_uuid)::text))))
+ )
+ SELECT perm.user_uuid,
+ perm.target_uuid,
+ max(perm.val) AS perm_level,
+ CASE perm.follow
+ WHEN true THEN perm.target_uuid
+ ELSE NULL::character varying
+ END AS target_owner_uuid,
+ max(perm.trashed) AS trashed
+ FROM perm
+ GROUP BY perm.user_uuid, perm.target_uuid,
+ CASE perm.follow
+ WHEN true THEN perm.target_uuid
+ ELSE NULL::character varying
+ END
+ WITH NO DATA;
+
+
+--
-- Name: pipeline_instances; Type: TABLE; Schema: public; Owner: -; Tablespace:
--
@@ -872,6 +934,30 @@ ALTER SEQUENCE pipeline_templates_id_seq OWNED BY pipeline_templates.id;
--
+-- Name: read_permissions; Type: VIEW; Schema: public; Owner: -
+--
+
+CREATE VIEW read_permissions AS
+ WITH RECURSIVE read_permissions(follow, user_uuid, readable_uuid) AS (
+ SELECT true AS bool,
+ users.uuid,
+ users.uuid
+ FROM users
+ UNION
+ SELECT (((links.name)::text = 'can_manage'::text) OR ((links.head_uuid)::text ~~ 'su92l-j7d0g-%'::text)) AS follow,
+ rp.user_uuid,
+ links.head_uuid
+ FROM read_permissions rp,
+ links
+ WHERE (rp.follow AND ((links.tail_uuid)::text = (rp.readable_uuid)::text))
+ )
+ SELECT read_permissions.follow,
+ read_permissions.user_uuid,
+ read_permissions.readable_uuid
+ FROM read_permissions;
+
+
+--
-- Name: repositories; Type: TABLE; Schema: public; Owner: -; Tablespace:
--
@@ -908,6 +994,18 @@ ALTER SEQUENCE repositories_id_seq OWNED BY repositories.id;
--
+-- Name: rp_cache; Type: MATERIALIZED VIEW; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE MATERIALIZED VIEW rp_cache AS
+ SELECT read_permissions.follow,
+ read_permissions.user_uuid,
+ read_permissions.readable_uuid
+ FROM read_permissions
+ WITH NO DATA;
+
+
+--
-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -; Tablespace:
--
@@ -1673,6 +1771,13 @@ CREATE INDEX index_collections_on_modified_at ON collections USING btree (modifi
--
+-- Name: index_collections_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_collections_on_modified_at_uuid ON collections USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_collections_on_owner_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -1722,6 +1827,13 @@ CREATE UNIQUE INDEX index_commits_on_repository_name_and_sha1 ON commits USING b
--
+-- Name: index_container_requests_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_container_requests_on_modified_at_uuid ON container_requests USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_container_requests_on_owner_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -1792,6 +1904,13 @@ CREATE INDEX index_groups_on_modified_at ON groups USING btree (modified_at);
--
+-- Name: index_groups_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_groups_on_modified_at_uuid ON groups USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_groups_on_owner_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -1911,6 +2030,13 @@ CREATE INDEX index_jobs_on_modified_at ON jobs USING btree (modified_at);
--
+-- Name: index_jobs_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_jobs_on_modified_at_uuid ON jobs USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_jobs_on_output; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -2030,6 +2156,13 @@ CREATE INDEX index_links_on_modified_at ON links USING btree (modified_at);
--
+-- Name: index_links_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_links_on_modified_at_uuid ON links USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_links_on_owner_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -2170,6 +2303,13 @@ CREATE INDEX index_pipeline_instances_on_modified_at ON pipeline_instances USING
--
+-- Name: index_pipeline_instances_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_pipeline_instances_on_modified_at_uuid ON pipeline_instances USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_pipeline_instances_on_owner_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -2198,6 +2338,13 @@ CREATE INDEX index_pipeline_templates_on_modified_at ON pipeline_templates USING
--
+-- Name: index_pipeline_templates_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_pipeline_templates_on_modified_at_uuid ON pipeline_templates USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_pipeline_templates_on_owner_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -2212,6 +2359,13 @@ CREATE UNIQUE INDEX index_pipeline_templates_on_uuid ON pipeline_templates USING
--
+-- Name: index_repositories_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_repositories_on_modified_at_uuid ON repositories USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_repositories_on_name; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -2296,6 +2450,13 @@ CREATE INDEX index_users_on_modified_at ON users USING btree (modified_at);
--
+-- Name: index_users_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_users_on_modified_at_uuid ON users USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_users_on_owner_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -2324,6 +2485,13 @@ CREATE INDEX index_virtual_machines_on_hostname ON virtual_machines USING btree
--
+-- Name: index_virtual_machines_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_virtual_machines_on_modified_at_uuid ON virtual_machines USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_virtual_machines_on_owner_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -2338,6 +2506,13 @@ CREATE UNIQUE INDEX index_virtual_machines_on_uuid ON virtual_machines USING btr
--
+-- Name: index_workflows_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_workflows_on_modified_at_uuid ON workflows USING btree (modified_at DESC, uuid);
+
+
+--
-- Name: index_workflows_on_owner_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -2415,6 +2590,20 @@ CREATE INDEX nodes_search_index ON nodes USING btree (uuid, owner_uuid, modified
--
+-- Name: permission_target_trashed; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX permission_target_trashed ON permission_view USING btree (trashed, target_uuid);
+
+
+--
+-- Name: permission_target_user_trashed_level; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX permission_target_user_trashed_level ON permission_view USING btree (user_uuid, trashed, perm_level);
+
+
+--
-- Name: pipeline_instances_full_text_search_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -2464,6 +2653,13 @@ CREATE INDEX specimens_search_index ON specimens USING btree (uuid, owner_uuid,
--
+-- Name: test_1; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX test_1 ON collections USING btree (id) WHERE (delete_at IS NULL);
+
+
+--
-- Name: traits_search_index; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@@ -2817,3 +3013,5 @@ INSERT INTO schema_migrations (version) VALUES ('20170628185847');
INSERT INTO schema_migrations (version) VALUES ('20170824202826');
+INSERT INTO schema_migrations (version) VALUES ('20170906224040');
+
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list