[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