Skip to content

Commit 5dc7ea9

Browse files
authored
pinned apps to support wildcard globs (#898)
pinned apps to support wildcard globs refactor Router#pinned_apps to accept the tokens and apps as input and compute pinned apps. This puts app logic & member variables in the controllers instead of in Router. This also adds a OodApp#has_sub_apps? api to determine if an app in fact has valid sub apps for showing the subapp in the pinned apps menus.
1 parent 97b2758 commit 5dc7ea9

File tree

18 files changed

+425
-20
lines changed

18 files changed

+425
-20
lines changed

apps/dashboard/app/apps/featured_app.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44
class FeaturedApp < OodApp
55
attr_reader :category, :subcategory, :token
66

7+
def self.from_ood_app(app, token: nil)
8+
FeaturedApp.new(app.router, token: token)
9+
end
10+
711
def initialize(router, category: "Apps", subcategory: "Pinned Apps", token: nil)
812
super(router)
913
@category = category.to_s
1014
@subcategory = subcategory.to_s
11-
@token = token
15+
@token = token || router.token
1216
end
1317

1418
protected

apps/dashboard/app/apps/ood_app.rb

+12-3
Original file line numberDiff line numberDiff line change
@@ -288,10 +288,19 @@ def ==(other)
288288
other.respond_to?(:url) ? url == other.url : false
289289
end
290290

291-
protected
292-
293291
def sub_app_list
294-
batch_connect.sub_app_list
292+
batch_connect_app? ? batch_connect.sub_app_list : []
293+
end
294+
295+
# The subapp list may only be of size 1 and actually contains
296+
# this app. This returns true if there are indeed sub apps that
297+
# that differ from this object.
298+
def has_sub_apps?
299+
if batch_connect_app?
300+
sub_app_list.size > 1 || sub_app_list[0] != batch_connect
301+
else
302+
false
303+
end
295304
end
296305

297306
private

apps/dashboard/app/apps/router.rb

+34-6
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,40 @@ def self.router_from_token(token)
1919
end
2020
end
2121

22-
def self.pinned_apps
23-
@pinned_apps ||= Configuration.pinned_apps.to_a.map do |token|
24-
router = router_from_token(token.to_s)
25-
next if router.nil?
22+
# All the configured "Pinned Apps". Returns an array of unique and already rejected apps
23+
# that may be problematic (inaccessible or idden and so on). Should at least return an
24+
# an empty array.
25+
#
26+
# @return [FeaturedApp]
27+
def self.pinned_apps(tokens, all_apps)
28+
@pinned_apps ||= tokens.to_a.each_with_object([]) do |token, pinned_apps|
29+
pinned_apps.concat pinned_apps_from_token(token, all_apps)
30+
end.uniq do |app|
31+
app.token.to_s
32+
end
33+
end
34+
35+
private
36+
37+
def self.pinned_apps_from_token(token, all_apps)
38+
all_apps.select do |app|
39+
glob_match = File.fnmatch(token, app.token, File::FNM_EXTGLOB)
40+
sub_app_match = token.start_with?(app.token) # find bc/desktop/pitzer from sys/bc_desktop
2641

27-
FeaturedApp.new(router, token: token)
28-
end.reject { |app| !app.accessible? || app.hidden? || app.backup? || app.invalid_batch_connect_app? }
42+
glob_match || sub_app_match
43+
end.each_with_object([]) do |app, apps|
44+
if app.has_sub_apps?
45+
apps.concat(featured_apps_from_sub_app(app, token))
46+
else
47+
apps.append(FeaturedApp.from_ood_app(app))
48+
end
49+
end
50+
end
51+
52+
def self.featured_apps_from_sub_app(app, token)
53+
app.sub_app_list.each_with_object([]) do |sub_app, apps|
54+
glob_match = File.fnmatch(token, sub_app.token, File::FNM_EXTGLOB)
55+
apps.append(FeaturedApp.from_ood_app(app, token: sub_app.token)) if glob_match
56+
end
2957
end
3058
end

apps/dashboard/app/controllers/application_controller.rb

+10-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ class ApplicationController < ActionController::Base
33
# For APIs, you may want to use :null_session instead.
44
protect_from_forgery with: :exception
55

6-
before_action :set_user, :set_nav_groups, :set_announcements, :set_locale
6+
before_action :set_user, :set_pinned_apps, :set_nav_groups, :set_announcements, :set_locale
77
before_action :set_my_balances, only: [:index, :new, :featured]
88
before_action :set_featured_group
99

@@ -38,6 +38,10 @@ def usr_apps
3838
@usr_apps ||= ::Configuration.app_sharing_enabled? ? UsrRouter.all_apps(owners: UsrRouter.owners) : []
3939
end
4040

41+
def nav_all_apps
42+
@nav_all_apps ||= nav_sys_apps + nav_usr_apps + nav_dev_apps
43+
end
44+
4145
def nav_sys_apps
4246
sys_apps.select(&:should_appear_in_nav?)
4347
end
@@ -55,7 +59,11 @@ def sys_app_groups
5559
end
5660

5761
def pinned_app_group
58-
OodAppGroup.groups_for(apps: Router.pinned_apps)
62+
OodAppGroup.groups_for(apps: @pinned_apps)
63+
end
64+
65+
def set_pinned_apps
66+
@pinned_apps ||= Router.pinned_apps(::Configuration.pinned_apps, nav_all_apps)
5967
end
6068

6169
def set_announcements

apps/dashboard/app/helpers/dashboard_helper.rb

-4
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,4 @@ def logo_image_tag(url)
1919
def invalid_clusters
2020
@invalid_clusters ||= OodCore::Clusters.new(OodAppkit.clusters.select { |c| not c.valid? })
2121
end
22-
23-
def pinned_apps?
24-
!Router.pinned_apps.empty?
25-
end
2622
end

apps/dashboard/app/views/dashboard/_pinned_apps.html.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="row">
2-
<%- Router.pinned_apps.each_with_index do |app, index| %>
2+
<%- @pinned_apps.each_with_index do |app, index| %>
33
<%- link = app.links.first -%>
44
<div class="col-sm-3 col-md-3 text-center">
55
<a class="thumbnail app" href="<%= link.url %>">

apps/dashboard/app/views/dashboard/index.html.erb

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<div class="row">
66
<% if @motd %>
77
<div class="col-md-8">
8-
<%= render "pinned_apps" if pinned_apps? %>
8+
<%= render "pinned_apps" unless @pinned_apps.empty? %>
99
<%# This assumes @motd_file responds to `to_partial_path` %>
1010
<%= render @motd %>
1111
</div>
@@ -29,6 +29,6 @@
2929
<% end %>
3030
</div>
3131
<% else %>
32-
<%= render "pinned_apps" if pinned_apps? %>
32+
<%= render "pinned_apps" unless @pinned_apps.empty? %>
3333
<%= render @motd if @motd %>
3434
<% end %>

apps/dashboard/app/views/layouts/application.html.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</div>
3838
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-9">
3939
<ul class="nav navbar-nav">
40-
<%= render partial: 'layouts/nav/featured_apps', locals: { group: @featured_group } if pinned_apps? %>
40+
<%= render partial: 'layouts/nav/featured_apps', locals: { group: @featured_group } unless @pinned_apps.empty? %>
4141
<%= render partial: 'layouts/nav/group', collection: @nav_groups %>
4242
<%= render partial: 'layouts/nav/sessions', nav_groups: @nav_groups if Configuration.app_development_enabled? || @nav_groups.any?(&:has_batch_connect_apps?) %>
4343
<%= render partial: 'layouts/nav/all_apps' if Configuration.show_all_apps_link? %>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
name: App One
3+
description: |-
4+
The first app that you can't see
5+
category: CantSee
6+
icon: fa://tachometer
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
name: App two
3+
description: |-
4+
The second app you can't see
5+
category: CantSee
6+
icon: fa://tachometer
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
name: My Shared App
3+
description: |-
4+
Some App I'm sharing
5+
category: Me
6+
icon: fa://tachometer
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
title: "Oakley Usr App"
3+
cluster: "oakley"
4+
form:
5+
first_item
6+
submit: submit/pbs.yml.erb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
name: "Oakley Usr App"
3+
category: Interactive Apps
4+
subcategory: Servers
5+
icon: fa://desktop
6+
role: batch_connect
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
description: |
3+
This app will launch an interactive desktop on one or more compute nodes. You
4+
will have full access to the resources these nodes provide. This is analogous
5+
to an interctive batch job.
6+
7+
attributes:
8+
desktop: "mate"
9+
bc_vnc_idle: 0
10+
bc_vnc_resolution:
11+
required: true
12+
node_type: null
13+
14+
form:
15+
- bc_vnc_idle
16+
- desktop
17+
- bc_num_hours
18+
- bc_num_slots
19+
- node_type
20+
- bc_account
21+
- bc_queue
22+
- bc_vnc_resolution
23+
- bc_email_on_started
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: "Oakley Desktop"
3+
cluster: "oakley"
4+
attributes:
5+
desktop: "gnome"
6+
bc_queue: null
7+
bc_account:
8+
help: "You can leave this blank if **not** in multiple projects."
9+
node_type:
10+
widget: select
11+
label: "Node type"
12+
help: |
13+
- **any** - (*12 cores*) Chooses anyone of the available Oakley nodes.
14+
This reduces the wait time as you have no requirements.
15+
- **vis** - (*12 cores*) This node includes an NVIDIA Tesla M2070 GPU
16+
with an X server running in the background. This allows for Hardware
17+
Rendering with the GPU typically needed for 3D visualization using
18+
VirtualGL. There are currently only 128 of these nodes on Oakley.
19+
- **gpu** - (*12 cores*) This node includes an NVIDIA Tesla M2070 GPU
20+
allowing for CUDA computations. There are currently only 128 of these
21+
nodes on Oakley. These nodes don't start an X server, so visualization
22+
with hardware rendering is not possible.
23+
- **bigmem** - (*12 cores*) This Oakley node comes with 192GB of
24+
available RAM. There are only 8 of these nodes on Oakley.
25+
- **hugemem** - (*32 cores*) This Oakley node has 1TB of available RAM as
26+
well as 32 cores. There is only 1 of these nodes on Oakley. A
27+
reservation may be required to use this node.
28+
options:
29+
- ["any", ":ppn=12"]
30+
- ["vis", ":ppn=12:vis:gpus=1"]
31+
- ["gpu", ":ppn=12:gpus=1"]
32+
- ["bigmem", ":ppn=12:bigmem"]
33+
- ["hugemem", ":ppn=32:hugemem"]
34+
submit: submit/pbs.yml.erb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: "Owens Desktop"
3+
cluster: "owens"
4+
attributes:
5+
desktop: "gnome"
6+
bc_queue: null
7+
bc_account:
8+
help: "You can leave this blank if **not** in multiple projects."
9+
node_type:
10+
widget: select
11+
label: "Node type"
12+
help: |
13+
- **any** - (*12 cores*) Chooses anyone of the available Oakley nodes.
14+
This reduces the wait time as you have no requirements.
15+
- **vis** - (*12 cores*) This node includes an NVIDIA Tesla M2070 GPU
16+
with an X server running in the background. This allows for Hardware
17+
Rendering with the GPU typically needed for 3D visualization using
18+
VirtualGL. There are currently only 128 of these nodes on Oakley.
19+
- **gpu** - (*12 cores*) This node includes an NVIDIA Tesla M2070 GPU
20+
allowing for CUDA computations. There are currently only 128 of these
21+
nodes on Oakley. These nodes don't start an X server, so visualization
22+
with hardware rendering is not possible.
23+
- **bigmem** - (*12 cores*) This Oakley node comes with 192GB of
24+
available RAM. There are only 8 of these nodes on Oakley.
25+
- **hugemem** - (*32 cores*) This Oakley node has 1TB of available RAM as
26+
well as 32 cores. There is only 1 of these nodes on Oakley. A
27+
reservation may be required to use this node.
28+
options:
29+
- ["any", ":ppn=12"]
30+
- ["vis", ":ppn=12:vis:gpus=1"]
31+
- ["gpu", ":ppn=12:gpus=1"]
32+
- ["bigmem", ":ppn=12:bigmem"]
33+
- ["hugemem", ":ppn=32:hugemem"]
34+
submit: submit/pbs.yml.erb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
name: Desktops
3+
category: Interactive Apps
4+
subcategory: Desktops
5+
icon: fa://desktop
6+
role: batch_connect

0 commit comments

Comments
 (0)