etna 0.1.32 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/etna.completion +115 -1
- data/lib/commands.rb +30 -0
- data/lib/etna/auth.rb +25 -0
- data/lib/etna/client.rb +13 -4
- data/lib/etna/clients/base_client.rb +2 -3
- data/lib/etna/clients/janus.rb +1 -0
- data/lib/etna/clients/janus/client.rb +19 -0
- data/lib/etna/clients/janus/models.rb +7 -1
- data/lib/etna/clients/janus/workflows.rb +1 -0
- data/lib/etna/clients/janus/workflows/generate_token_workflow.rb +77 -0
- data/lib/etna/clients/magma/workflows/file_linking_workflow.rb +3 -1
- data/lib/etna/command.rb +1 -0
- data/lib/etna/directed_graph.rb +62 -8
- data/lib/etna/route.rb +4 -0
- data/lib/helpers.rb +2 -2
- metadata +4 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 49dacbad5431a0004c77536e600b8f46ee544effb472a459cd9205cb6d3d0aed
|
|
4
|
+
data.tar.gz: 669d95414188d35adcff630545dde4d49caa43c064a7db3cfc19bf81fba6eff8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d1089f55be44686e14264f9b0df51b926a1ad758d40944010ca4fee40e69ced8d6be1cdaf452dc9ea6e05ab0fb099b597b6c4746f2bee400b090be4ec7a9ec56
|
|
7
|
+
data.tar.gz: d28be042a1210b12472a39502fa3ae8164ff4cd0ee3a2e0b552fb2f520ff5863d15cf88e7d66b9776aa6c7ecd54e1795e3527a16bdb5f7e6f860b944a87a20eb
|
data/etna.completion
CHANGED
|
@@ -32,7 +32,7 @@ arg_flag_completion_names="$arg_flag_completion_names "
|
|
|
32
32
|
multi_flags="$multi_flags "
|
|
33
33
|
while [[ "$#" != "0" ]]; do
|
|
34
34
|
if [[ "$#" == "1" ]]; then
|
|
35
|
-
all_completion_names="help models project"
|
|
35
|
+
all_completion_names="help models project token"
|
|
36
36
|
all_completion_names="$all_completion_names $all_flag_completion_names"
|
|
37
37
|
if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
|
|
38
38
|
return
|
|
@@ -722,6 +722,120 @@ else
|
|
|
722
722
|
return
|
|
723
723
|
fi
|
|
724
724
|
done
|
|
725
|
+
elif [[ "$1" == "token" ]]; then
|
|
726
|
+
shift
|
|
727
|
+
all_flag_completion_names="$all_flag_completion_names "
|
|
728
|
+
arg_flag_completion_names="$arg_flag_completion_names "
|
|
729
|
+
multi_flags="$multi_flags "
|
|
730
|
+
while [[ "$#" != "0" ]]; do
|
|
731
|
+
if [[ "$#" == "1" ]]; then
|
|
732
|
+
all_completion_names="generate help"
|
|
733
|
+
all_completion_names="$all_completion_names $all_flag_completion_names"
|
|
734
|
+
if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
|
|
735
|
+
return
|
|
736
|
+
fi
|
|
737
|
+
COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
|
|
738
|
+
return
|
|
739
|
+
elif [[ "$1" == "generate" ]]; then
|
|
740
|
+
shift
|
|
741
|
+
all_flag_completion_names="$all_flag_completion_names --task --project-name "
|
|
742
|
+
arg_flag_completion_names="$arg_flag_completion_names --project-name "
|
|
743
|
+
multi_flags="$multi_flags "
|
|
744
|
+
declare _completions_for_project_name="__project_name__"
|
|
745
|
+
while [[ "$#" != "0" ]]; do
|
|
746
|
+
if [[ "$#" == "1" ]]; then
|
|
747
|
+
all_completion_names=""
|
|
748
|
+
all_completion_names="$all_completion_names $all_flag_completion_names"
|
|
749
|
+
if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
|
|
750
|
+
return
|
|
751
|
+
fi
|
|
752
|
+
COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
|
|
753
|
+
return
|
|
754
|
+
elif [[ -z "$(echo $all_flag_completion_names | xargs)" ]]; then
|
|
755
|
+
return
|
|
756
|
+
elif [[ "$all_flag_completion_names" =~ $1\ ]]; then
|
|
757
|
+
if ! [[ "$multi_flags" =~ $1\ ]]; then
|
|
758
|
+
all_flag_completion_names="${all_flag_completion_names//$1\ /}"
|
|
759
|
+
fi
|
|
760
|
+
a=$1
|
|
761
|
+
shift
|
|
762
|
+
if [[ "$arg_flag_completion_names" =~ $a\ ]]; then
|
|
763
|
+
if [[ "$#" == "1" ]]; then
|
|
764
|
+
a="${a//--/}"
|
|
765
|
+
a="${a//-/_}"
|
|
766
|
+
i="_completions_for_$a"
|
|
767
|
+
all_completion_names="${!i}"
|
|
768
|
+
COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
|
|
769
|
+
return
|
|
770
|
+
fi
|
|
771
|
+
shift
|
|
772
|
+
fi
|
|
773
|
+
else
|
|
774
|
+
return
|
|
775
|
+
fi
|
|
776
|
+
done
|
|
777
|
+
return
|
|
778
|
+
elif [[ "$1" == "help" ]]; then
|
|
779
|
+
shift
|
|
780
|
+
all_flag_completion_names="$all_flag_completion_names "
|
|
781
|
+
arg_flag_completion_names="$arg_flag_completion_names "
|
|
782
|
+
multi_flags="$multi_flags "
|
|
783
|
+
while [[ "$#" != "0" ]]; do
|
|
784
|
+
if [[ "$#" == "1" ]]; then
|
|
785
|
+
all_completion_names=""
|
|
786
|
+
all_completion_names="$all_completion_names $all_flag_completion_names"
|
|
787
|
+
if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
|
|
788
|
+
return
|
|
789
|
+
fi
|
|
790
|
+
COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
|
|
791
|
+
return
|
|
792
|
+
elif [[ -z "$(echo $all_flag_completion_names | xargs)" ]]; then
|
|
793
|
+
return
|
|
794
|
+
elif [[ "$all_flag_completion_names" =~ $1\ ]]; then
|
|
795
|
+
if ! [[ "$multi_flags" =~ $1\ ]]; then
|
|
796
|
+
all_flag_completion_names="${all_flag_completion_names//$1\ /}"
|
|
797
|
+
fi
|
|
798
|
+
a=$1
|
|
799
|
+
shift
|
|
800
|
+
if [[ "$arg_flag_completion_names" =~ $a\ ]]; then
|
|
801
|
+
if [[ "$#" == "1" ]]; then
|
|
802
|
+
a="${a//--/}"
|
|
803
|
+
a="${a//-/_}"
|
|
804
|
+
i="_completions_for_$a"
|
|
805
|
+
all_completion_names="${!i}"
|
|
806
|
+
COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
|
|
807
|
+
return
|
|
808
|
+
fi
|
|
809
|
+
shift
|
|
810
|
+
fi
|
|
811
|
+
else
|
|
812
|
+
return
|
|
813
|
+
fi
|
|
814
|
+
done
|
|
815
|
+
return
|
|
816
|
+
elif [[ -z "$(echo $all_flag_completion_names | xargs)" ]]; then
|
|
817
|
+
return
|
|
818
|
+
elif [[ "$all_flag_completion_names" =~ $1\ ]]; then
|
|
819
|
+
if ! [[ "$multi_flags" =~ $1\ ]]; then
|
|
820
|
+
all_flag_completion_names="${all_flag_completion_names//$1\ /}"
|
|
821
|
+
fi
|
|
822
|
+
a=$1
|
|
823
|
+
shift
|
|
824
|
+
if [[ "$arg_flag_completion_names" =~ $a\ ]]; then
|
|
825
|
+
if [[ "$#" == "1" ]]; then
|
|
826
|
+
a="${a//--/}"
|
|
827
|
+
a="${a//-/_}"
|
|
828
|
+
i="_completions_for_$a"
|
|
829
|
+
all_completion_names="${!i}"
|
|
830
|
+
COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
|
|
831
|
+
return
|
|
832
|
+
fi
|
|
833
|
+
shift
|
|
834
|
+
fi
|
|
835
|
+
else
|
|
836
|
+
return
|
|
837
|
+
fi
|
|
838
|
+
done
|
|
725
839
|
elif [[ -z "$(echo $all_flag_completion_names | xargs)" ]]; then
|
|
726
840
|
return
|
|
727
841
|
elif [[ "$all_flag_completion_names" =~ $1\ ]]; then
|
data/lib/commands.rb
CHANGED
|
@@ -91,6 +91,36 @@ class EtnaApp
|
|
|
91
91
|
class Administrate
|
|
92
92
|
include Etna::CommandExecutor
|
|
93
93
|
|
|
94
|
+
class Token
|
|
95
|
+
include Etna::CommandExecutor
|
|
96
|
+
|
|
97
|
+
class Generate < Etna::Command
|
|
98
|
+
include WithLogger
|
|
99
|
+
|
|
100
|
+
boolean_flags << "--task"
|
|
101
|
+
string_flags << "--project-name"
|
|
102
|
+
string_flags << "--email"
|
|
103
|
+
|
|
104
|
+
def execute(email:, task: false, project_name: nil)
|
|
105
|
+
# the token is not required, but can be used if available
|
|
106
|
+
# to generate a task token, so we pass it in here
|
|
107
|
+
janus_client = Etna::Clients::Janus.new(
|
|
108
|
+
token: ENV['TOKEN'],
|
|
109
|
+
ignore_ssl: EtnaApp.instance.config(:ignore_ssl),
|
|
110
|
+
**EtnaApp.instance.config(:janus, EtnaApp.instance.environment))
|
|
111
|
+
|
|
112
|
+
generate_token_workflow = Etna::Clients::Janus::GenerateTokenWorkflow.new(
|
|
113
|
+
janus_client: janus_client,
|
|
114
|
+
token_type: task ? 'task' : 'login',
|
|
115
|
+
email: email,
|
|
116
|
+
project_name: project_name,
|
|
117
|
+
private_key_file: EtnaApp.instance.config(:private_key, EtnaApp.instance.environment)
|
|
118
|
+
)
|
|
119
|
+
generate_token_workflow.generate!
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
94
124
|
class Project
|
|
95
125
|
include Etna::CommandExecutor
|
|
96
126
|
|
data/lib/etna/auth.rb
CHANGED
|
@@ -70,6 +70,29 @@ module Etna
|
|
|
70
70
|
return route && route.noauth?
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
+
def janus_approved?(payload, token, request)
|
|
74
|
+
route = server.find_route(request)
|
|
75
|
+
|
|
76
|
+
# some routes don't need janus approval
|
|
77
|
+
return true if route && route.ignore_janus?
|
|
78
|
+
|
|
79
|
+
# only process task tokens right now
|
|
80
|
+
return true unless payload['task']
|
|
81
|
+
|
|
82
|
+
return false unless application.config(:janus) && application.config(:janus)[:host]
|
|
83
|
+
|
|
84
|
+
janus_client = Etna::Clients::Janus.new(
|
|
85
|
+
token: token,
|
|
86
|
+
host: application.config(:janus)[:host]
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
response = janus_client.validate_task_token()
|
|
90
|
+
|
|
91
|
+
return false unless response.code == '200'
|
|
92
|
+
|
|
93
|
+
return true
|
|
94
|
+
end
|
|
95
|
+
|
|
73
96
|
def approve_user(request)
|
|
74
97
|
token = request.cookies[application.config(:token_name)] || auth(request, :etna)
|
|
75
98
|
|
|
@@ -77,6 +100,8 @@ module Etna
|
|
|
77
100
|
|
|
78
101
|
begin
|
|
79
102
|
payload, header = application.sign.jwt_decode(token)
|
|
103
|
+
|
|
104
|
+
return false unless janus_approved?(payload, token, request)
|
|
80
105
|
return request.env['etna.user'] = Etna::User.new(payload.map{|k,v| [k.to_sym, v]}.to_h, token)
|
|
81
106
|
rescue
|
|
82
107
|
# bail out if anything goes wrong
|
data/lib/etna/client.rb
CHANGED
|
@@ -17,6 +17,13 @@ module Etna
|
|
|
17
17
|
|
|
18
18
|
attr_reader :routes
|
|
19
19
|
|
|
20
|
+
def with_headers(headers, &block)
|
|
21
|
+
@request_headers = headers.compact
|
|
22
|
+
result = instance_eval(&block)
|
|
23
|
+
@request_headers = nil
|
|
24
|
+
return result
|
|
25
|
+
end
|
|
26
|
+
|
|
20
27
|
def signed_route_path(route, params)
|
|
21
28
|
path = route_path(route,params)
|
|
22
29
|
|
|
@@ -111,7 +118,7 @@ module Etna
|
|
|
111
118
|
|
|
112
119
|
def body_request(type, endpoint, params = {}, &block)
|
|
113
120
|
uri = request_uri(endpoint)
|
|
114
|
-
req = type.new(uri.request_uri,
|
|
121
|
+
req = type.new(uri.request_uri, request_headers)
|
|
115
122
|
req.body = params.to_json
|
|
116
123
|
request(uri, req, &block)
|
|
117
124
|
end
|
|
@@ -124,7 +131,7 @@ module Etna
|
|
|
124
131
|
else
|
|
125
132
|
uri.query = URI.encode_www_form(params)
|
|
126
133
|
end
|
|
127
|
-
req = type.new(uri.request_uri,
|
|
134
|
+
req = type.new(uri.request_uri, request_headers)
|
|
128
135
|
request(uri, req, &block)
|
|
129
136
|
end
|
|
130
137
|
|
|
@@ -132,12 +139,14 @@ module Etna
|
|
|
132
139
|
URI("#{@host}#{endpoint}")
|
|
133
140
|
end
|
|
134
141
|
|
|
135
|
-
def
|
|
142
|
+
def request_headers
|
|
136
143
|
{
|
|
137
144
|
'Content-Type' => 'application/json',
|
|
138
145
|
'Accept' => 'application/json, text/*',
|
|
139
146
|
'Authorization' => "Etna #{@token}"
|
|
140
|
-
}
|
|
147
|
+
}.update(
|
|
148
|
+
@request_headers || {}
|
|
149
|
+
)
|
|
141
150
|
end
|
|
142
151
|
|
|
143
152
|
def status_check!(response)
|
|
@@ -8,10 +8,9 @@ module Etna
|
|
|
8
8
|
attr_reader :host, :token, :ignore_ssl
|
|
9
9
|
def initialize(host:, token:, ignore_ssl: false)
|
|
10
10
|
raise "#{self.class.name} client configuration is missing host." unless host
|
|
11
|
-
raise "#{self.class.name} client configuration is missing token." unless token
|
|
12
11
|
|
|
13
12
|
@token = token
|
|
14
|
-
raise "Your token is expired." if token_expired?
|
|
13
|
+
raise "Your token is expired." if token && token_expired?
|
|
15
14
|
|
|
16
15
|
@etna_client = ::Etna::Client.new(
|
|
17
16
|
host,
|
|
@@ -36,4 +35,4 @@ module Etna
|
|
|
36
35
|
end
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
|
-
end
|
|
38
|
+
end
|
data/lib/etna/clients/janus.rb
CHANGED
|
@@ -57,6 +57,25 @@ module Etna
|
|
|
57
57
|
|
|
58
58
|
TokenResponse.new(token)
|
|
59
59
|
end
|
|
60
|
+
|
|
61
|
+
def validate_task_token(validate_task_token_request = ValidateTaskTokenRequest.new)
|
|
62
|
+
token = nil
|
|
63
|
+
@etna_client.post('/api/tokens/task/validate', validate_task_token_request)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def get_nonce
|
|
67
|
+
@etna_client.get('/api/tokens/nonce').body
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def generate_token(token_type, signed_nonce: nil, project_name: nil)
|
|
71
|
+
response = @etna_client.with_headers(
|
|
72
|
+
'Authorization' => signed_nonce ? "Signed-Nonce #{signed_nonce}" : nil
|
|
73
|
+
) do
|
|
74
|
+
post('/api/tokens/generate', token_type: token_type, project_name: project_name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
response.body
|
|
78
|
+
end
|
|
60
79
|
end
|
|
61
80
|
end
|
|
62
81
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_relative './workflows/generate_token_workflow'
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Base workflow for setting up a project by a super user.
|
|
2
|
+
# 1) Creates the project in janus
|
|
3
|
+
# 2) Adds administrator(s) to Janus
|
|
4
|
+
# 3) Refreshes the user's token with the new privileges.
|
|
5
|
+
# 4) Creates the project in .
|
|
6
|
+
|
|
7
|
+
require 'base64'
|
|
8
|
+
require 'json'
|
|
9
|
+
require 'ostruct'
|
|
10
|
+
require_relative '../models'
|
|
11
|
+
|
|
12
|
+
module Etna
|
|
13
|
+
module Clients
|
|
14
|
+
class Janus
|
|
15
|
+
class GenerateTokenWorkflow < Struct.new(:janus_client, :email, :project_name, :token_type, :private_key_file, keyword_init: true)
|
|
16
|
+
def generate!
|
|
17
|
+
nonce = janus_client.get_nonce
|
|
18
|
+
|
|
19
|
+
unless email
|
|
20
|
+
puts "Email address for #{janus_client.host} account?"
|
|
21
|
+
email = STDIN.gets.chomp
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if use_nonce?
|
|
25
|
+
until private_key_file
|
|
26
|
+
puts "Location of private key file?"
|
|
27
|
+
private_key_file = ::File.expand_path(STDIN.gets.chomp)
|
|
28
|
+
unless File.exists?(private_key_file)
|
|
29
|
+
puts "No such file."
|
|
30
|
+
private_key_file = nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if needs_project_name?
|
|
36
|
+
puts "Project name?"
|
|
37
|
+
project_name = STDIN.gets.chomp
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
token = janus_client.generate_token(token_type, signed_nonce: use_nonce? ? signed_nonce(nonce) : nil, project_name: project_name)
|
|
41
|
+
|
|
42
|
+
puts token
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def signed_nonce(nonce)
|
|
48
|
+
private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file))
|
|
49
|
+
|
|
50
|
+
txt_to_sign = "#{nonce}.#{Base64.strict_encode64(email)}"
|
|
51
|
+
|
|
52
|
+
sig = Base64.strict_encode64(
|
|
53
|
+
private_key.sign(OpenSSL::Digest::SHA256.new,txt_to_sign)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
"#{txt_to_sign}.#{sig}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def use_nonce?
|
|
60
|
+
!task_token? || !janus_client.token
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def needs_project_name?
|
|
64
|
+
task_token? && !project_name
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def task_token?
|
|
68
|
+
token_type == 'task'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def user
|
|
72
|
+
@user ||= JSON.parse(Base64.urlsafe_decode64(magma_client.token.split('.')[1]))
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -95,7 +95,9 @@ module Etna
|
|
|
95
95
|
file_path = ::File.dirname(file_path)
|
|
96
96
|
{attribute_name => "https://metis.ucsf.edu/#{project_name}/browse/#{bucket_name}/#{file_path}"}
|
|
97
97
|
else
|
|
98
|
-
{attribute_name => {
|
|
98
|
+
{attribute_name => {
|
|
99
|
+
path: "metis://#{project_name}/#{bucket_name}/#{file_path}",
|
|
100
|
+
original_filename: File.basename(file_path)}}
|
|
99
101
|
end
|
|
100
102
|
end
|
|
101
103
|
|
data/lib/etna/command.rb
CHANGED
|
@@ -203,6 +203,7 @@ module Etna
|
|
|
203
203
|
@subcommands ||= self.class.constants.sort.reduce({}) do |acc, n|
|
|
204
204
|
acc.tap do
|
|
205
205
|
c = self.class.const_get(n)
|
|
206
|
+
next unless c.respond_to?(:instance_methods)
|
|
206
207
|
next unless c.instance_methods.include?(:find_command)
|
|
207
208
|
v = c.new(self)
|
|
208
209
|
acc[v.command_name] = v
|
data/lib/etna/directed_graph.rb
CHANGED
|
@@ -7,6 +7,59 @@ class DirectedGraph
|
|
|
7
7
|
attr_reader :children
|
|
8
8
|
attr_reader :parents
|
|
9
9
|
|
|
10
|
+
def full_parentage(n)
|
|
11
|
+
[].tap do |result|
|
|
12
|
+
q = @parents[n].keys.dup
|
|
13
|
+
seen = Set.new
|
|
14
|
+
|
|
15
|
+
until q.empty?
|
|
16
|
+
n = q.shift
|
|
17
|
+
next if seen.include?(n)
|
|
18
|
+
seen.add(n)
|
|
19
|
+
|
|
20
|
+
result << n
|
|
21
|
+
q.push(*@parents[n].keys)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
result.uniq!
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def as_normalized_hash(root, include_root = true)
|
|
29
|
+
q = [root]
|
|
30
|
+
{}.tap do |result|
|
|
31
|
+
if include_root
|
|
32
|
+
result[root] = []
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
seen = Set.new
|
|
36
|
+
|
|
37
|
+
until q.empty?
|
|
38
|
+
n = q.shift
|
|
39
|
+
next if seen.include?(n)
|
|
40
|
+
seen.add(n)
|
|
41
|
+
|
|
42
|
+
parentage = full_parentage(n)
|
|
43
|
+
|
|
44
|
+
@children[n].keys.each do |child_node|
|
|
45
|
+
q << child_node
|
|
46
|
+
|
|
47
|
+
if result.include?(n)
|
|
48
|
+
result[n] << child_node
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
parentage.each do |grandparent|
|
|
52
|
+
result[grandparent] << child_node if result.include?(grandparent)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
result[child_node] = []
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
result.values.each(&:uniq!)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
10
63
|
def add_connection(parent, child)
|
|
11
64
|
children = @children[parent] ||= {}
|
|
12
65
|
child_children = @children[child] ||= {}
|
|
@@ -18,12 +71,13 @@ class DirectedGraph
|
|
|
18
71
|
parents[parent] = parent_parents
|
|
19
72
|
end
|
|
20
73
|
|
|
21
|
-
def serialized_path_from(root)
|
|
74
|
+
def serialized_path_from(root, include_root = true)
|
|
22
75
|
seen = Set.new
|
|
23
76
|
[].tap do |result|
|
|
24
|
-
result << root
|
|
77
|
+
result << root if include_root
|
|
25
78
|
seen.add(root)
|
|
26
|
-
path_q = paths_from(root)
|
|
79
|
+
path_q = paths_from(root, include_root)
|
|
80
|
+
traversables = path_q.flatten
|
|
27
81
|
|
|
28
82
|
until path_q.empty?
|
|
29
83
|
next_path = path_q.shift
|
|
@@ -34,7 +88,7 @@ class DirectedGraph
|
|
|
34
88
|
next if next_n.nil?
|
|
35
89
|
next if seen.include?(next_n)
|
|
36
90
|
|
|
37
|
-
if @parents[next_n].keys.any? { |p| !seen.include?(p) }
|
|
91
|
+
if @parents[next_n].keys.any? { |p| !seen.include?(p) && traversables.include?(p) }
|
|
38
92
|
next_path.unshift(next_n)
|
|
39
93
|
path_q.push(next_path)
|
|
40
94
|
break
|
|
@@ -47,9 +101,9 @@ class DirectedGraph
|
|
|
47
101
|
end
|
|
48
102
|
end
|
|
49
103
|
|
|
50
|
-
def paths_from(root)
|
|
104
|
+
def paths_from(root, include_root = true)
|
|
51
105
|
[].tap do |result|
|
|
52
|
-
parents_of_map = descendants(root)
|
|
106
|
+
parents_of_map = descendants(root, include_root)
|
|
53
107
|
seen = Set.new
|
|
54
108
|
|
|
55
109
|
parents_of_map.to_a.sort_by { |k, parents| [-parents.length, k.inspect] }.each do |k, parents|
|
|
@@ -68,7 +122,7 @@ class DirectedGraph
|
|
|
68
122
|
end
|
|
69
123
|
end
|
|
70
124
|
|
|
71
|
-
def descendants(parent)
|
|
125
|
+
def descendants(parent, include_root = true)
|
|
72
126
|
seen = Set.new
|
|
73
127
|
|
|
74
128
|
seen.add(parent)
|
|
@@ -90,7 +144,7 @@ class DirectedGraph
|
|
|
90
144
|
while child = queue.pop
|
|
91
145
|
next if seen.include? child
|
|
92
146
|
seen.add(child)
|
|
93
|
-
path = (paths[child] ||= [parent])
|
|
147
|
+
path = (paths[child] ||= (include_root ? [parent] : []))
|
|
94
148
|
|
|
95
149
|
@children[child].keys.each do |child_child|
|
|
96
150
|
queue.push child_child
|
data/lib/etna/route.rb
CHANGED
data/lib/helpers.rb
CHANGED
|
@@ -57,9 +57,9 @@ module WithEtnaClients
|
|
|
57
57
|
**EtnaApp.instance.config(:metis, environment) || {})
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
def janus_client
|
|
60
|
+
def janus_client(opts={})
|
|
61
61
|
@janus_client ||= Etna::Clients::Janus.new(
|
|
62
|
-
token: token,
|
|
62
|
+
token: opts.has_key?(:token) ? opts[:token] : token,
|
|
63
63
|
ignore_ssl: EtnaApp.instance.config(:ignore_ssl),
|
|
64
64
|
**EtnaApp.instance.config(:janus, environment) || {})
|
|
65
65
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: etna
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.33
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Saurabh Asthana
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-04-
|
|
11
|
+
date: 2021-04-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|
|
@@ -94,20 +94,6 @@ dependencies:
|
|
|
94
94
|
- - ">="
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '0'
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: concurrent-ruby-ext
|
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
|
100
|
-
requirements:
|
|
101
|
-
- - ">="
|
|
102
|
-
- !ruby/object:Gem::Version
|
|
103
|
-
version: '0'
|
|
104
|
-
type: :runtime
|
|
105
|
-
prerelease: false
|
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
-
requirements:
|
|
108
|
-
- - ">="
|
|
109
|
-
- !ruby/object:Gem::Version
|
|
110
|
-
version: '0'
|
|
111
97
|
description: See summary
|
|
112
98
|
email: Saurabh.Asthana@ucsf.edu
|
|
113
99
|
executables:
|
|
@@ -131,6 +117,8 @@ files:
|
|
|
131
117
|
- lib/etna/clients/janus.rb
|
|
132
118
|
- lib/etna/clients/janus/client.rb
|
|
133
119
|
- lib/etna/clients/janus/models.rb
|
|
120
|
+
- lib/etna/clients/janus/workflows.rb
|
|
121
|
+
- lib/etna/clients/janus/workflows/generate_token_workflow.rb
|
|
134
122
|
- lib/etna/clients/magma.rb
|
|
135
123
|
- lib/etna/clients/magma/client.rb
|
|
136
124
|
- lib/etna/clients/magma/formatting.rb
|