polyseerio 0.0.1

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 (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +12 -0
  4. data/Gemfile +4 -0
  5. data/HISTORY.md +3 -0
  6. data/LICENSE +21 -0
  7. data/Makefile +43 -0
  8. data/README.md +307 -0
  9. data/lib/agent/agent.rb +35 -0
  10. data/lib/agent/default_config.rb +51 -0
  11. data/lib/agent/enum.rb +35 -0
  12. data/lib/agent/executor.rb +62 -0
  13. data/lib/agent/handler/event.rb +32 -0
  14. data/lib/agent/handler/expectation.rb +10 -0
  15. data/lib/agent/handler/fact.rb +18 -0
  16. data/lib/agent/handler/index.rb +15 -0
  17. data/lib/agent/handler/interface.rb +11 -0
  18. data/lib/agent/handler/metric.rb +23 -0
  19. data/lib/agent/handler/process.rb +10 -0
  20. data/lib/agent/helper.rb +137 -0
  21. data/lib/client.rb +47 -0
  22. data/lib/constant.rb +12 -0
  23. data/lib/enum.rb +82 -0
  24. data/lib/helper.rb +153 -0
  25. data/lib/middleware.rb +51 -0
  26. data/lib/polyseerio.rb +115 -0
  27. data/lib/request.rb +84 -0
  28. data/lib/resource/base.rb +73 -0
  29. data/lib/resource/definition.rb +166 -0
  30. data/lib/resource/factory.rb +149 -0
  31. data/lib/resource/helper.rb +91 -0
  32. data/lib/resource/routine.rb +26 -0
  33. data/lib/response.rb +27 -0
  34. data/lib/sdk/factory.rb +34 -0
  35. data/lib/sdk/helper.rb +50 -0
  36. data/lib/sdk/method/add_fact.rb +14 -0
  37. data/lib/sdk/method/add_gauge.rb +14 -0
  38. data/lib/sdk/method/attach.rb +26 -0
  39. data/lib/sdk/method/check.rb +11 -0
  40. data/lib/sdk/method/detach.rb +11 -0
  41. data/lib/sdk/method/execute.rb +11 -0
  42. data/lib/sdk/method/fact.rb +11 -0
  43. data/lib/sdk/method/gauge.rb +11 -0
  44. data/lib/sdk/method/index.rb +10 -0
  45. data/lib/sdk/method/message.rb +11 -0
  46. data/lib/sdk/method/remove.rb +11 -0
  47. data/lib/sdk/method/save.rb +32 -0
  48. data/lib/sdk/method/to_json.rb +11 -0
  49. data/lib/sdk/method/trigger.rb +17 -0
  50. data/lib/sdk/static/attach.rb +11 -0
  51. data/lib/sdk/static/check.rb +11 -0
  52. data/lib/sdk/static/create.rb +21 -0
  53. data/lib/sdk/static/detach.rb +11 -0
  54. data/lib/sdk/static/execute.rb +11 -0
  55. data/lib/sdk/static/find.rb +20 -0
  56. data/lib/sdk/static/find_by_id.rb +21 -0
  57. data/lib/sdk/static/find_by_name.rb +28 -0
  58. data/lib/sdk/static/index.rb +10 -0
  59. data/lib/sdk/static/message.rb +15 -0
  60. data/lib/sdk/static/remove.rb +21 -0
  61. data/lib/sdk/static/trigger.rb +17 -0
  62. data/lib/sdk/static/update.rb +18 -0
  63. data/lib/url_builder.rb +55 -0
  64. data/polyseerio.gemspec +32 -0
  65. metadata +205 -0
@@ -0,0 +1,153 @@
1
+ require 'inflection'
2
+
3
+ module Polyseerio
4
+ # General helper functions for SDK
5
+ module Helper
6
+ DEFAULT_REQUIRE_DIRECTORY_OPTIONS = {
7
+ exclude: ['index'].freeze
8
+ }.freeze
9
+
10
+ # Simple conversion to seconds from ms.
11
+ def self.ms_to_seconds(ms)
12
+ ms / 1000.0
13
+ end
14
+
15
+ # Given directory and module a map of module procs will be created.
16
+ # TODO: this is really a dir func map not a proc map
17
+ def self.dir_proc_map(dir, mod)
18
+ map = Polyseerio::Helper.dir_to_path_map dir
19
+
20
+ map.each { |(_, path)| require path }
21
+
22
+ map.each_with_object({}, &Helper.add_to_proc_map(mod))
23
+ end
24
+
25
+ # Adds a proc method to an accumulator by its name.
26
+ # TODO: this is really a dir func map not always a proc map.
27
+ def self.add_to_proc_map(*args)
28
+ proc do |mod, (name, _), acc|
29
+ if mod.respond_to? name
30
+ result = mod.send name
31
+
32
+ acc[name] = result unless result.nil?
33
+ end
34
+
35
+ acc
36
+ end.curry.call(*args)
37
+ end
38
+
39
+ # Convert resource string to resource type.
40
+ def self.resource_to_type(resource)
41
+ Inflection.singular(resource)
42
+ end
43
+
44
+ # A memoize function that has an optional cache key.
45
+ def self.memoize_function(func, get_key)
46
+ lambda do
47
+ results = {}
48
+
49
+ proc do |*args|
50
+ key = get_key.call(*args) # TODO: assert key is sym?
51
+
52
+ if results.key? key
53
+ results.fetch key
54
+ else
55
+ result = func.call(*args)
56
+
57
+ results[key] = result
58
+
59
+ result
60
+ end
61
+ end
62
+ end.call
63
+ end
64
+
65
+ # Simple identity function.
66
+ def self.identity(value)
67
+ proc { |x| x }.call(value)
68
+ end
69
+
70
+ # Maps filename to file path
71
+ def self.dir_to_path_map(directory, options = {})
72
+ directory = "#{directory}/*#{options[:extension]}"
73
+ options = defaults(options, DEFAULT_REQUIRE_DIRECTORY_OPTIONS)
74
+
75
+ paths = Dir[directory].select do |file|
76
+ name = File.basename(file, '.*')
77
+
78
+ !options[:exclude].include? name
79
+ end
80
+
81
+ paths.each_with_object({}) do |file, acc|
82
+ name = File.basename(file, '.*')
83
+
84
+ acc[name.to_sym] = file
85
+
86
+ acc
87
+ end
88
+ end
89
+
90
+ # Load an include an entire directory.
91
+ def self.require_directory(directory, options = {})
92
+ directory = "#{directory}/*#{options[:extension]}"
93
+ options = defaults(options, DEFAULT_REQUIRE_DIRECTORY_OPTIONS)
94
+
95
+ Dir[directory].select do |file|
96
+ pathname = Pathname.new(file)
97
+
98
+ !options[:exclude].include? pathname.basename
99
+ end
100
+ end
101
+
102
+ # Format a resouce payload for API consumption
103
+ def self.format_payload(payload)
104
+ { data: { attributes: payload.clone } }
105
+ end
106
+
107
+ # Attempt to geta token.
108
+ def self.resolve_token(options)
109
+ return options[:token] unless options[:token].nil?
110
+
111
+ if ENV.key? options[:token_env]
112
+ value = ENV.fetch(options[:token_env], nil)
113
+
114
+ return value unless value.nil?
115
+ end
116
+
117
+ nil
118
+ end
119
+
120
+ # Generates default options.
121
+ def self.defaults(options, *defaults)
122
+ result = {}
123
+
124
+ defaults.reverse_each do |opts|
125
+ result.merge!(opts)
126
+ end
127
+
128
+ result.merge!(options)
129
+ end
130
+
131
+ # Used to attach a method to an instance
132
+ def self.attach_to_instance!(*args)
133
+ lambda do |instance, (key, value)|
134
+ instance.instance_eval do
135
+ define_singleton_method(key, proc { value })
136
+ end
137
+ end.curry.call(*args)
138
+ end
139
+
140
+ # Rekey a hash using a remapping hash.
141
+ def self.rekey(hash, map)
142
+ hash.each_with_object({}) do |(key, value), acc|
143
+ if map.key? key
144
+ acc[map[key]] = value
145
+ else
146
+ acc[key] = value
147
+ end
148
+
149
+ acc
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,51 @@
1
+ require 'helper'
2
+ require 'json'
3
+ require 'response'
4
+ require 'resource/helper'
5
+
6
+ module Polyseerio
7
+ module Middleware
8
+ # Pre request middleware.
9
+ module Pre
10
+ # Requests arguments run through there.
11
+ def self.format_arguments
12
+ proc do |*args|
13
+ new_args = args
14
+
15
+ if new_args.size > 1
16
+ new_args[1] = Helper.format_payload new_args[1]
17
+ new_args[1] = new_args[1].to_json
18
+ end
19
+
20
+ new_args
21
+ end
22
+ end
23
+ end
24
+
25
+ # Post request middleware.
26
+ module Post
27
+ # Takes rest-client and response and converts it to internal response.
28
+ def self.to_response
29
+ proc do |response|
30
+ Response.new(response)
31
+ end
32
+ end
33
+
34
+ # Request results run through there.
35
+ def self.parse_response
36
+ proc do |response|
37
+ Resource::Helper.parse_response(response, 0) # TODO: need a cid
38
+ end
39
+ end
40
+ end
41
+
42
+ # Request rejection (error) middleware.
43
+ module Reject
44
+ def self.handle_rejection
45
+ proc do |error|
46
+ error
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,115 @@
1
+ require 'resource/factory'
2
+ require 'request'
3
+ require 'middleware'
4
+ require 'constant'
5
+ require 'enum'
6
+ require 'client'
7
+ require 'url_builder'
8
+ require 'rest-client'
9
+ require 'helper'
10
+
11
+ # Main Polyseerio module.
12
+ module Polyseerio
13
+ # Default client options.
14
+ DEFAULT_CLIENT_OPTIONS = {
15
+ agent: {},
16
+ deduce: true,
17
+ env: Constant::DEFAULT_ENV,
18
+ timeout: Constant::DEFAULT_TIMEOUT,
19
+ environment: Constant::DEFAULT_ENVIRONMENT,
20
+ token: nil,
21
+ token_env: Constant::DEFAULT_TOKEN_ENV,
22
+ upsert_env: true,
23
+ version: Constant::DEFAULT_API_VERSION
24
+ }.freeze
25
+
26
+ # Required resources for constructing a client.
27
+ REQUIRED_RESOURCES = [
28
+ Enum::Resource::ALERT,
29
+ Enum::Resource::CHANNEL,
30
+ Enum::Resource::ENVIRONMENT,
31
+ Enum::Resource::EVENT,
32
+ Enum::Resource::EXPECTATION,
33
+ Enum::Resource::INSTANCE,
34
+ Enum::Resource::LOGIC_BLOCK,
35
+ Enum::Resource::MEMBER,
36
+ Enum::Resource::SETTING,
37
+ Enum::Resource::TASK
38
+ ].freeze
39
+
40
+ # Maps resources to paths within a Client
41
+ CLIENT_RESOURCE_PATHS = {
42
+ Enum::Resource::ALERT => :Alert,
43
+ Enum::Resource::CHANNEL => :Channel,
44
+ Enum::Resource::ENVIRONMENT => :Environment,
45
+ Enum::Resource::EVENT => :Event,
46
+ Enum::Resource::EXPECTATION => :Expectation,
47
+ Enum::Resource::INSTANCE => :Instance,
48
+ Enum::Resource::LOGIC_BLOCK => :LogicBlock,
49
+ Enum::Resource::MEMBER => :Member,
50
+ Enum::Resource::SETTING => :Settings,
51
+ Enum::Resource::TASK => :Task
52
+ }.freeze
53
+
54
+ # Create a client and start it's agent.
55
+ def self.start(*args)
56
+ client = make(*args)
57
+
58
+ client.start_agent
59
+ end
60
+
61
+ @make_call_count = 0
62
+
63
+ # Create a client.
64
+ def self.make(options = {})
65
+ options = Helper.defaults(options, DEFAULT_CLIENT_OPTIONS)
66
+
67
+ cid = @make_call_count
68
+
69
+ token = Helper.resolve_token options
70
+
71
+ base_url = URL.get_base_url(
72
+ Constant::DEFAULT_API_BASE_URL,
73
+ Constant::DEFAULT_API_PROTOCOL,
74
+ options[:version]
75
+ )
76
+
77
+ if token.nil?
78
+ raise ArgumentError, 'Could not find an access token. None was passed' \
79
+ 'and non could be found in the environment variable: ' \
80
+ "#{options[:token_env]}."
81
+ end
82
+
83
+ headers = {
84
+ Constant::ACCESS_TOKEN_HEADER => token,
85
+ :content_type => 'application/json'
86
+ }
87
+
88
+ rest_resource = RestClient::Resource.new(
89
+ base_url,
90
+ headers: headers,
91
+ timeout: Helper.ms_to_seconds(options[:timeout])
92
+ )
93
+
94
+ # Create a request instance that uses middleware.
95
+ request = Request.new(
96
+ rest_resource,
97
+ pre: [Middleware::Pre.format_arguments],
98
+ post: [Middleware::Post.to_response, Middleware::Post.parse_response]
99
+ )
100
+
101
+ resources = REQUIRED_RESOURCES.each_with_object({}) do |resource, acc|
102
+ acc[resource] = Resource::Factory.make(resource, request, cid, options)
103
+
104
+ acc
105
+ end
106
+
107
+ resources = Helper.rekey(resources, CLIENT_RESOURCE_PATHS)
108
+
109
+ client = Client.new(cid, request: request, resources: resources)
110
+
111
+ @make_call_count += 1
112
+
113
+ client
114
+ end
115
+ end
@@ -0,0 +1,84 @@
1
+ require 'helper'
2
+ require 'concurrent'
3
+
4
+ module Polyseerio
5
+ # HTTP request wrapper that can use attached middleware.
6
+ class Request
7
+ module Middleware
8
+ PRE = :pre
9
+ POST = :post
10
+ REJECT = :reject
11
+ end
12
+
13
+ INITIALIZE_DEFAULTS = {
14
+ Middleware::PRE => [],
15
+ Middleware::POST => [],
16
+ Middleware::REJECT => []
17
+ }.freeze
18
+
19
+ def initialize(resource, options = {})
20
+ # need to ensure taht pre, post, reject are all arrays otherwise raise
21
+ options = Helper.defaults(options, INITIALIZE_DEFAULTS)
22
+
23
+ @resource = resource
24
+
25
+ @pre_request = options[Middleware::PRE]
26
+ @post_request = options[Middleware::POST]
27
+ @reject_request = options[Middleware::REJECT]
28
+ end
29
+
30
+ # Perform a GET request.
31
+ def get(*args)
32
+ execute(:get, *args)
33
+ end
34
+
35
+ # Perform a POST request.
36
+ def post(*args)
37
+ execute(:post, *args)
38
+ end
39
+
40
+ # Perform a PUT request.
41
+ def put(*args)
42
+ execute(:put, *args)
43
+ end
44
+
45
+ # Perform a DELETE request.
46
+ def delete(*args)
47
+ execute(:delete, *args)
48
+ end
49
+
50
+ private
51
+
52
+ # Execute a request using pre, post, and reject middleware.
53
+ #
54
+ # method - The HTTP method.
55
+ # ... - Arguments to forward to execute.
56
+ #
57
+ # Returns a promise.
58
+ def execute(method, *args)
59
+ new_args = args
60
+
61
+ @pre_request.each do |middleware|
62
+ new_args = middleware.call(*new_args)
63
+ end
64
+
65
+ path = new_args.empty? ? '' : new_args.shift
66
+
67
+ req = proc do ||
68
+ @resource[path].send(method, *new_args)
69
+ end
70
+
71
+ post = proc do |result|
72
+ @post_request.each do |middleware|
73
+ result = middleware.call(result)
74
+ end
75
+
76
+ result
77
+ end
78
+
79
+ Concurrent::Promise.new(&req).on_success(&post)
80
+ end
81
+
82
+ attr_accessor :resource, :pre_request, :post_request, :reject_request
83
+ end
84
+ end
@@ -0,0 +1,73 @@
1
+ require 'sdk/helper'
2
+
3
+ module Polyseerio
4
+ module Resource
5
+ # Base class for any resource.
6
+ class Base
7
+ attr_accessor :eid
8
+ attr_writer :eid
9
+
10
+ def initialize(attributes = {})
11
+ @eid = if attributes.include? :eid
12
+ attributes[:eid]
13
+ else
14
+ Polyseerio::SDK::Helper.resolve_eid(copts)
15
+ end
16
+ @attributes = attributes
17
+ end
18
+
19
+ # Set a property hash on the instance.
20
+ def override_properties(properties)
21
+ properties.each_with_object(self) do |(key, value), this|
22
+ this.send(:"#{key}=", value)
23
+ end
24
+ end
25
+
26
+ # Returns a copy of class attributes.
27
+ def properties
28
+ attributes.clone
29
+ end
30
+
31
+ # Returns the type of the class.
32
+ def type
33
+ self.class.type
34
+ end
35
+
36
+ # Returns the client options this class was constructed with.
37
+ def copts
38
+ self.class.copts
39
+ end
40
+
41
+ # Returns the client's request object.
42
+ def request
43
+ self.class.request
44
+ end
45
+
46
+ # True if the resource is new (not yet saved).
47
+ def new?
48
+ id.nil?
49
+ end
50
+
51
+ def method_missing(name, *args) # rubocop:disable all
52
+ # Setter.
53
+ if name =~ /^(\w+)=$/
54
+ name = :"#{$1}" # rubocop:disable all
55
+
56
+ @attributes[:"#{$1}"] = args[0] # rubocop:disable all
57
+ end
58
+
59
+ # Getter.
60
+ @attributes.fetch(name, nil)
61
+ end
62
+
63
+ def respond_to_missing?(_method_name)
64
+ true
65
+ end
66
+
67
+ private
68
+
69
+ attr_accessor :attributes
70
+ attr_writer :attributes
71
+ end
72
+ end
73
+ end