etna 0.1.15 → 0.1.21

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/bin/etna +18 -0
  3. data/etna.completion +1001 -0
  4. data/etna_app.completion +133 -0
  5. data/ext/completions/extconf.rb +20 -0
  6. data/lib/commands.rb +395 -0
  7. data/lib/etna.rb +7 -0
  8. data/lib/etna/application.rb +46 -22
  9. data/lib/etna/client.rb +82 -48
  10. data/lib/etna/clients.rb +4 -0
  11. data/lib/etna/clients/enum.rb +9 -0
  12. data/lib/etna/clients/janus.rb +2 -0
  13. data/lib/etna/clients/janus/client.rb +73 -0
  14. data/lib/etna/clients/janus/models.rb +78 -0
  15. data/lib/etna/clients/magma.rb +4 -0
  16. data/lib/etna/clients/magma/client.rb +80 -0
  17. data/lib/etna/clients/magma/formatting.rb +1 -0
  18. data/lib/etna/clients/magma/formatting/models_csv.rb +354 -0
  19. data/lib/etna/clients/magma/models.rb +630 -0
  20. data/lib/etna/clients/magma/workflows.rb +10 -0
  21. data/lib/etna/clients/magma/workflows/add_project_models_workflow.rb +67 -0
  22. data/lib/etna/clients/magma/workflows/attribute_actions_from_json_workflow.rb +62 -0
  23. data/lib/etna/clients/magma/workflows/create_project_workflow.rb +123 -0
  24. data/lib/etna/clients/magma/workflows/crud_workflow.rb +85 -0
  25. data/lib/etna/clients/magma/workflows/ensure_containing_record_workflow.rb +44 -0
  26. data/lib/etna/clients/magma/workflows/file_attributes_blank_workflow.rb +68 -0
  27. data/lib/etna/clients/magma/workflows/file_linking_workflow.rb +115 -0
  28. data/lib/etna/clients/magma/workflows/json_converters.rb +81 -0
  29. data/lib/etna/clients/magma/workflows/json_validators.rb +452 -0
  30. data/lib/etna/clients/magma/workflows/model_synchronization_workflow.rb +306 -0
  31. data/lib/etna/clients/magma/workflows/record_synchronization_workflow.rb +63 -0
  32. data/lib/etna/clients/magma/workflows/update_attributes_from_csv_workflow.rb +246 -0
  33. data/lib/etna/clients/metis.rb +3 -0
  34. data/lib/etna/clients/metis/client.rb +239 -0
  35. data/lib/etna/clients/metis/models.rb +313 -0
  36. data/lib/etna/clients/metis/workflows.rb +2 -0
  37. data/lib/etna/clients/metis/workflows/metis_download_workflow.rb +37 -0
  38. data/lib/etna/clients/metis/workflows/metis_upload_workflow.rb +137 -0
  39. data/lib/etna/clients/polyphemus.rb +3 -0
  40. data/lib/etna/clients/polyphemus/client.rb +33 -0
  41. data/lib/etna/clients/polyphemus/models.rb +68 -0
  42. data/lib/etna/clients/polyphemus/workflows.rb +1 -0
  43. data/lib/etna/clients/polyphemus/workflows/set_configuration_workflow.rb +47 -0
  44. data/lib/etna/command.rb +243 -5
  45. data/lib/etna/controller.rb +4 -0
  46. data/lib/etna/csvs.rb +159 -0
  47. data/lib/etna/directed_graph.rb +56 -0
  48. data/lib/etna/environment_scoped.rb +19 -0
  49. data/lib/etna/errors.rb +6 -0
  50. data/lib/etna/generate_autocompletion_script.rb +131 -0
  51. data/lib/etna/json_serializable_struct.rb +37 -0
  52. data/lib/etna/logger.rb +24 -2
  53. data/lib/etna/multipart_serializable_nested_hash.rb +50 -0
  54. data/lib/etna/route.rb +1 -1
  55. data/lib/etna/server.rb +3 -0
  56. data/lib/etna/spec/vcr.rb +99 -0
  57. data/lib/etna/templates/attribute_actions_template.json +43 -0
  58. data/lib/etna/test_auth.rb +3 -1
  59. data/lib/etna/user.rb +4 -0
  60. data/lib/helpers.rb +90 -0
  61. metadata +70 -5
@@ -15,3 +15,10 @@ require_relative './etna/describe_routes'
15
15
  require_relative './etna/client'
16
16
  require_relative './etna/symbolize_params'
17
17
  require_relative './etna/spec'
18
+ require_relative './etna/clients'
19
+ require_relative './etna/csvs'
20
+ require_relative './etna/environment_scoped'
21
+
22
+ class EtnaApp
23
+ include Etna::Application
24
+ end
@@ -4,17 +4,31 @@
4
4
  # whenever we want to use it as a container
5
5
 
6
6
  require_relative './sign_service'
7
+ require_relative './command'
8
+ require_relative './generate_autocompletion_script'
7
9
  require 'singleton'
10
+ require 'rollbar'
8
11
 
9
12
  module Etna::Application
10
13
  def self.included(other)
11
14
  other.include Singleton
15
+ other.include Etna::CommandExecutor
16
+ @@application = other
17
+
18
+ other.const_set(:GenerateCompletionScript, Class.new(Etna::GenerateCompletionScript))
12
19
  end
13
20
 
14
21
  def self.find(klass)
15
- Kernel.const_get(
16
- klass.name.split('::').first
17
- ).instance
22
+ namespace = klass.name.split('::').first
23
+ if (namespace_klass = Kernel.const_get(namespace)) && (namespace_klass.respond_to? :instance)
24
+ return namespace_klass.instance
25
+ end
26
+
27
+ if @@application
28
+ return @@application.instance
29
+ end
30
+
31
+ raise "Could not find application instance from #{namespace}, and not subclass of Application found."
18
32
  end
19
33
 
20
34
  def self.register(app)
@@ -31,6 +45,12 @@ module Etna::Application
31
45
 
32
46
  def configure(opts)
33
47
  @config = opts
48
+
49
+ if (rollbar_config = config(:rollbar)) && rollbar_config[:access_token]
50
+ Rollbar.configure do |config|
51
+ config.access_token = rollbar_config[:access_token]
52
+ end
53
+ end
34
54
  end
35
55
 
36
56
  def setup_logger
@@ -40,18 +60,27 @@ module Etna::Application
40
60
  # Number of old copies of the log to keep.
41
61
  config(:log_copies) || 5,
42
62
  # How large the log can get before overturning.
43
- config(:log_size) || 1048576
63
+ config(:log_size) || 1048576,
44
64
  )
45
65
  log_level = (config(:log_level) || 'warn').upcase.to_sym
46
-
47
66
  @logger.level = Logger.const_defined?(log_level) ? Logger.const_get(log_level) : Logger::WARN
48
67
  end
49
68
 
50
69
  # the application logger is available globally
51
70
  attr_reader :logger
52
71
 
53
- def config(type)
54
- @config[environment][type]
72
+ def config(type, env = environment)
73
+ return nil if @config.nil?
74
+ return nil if @config[env].nil?
75
+ return nil unless @config[env].is_a?(Hash)
76
+ @config[env][type]
77
+ end
78
+
79
+ def env_config(env = environment)
80
+ return nil if @config.nil?
81
+ return nil if @config[env].nil?
82
+ return nil unless @config[env].is_a?(Hash)
83
+ @config[env]
55
84
  end
56
85
 
57
86
  def sign
@@ -68,23 +97,18 @@ module Etna::Application
68
97
  end
69
98
  end
70
99
 
71
- def run_command(config, cmd = :help, *args)
72
- cmd = cmd.to_sym
73
- if commands.key?(cmd)
74
- commands[cmd].setup(config)
75
- commands[cmd].execute(*args)
76
- else
77
- commands[:help].execute
100
+ def run_command(config, *args, &block)
101
+ cmd, cmd_args, cmd_kwds = find_command(*args)
102
+ cmd.setup(config)
103
+
104
+ if block_given?
105
+ return unless yield [cmd, cmd_args]
78
106
  end
79
- end
80
107
 
81
- def commands
82
- @commands ||= Hash[
83
- find_descendents(Etna::Command).map do |c|
84
- cmd = c.new
85
- [ cmd.name, cmd ]
86
- end
87
- ]
108
+ cmd.execute(*cmd.fill_in_missing_params(cmd_args), **cmd_kwds)
109
+ rescue => e
110
+ Rollbar.error(e)
111
+ raise
88
112
  end
89
113
  end
90
114
 
@@ -1,16 +1,20 @@
1
1
  require 'net/http/persistent'
2
2
  require 'net/http/post/multipart'
3
3
  require 'singleton'
4
+ require 'rack/utils'
4
5
 
5
6
  module Etna
6
7
  class Client
7
- def initialize(host, token)
8
- @host = host.sub(%r!/$!,'')
8
+ def initialize(host, token, routes_available: true, persistent: true, ignore_ssl: false)
9
+ @host = host.sub(%r!/$!, '')
9
10
  @token = token
11
+ @persistent = persistent
12
+ @ignore_ssl = ignore_ssl
10
13
 
11
- set_routes
12
-
13
- define_route_helpers
14
+ if routes_available
15
+ set_routes
16
+ define_route_helpers
17
+ end
14
18
  end
15
19
 
16
20
  attr_reader :routes
@@ -19,6 +23,29 @@ module Etna
19
23
  Etna::Route.path(route[:route], params)
20
24
  end
21
25
 
26
+ def multipart_post(endpoint, content, &block)
27
+ uri = request_uri(endpoint)
28
+ multipart = Net::HTTP::Post::Multipart.new uri.request_uri, content
29
+ multipart.add_field('Authorization', "Etna #{@token}")
30
+ request(uri, multipart, &block)
31
+ end
32
+
33
+ def post(endpoint, params = {}, &block)
34
+ body_request(Net::HTTP::Post, endpoint, params, &block)
35
+ end
36
+
37
+ def get(endpoint, params = {}, &block)
38
+ query_request(Net::HTTP::Get, endpoint, params, &block)
39
+ end
40
+
41
+ def options(endpoint, params = {}, &block)
42
+ query_request(Net::HTTP::Options, endpoint, params, &block)
43
+ end
44
+
45
+ def delete(endpoint, params = {}, &block)
46
+ body_request(Net::HTTP::Delete, endpoint, params, &block)
47
+ end
48
+
22
49
  private
23
50
 
24
51
  def set_routes
@@ -30,12 +57,12 @@ module Etna
30
57
  def define_route_helpers
31
58
  @routes.each do |route|
32
59
  next unless route[:name]
33
- self.define_singleton_method(route[:name]) do |params={}|
60
+ self.define_singleton_method(route[:name]) do |params = {}|
34
61
 
35
62
  missing_params = (route[:params] - params.keys.map(&:to_s))
36
63
  unless missing_params.empty?
37
64
  raise ArgumentError, "Missing required #{missing_params.size > 1 ?
38
- 'params' : 'param'} #{missing_params.join(', ')}"
65
+ 'params' : 'param'} #{missing_params.join(', ')}"
39
66
  end
40
67
 
41
68
  response = send(route[:method].downcase, route_path(route, params), params)
@@ -54,45 +81,29 @@ module Etna
54
81
 
55
82
  def persistent_connection
56
83
  @http ||= begin
57
- http = Net::HTTP::Persistent.new
58
- http.read_timeout = 3600
59
- http
60
- end
61
- end
62
-
63
- def multipart_post(endpoint, content, &block)
64
- uri = request_uri(endpoint)
65
- multipart = Net::HTTP::Post::Multipart.new uri.path, content
66
- multipart.add_field('Authorization', "Etna #{@token}")
67
- request(uri, multipart, &block)
68
- end
69
-
70
- def post(endpoint, params={}, &block)
71
- body_request(Net::HTTP::Post, endpoint, params, &block)
72
- end
73
-
74
- def get(endpoint, params={}, &block)
75
- query_request(Net::HTTP::Get, endpoint, params, &block)
76
- end
77
-
78
- def options(endpoint, params={}, &block)
79
- query_request(Net::HTTP::Options, endpoint, params, &block)
84
+ http = Net::HTTP::Persistent.new
85
+ http.read_timeout = 3600
86
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @ignore_ssl
87
+ http
88
+ end
80
89
  end
81
90
 
82
- def delete(endpoint, params={}, &block)
83
- body_request(Net::HTTP::Delete, endpoint, params, &block)
84
- end
85
91
 
86
- def body_request(type, endpoint, params={}, &block)
92
+ def body_request(type, endpoint, params = {}, &block)
87
93
  uri = request_uri(endpoint)
88
- req = type.new(uri.request_uri,request_params)
94
+ req = type.new(uri.request_uri, request_params)
89
95
  req.body = params.to_json
90
96
  request(uri, req, &block)
91
97
  end
92
98
 
93
- def query_request(type, endpoint, params={}, &block)
99
+ def query_request(type, endpoint, params = {}, &block)
94
100
  uri = request_uri(endpoint)
95
- uri.query = URI.encode_www_form(params)
101
+
102
+ if uri.query
103
+ uri.query += "&" + URI.encode_www_form(params)
104
+ else
105
+ uri.query = URI.encode_www_form(params)
106
+ end
96
107
  req = type.new(uri.request_uri, request_params)
97
108
  request(uri, req, &block)
98
109
  end
@@ -103,9 +114,9 @@ module Etna
103
114
 
104
115
  def request_params
105
116
  {
106
- 'Content-Type' => 'application/json',
107
- 'Accept'=> 'application/json, text/*',
108
- 'Authorization'=>"Etna #{@token}"
117
+ 'Content-Type' => 'application/json',
118
+ 'Accept' => 'application/json, text/*',
119
+ 'Authorization' => "Etna #{@token}"
109
120
  }
110
121
  end
111
122
 
@@ -113,8 +124,8 @@ module Etna
113
124
  status = response.code.to_i
114
125
  if status >= 400
115
126
  msg = response.content_type == 'application/json' ?
116
- json_error(response.body) :
117
- response.body
127
+ json_error(response.body) :
128
+ response.body
118
129
  raise Etna::Error.new(msg, status)
119
130
  end
120
131
  end
@@ -130,14 +141,37 @@ module Etna
130
141
 
131
142
  def request(uri, data)
132
143
  if block_given?
133
- persistent_connection.request(uri, data) do |response|
134
- status_check!(response)
135
- yield response
144
+ if @persistent
145
+ persistent_connection.request(uri, data) do |response|
146
+ status_check!(response)
147
+ yield response
148
+ end
149
+ else
150
+ verify_mode = @ignore_ssl ?
151
+ OpenSSL::SSL::VERIFY_NONE :
152
+ OpenSSL::SSL::VERIFY_PEER
153
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true, verify_mode: verify_mode) do |http|
154
+ http.request(data) do |response|
155
+ status_check!(response)
156
+ yield response
157
+ end
158
+ end
136
159
  end
137
160
  else
138
- response = persistent_connection.request(uri, data)
139
- status_check!(response)
140
- return response
161
+ if @persistent
162
+ response = persistent_connection.request(uri, data)
163
+ status_check!(response)
164
+ return response
165
+ else
166
+ verify_mode = @ignore_ssl ?
167
+ OpenSSL::SSL::VERIFY_NONE :
168
+ OpenSSL::SSL::VERIFY_PEER
169
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true, verify_mode: verify_mode) do |http|
170
+ response = http.request(data)
171
+ status_check!(response)
172
+ return response
173
+ end
174
+ end
141
175
  end
142
176
  end
143
177
  end
@@ -0,0 +1,4 @@
1
+ require_relative 'clients/magma'
2
+ require_relative 'clients/metis'
3
+ require_relative 'clients/janus'
4
+ require_relative 'clients/polyphemus'
@@ -0,0 +1,9 @@
1
+ module Enum
2
+ def self.included(cls)
3
+ cls.instance_eval do
4
+ def entries
5
+ self.constants.map { |c| self.const_get(c) }.select { |v| v.instance_of?(self) }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ require_relative './janus/client'
2
+ require_relative './janus/models'
@@ -0,0 +1,73 @@
1
+ require 'net/http/persistent'
2
+ require 'net/http/post/multipart'
3
+ require 'singleton'
4
+ require_relative '../../client'
5
+ require_relative './models'
6
+
7
+ module Etna
8
+ module Clients
9
+ class Janus
10
+ def initialize(host:, token:, persistent: true, ignore_ssl: false)
11
+ raise 'Janus client configuration is missing host.' unless host
12
+ raise 'Janus client configuration is missing token.' unless token
13
+ @etna_client = ::Etna::Client.new(
14
+ host,
15
+ token,
16
+ routes_available: false,
17
+ persistent: persistent,
18
+ ignore_ssl: ignore_ssl)
19
+ end
20
+
21
+ def get_project(get_project_request = GetProjectRequest.new)
22
+ html = nil
23
+ @etna_client.get(
24
+ "/project/#{get_project_request.project_name}",
25
+ get_project_request) do |res|
26
+ html = res.body
27
+ end
28
+
29
+ HtmlResponse.new(html)
30
+ end
31
+
32
+ def add_project(add_project_request = AddProjectRequest.new)
33
+ @etna_client.post('/add_project', add_project_request) do |res|
34
+ # Redirect, no response data
35
+ end
36
+ end
37
+
38
+ def add_user(add_user_request = AddUserRequest.new)
39
+ @etna_client.post(
40
+ "/add_user/#{add_user_request.project_name}",
41
+ add_user_request) do |res|
42
+ # Redirect, no response data
43
+ end
44
+ end
45
+
46
+ def update_permission(update_permission_request = UpdatePermissionRequest.new)
47
+ @etna_client.post(
48
+ "/update_permission/#{update_permission_request.project_name}",
49
+ update_permission_request) do |res|
50
+ # Redirect, no response data
51
+ end
52
+ end
53
+
54
+ def refresh_token(refresh_token_request = RefreshTokenRequest.new)
55
+ token = nil
56
+ @etna_client.get('/refresh_token', refresh_token_request) do |res|
57
+ token = res.body
58
+ end
59
+
60
+ TokenResponse.new(token)
61
+ end
62
+
63
+ def viewer_token(viewer_token_request = ViewerTokenRequest.new)
64
+ token = nil
65
+ @etna_client.get('/viewer_token', viewer_token_request) do |res|
66
+ token = res.body
67
+ end
68
+
69
+ TokenResponse.new(token)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,78 @@
1
+ require 'ostruct'
2
+ require_relative '../../json_serializable_struct'
3
+
4
+ # TODO: In the near future, I'd like to transition to specifying apis via SWAGGER and generating model stubs from the
5
+ # common definitions. For nowe I've written them out by hand here.
6
+ module Etna
7
+ module Clients
8
+ class Janus
9
+ class GetProjectRequest < Struct.new(:project_name, keyword_init: true)
10
+ include JsonSerializableStruct
11
+
12
+ def initialize(**params)
13
+ super({}.update(params))
14
+ end
15
+ end
16
+
17
+ class AddProjectRequest < Struct.new(:project_name, :project_name_full, keyword_init: true)
18
+ include JsonSerializableStruct
19
+
20
+ def initialize(**params)
21
+ super({}.update(params))
22
+ end
23
+ end
24
+
25
+ class AddUserRequest < Struct.new(:project_name, :email, :name, :role, :privileged, :affiliation, keyword_init: true)
26
+ include JsonSerializableStruct
27
+
28
+ def initialize(**params)
29
+ super({privileged: false, affiliation: ''}.update(params))
30
+ end
31
+ end
32
+
33
+ class UpdatePermissionRequest < Struct.new(:project_name, :email, :role, :privileged, :affiliation, keyword_init: true)
34
+ include JsonSerializableStruct
35
+
36
+ def initialize(**params)
37
+ super({privileged: false, affiliation: ''}.update(params))
38
+ end
39
+ end
40
+
41
+ class RefreshTokenRequest
42
+ def map
43
+ []
44
+ end
45
+ end
46
+
47
+ class ViewerTokenRequest
48
+ def map
49
+ []
50
+ end
51
+ end
52
+
53
+ class HtmlResponse
54
+ attr_reader :raw
55
+
56
+ def initialize(raw = '')
57
+ @raw = raw
58
+ end
59
+
60
+ def html
61
+ @raw
62
+ end
63
+ end
64
+
65
+ class TokenResponse
66
+ attr_reader :raw
67
+
68
+ def initialize(raw = '')
69
+ @raw = raw
70
+ end
71
+
72
+ def token
73
+ @raw
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end