uppityrobot 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UppityRobot
4
+ module CLI
5
+ module Commands
6
+ module Monitors
7
+ # UppityRobot::CLI::Commands::Monitors::List lists monitors
8
+ class List < Dry::CLI::Command
9
+ desc "List Monitors"
10
+
11
+ option :csv, type: :string, desc: "Path to additionally save results as csv"
12
+ option :filter, type: :string, default: "{}", desc: "Filter string for monitors"
13
+ option :search, type: :string, desc: "keyword within url or friendly_name"
14
+
15
+ example [
16
+ "--search aspace",
17
+ '--filter \'{"friendly_name": "^aspace-"}\'',
18
+ '--search aspace --filter \'{"status": 0}\''
19
+ ]
20
+
21
+ def call(csv: nil, filter: "{}", search: nil, **)
22
+ filter = JSON.parse(filter)
23
+ filtered = { stat: "ok", total: 0, monitors: [] }
24
+ params = search ? { search: search } : {}
25
+ total = 0
26
+
27
+ UppityRobot::Client.new(:getMonitors, params).filter(filter).each do |m|
28
+ filtered[:monitors] << m
29
+ total += 1
30
+ end
31
+
32
+ filtered[:total] = total
33
+ write_csv(csv, filtered[:monitors])
34
+ puts filtered.to_json
35
+ rescue JSON::ParserError => e
36
+ puts JSON.generate({ stat: "fail", error: "JSON parser #{e.message}" })
37
+ end
38
+
39
+ def write_csv(file, data)
40
+ return unless file
41
+
42
+ CSV.open(File.expand_path(file), "wb", encoding: "UTF-8") do |csv|
43
+ csv << data.first.keys
44
+ data.each { |hash| csv << hash.values }
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UppityRobot
4
+ module CLI
5
+ module Commands
6
+ module Monitors
7
+ # UppityRobot::CLI::Commands::Monitors::Update update monitors
8
+ class Update < Dry::CLI::Command
9
+ desc "Update monitors"
10
+
11
+ argument :format, required: true, values: %w[csv json], desc: "The format to use for updates"
12
+ argument :data, required: true, desc: "The data file or (json) string for updates"
13
+
14
+ example [
15
+ "csv monitors.csv",
16
+ "json monitors.json",
17
+ 'json \'[{"id": 1, "friendly_name": "newName"}]\''
18
+ ]
19
+
20
+ # rubocop:disable Metrics/AbcSize
21
+ def call(format:, data:, **)
22
+ check_format(format)
23
+ data = parse_data(format, data)
24
+ unless data.is_a? Array
25
+ abort(
26
+ { stat: "fail", error: "Data must be an array: #{data.inspect}" }.to_json
27
+ )
28
+ end
29
+
30
+ updated = { stat: "ok", total: 0, updated: 0, monitors: [], errors: [] }
31
+ data.each do |d|
32
+ original = d.dup # UptimeRobot::Client modifies `d`, avoid this for errors
33
+ updated[:total] += 1
34
+ updated[:monitors] << UppityRobot::Client.new(:editMonitor, d).execute
35
+ updated[:updated] += 1
36
+ rescue UptimeRobot::Error => e
37
+ updated[:errors] << "#{e.message} for: #{original.inspect}"
38
+ end
39
+
40
+ puts updated.to_json
41
+ rescue CSV::MalformedCSVError, JSON::ParserError => e
42
+ puts JSON.generate({ stat: "fail", error: "Invalid input: #{e.message}" })
43
+ end
44
+ # rubocop:enable Metrics/AbcSize
45
+
46
+ def check_format(format)
47
+ return if %w[csv json].include? format
48
+
49
+ abort({ stat: "fail",
50
+ error: "Format not recognized, must be one of: [csv, json]" }.to_json)
51
+ end
52
+
53
+ def parse_data(format, data)
54
+ if format == "json" && File.file?(data)
55
+ JSON.parse(File.read(data))
56
+ elsif format == "json"
57
+ JSON.parse(data)
58
+ elsif format == "csv" && File.file?(data)
59
+ rows = []
60
+ CSV.foreach(data, headers: true, header_converters: :symbol) do |row|
61
+ rows << row.to_hash
62
+ end
63
+ rows
64
+ else
65
+ abort({ stat: "fail", error: "Error parsing data: #{format}, #{data.inspect}" }.to_json)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UppityRobot
4
+ module CLI
5
+ # UppityRobot::CLI::Commands Registry
6
+ module Commands
7
+ extend Dry::CLI::Registry
8
+
9
+ register "exec", Exec, aliases: ["e"]
10
+ register "version", Version, aliases: ["v", "-v", "--version"]
11
+
12
+ register "monitors", aliases: ["m"] do |prefix|
13
+ prefix.register "create", Monitors::Create
14
+ prefix.register "delete", Monitors::Delete
15
+ prefix.register "exec", Monitors::Exec
16
+ prefix.register "list", Monitors::List
17
+ prefix.register "update", Monitors::Update
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UppityRobot
4
+ module CLI
5
+ module Commands
6
+ # UppityRobot::CLI::Commands::Version prints version
7
+ class Version < Dry::CLI::Command
8
+ desc "Print UppityRobot CLI tool version"
9
+
10
+ def call(*)
11
+ puts UppityRobot::VERSION
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UppityRobot
4
+ # UppityRobot::Client is a CLI focused wrapper for the UptimeRobot::Client
5
+ class Client
6
+ attr_reader :response
7
+
8
+ RECORD_TYPES = {
9
+ getAlertContacts: "alert_contacts",
10
+ getMonitors: "monitors"
11
+ }.freeze
12
+
13
+ def initialize(task, params)
14
+ @client = client
15
+ @task = verify_task(task)
16
+ @params = params
17
+ @response = nil
18
+ end
19
+
20
+ def execute
21
+ @response = client.send(@task, @params)
22
+ end
23
+
24
+ def filter(filter = {})
25
+ type = RECORD_TYPES[@task]
26
+ Enumerator.new do |yielder|
27
+ paginate.each do |response, _offset, _total|
28
+ response[type].find_all do |record|
29
+ satisfies_conditions = true
30
+ filter.each do |key, regex|
31
+ satisfies_conditions = false unless record.key?(key) && record[key].to_s =~ /#{regex}/
32
+ end
33
+ yielder << record if satisfies_conditions
34
+ end
35
+ end
36
+ end.lazy
37
+ end
38
+
39
+ def paginate
40
+ Enumerator.new do |yielder|
41
+ @params.delete :offset # we want to start from the beginning
42
+ response = execute # initial connection
43
+ offset = 0
44
+ limit = response["pagination"]["limit"]
45
+ total = response["pagination"]["total"]
46
+
47
+ loop do
48
+ raise StopIteration if offset >= total
49
+
50
+ @params = @params.merge({ offset: offset })
51
+ response = execute
52
+ yielder << [response, offset, total]
53
+ offset += limit
54
+ end
55
+ end.lazy
56
+ end
57
+
58
+ # use when a single record result is expected & required
59
+ def fetch
60
+ verify_fetch_params
61
+ # TODO: support alert_contacts search (requires filter)
62
+ response = execute
63
+ verify_fetch_total response
64
+ response[RECORD_TYPES[@task]].first
65
+ end
66
+
67
+ private
68
+
69
+ def client
70
+ options = { api_key: ENV.fetch("UPTIMEROBOT_API_KEY") }
71
+ options[:url] = ENV["UPTIMEROBOT_ENDPOINT"] if ENV["UPTIMEROBOT_ENDPOINT"]
72
+ UptimeRobot::Client.new(options)
73
+ rescue KeyError => e
74
+ abort({ stat: "fail", error: "Error, #{e.message}" }.to_json)
75
+ end
76
+
77
+ def parse_total(response)
78
+ response.key?("total") ? response["total"] : response["pagination"]["total"]
79
+ end
80
+
81
+ def verify_fetch_params
82
+ return if @params.key?(:search) || @params.key?(RECORD_TYPES[@task].to_sym)
83
+
84
+ abort(
85
+ { stat: "fail", error: "Attempted fetch without required params" }.to_json
86
+ )
87
+ end
88
+
89
+ def verify_fetch_total(response)
90
+ total = parse_total response
91
+ return if total == 1
92
+
93
+ abort(
94
+ {
95
+ stat: "fail",
96
+ error: "Unique record lookup failed: #{response.inspect}"
97
+ }.to_json
98
+ )
99
+ end
100
+
101
+ def verify_task(task)
102
+ unless UptimeRobot::Client::METHODS.include? task
103
+ error = {
104
+ stat: "fail",
105
+ error: "Task not recognized [#{task}], must be: #{UptimeRobot::Client::METHODS.join(", ")}"
106
+ }.to_json
107
+ abort(error)
108
+ end
109
+ task
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UppityRobot
4
+ VERSION = "0.2.0"
5
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+ require "dry/cli"
5
+ require "json"
6
+ require "uptimerobot"
7
+
8
+ require_relative "uppityrobot/client"
9
+ require_relative "uppityrobot/version"
10
+ require_relative "uppityrobot/cli/commands/exec"
11
+ require_relative "uppityrobot/cli/commands/monitors/create"
12
+ require_relative "uppityrobot/cli/commands/monitors/delete"
13
+ require_relative "uppityrobot/cli/commands/monitors/exec"
14
+ require_relative "uppityrobot/cli/commands/monitors/list"
15
+ require_relative "uppityrobot/cli/commands/monitors/update"
16
+ require_relative "uppityrobot/cli/commands/version"
17
+
18
+ # load the registry last
19
+ require_relative "uppityrobot/cli/commands/registry"
20
+
21
+ module UppityRobot
22
+ class Error < StandardError; end
23
+
24
+ ROOT = Gem::Specification.find_by_name("uppityrobot").gem_dir
25
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/uppityrobot/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "uppityrobot"
7
+ spec.version = UppityRobot::VERSION
8
+ spec.authors = ["Mark Cooper"]
9
+ spec.email = ["mark.c.cooper@outlook.com"]
10
+
11
+ spec.summary = "Command line wrapper for the UptimeRobot API (wrapper)."
12
+ spec.description = "Command line wrapper for the UptimeRobot API (wrapper)."
13
+ spec.homepage = "https://github.com/lyrasis/uppityrobot.git"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.7.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = spec.homepage
19
+
20
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_dependency "dry-cli", "~> 0.7"
28
+ spec.add_dependency "json", "~> 2.5"
29
+ spec.add_dependency "uptimerobot", "~> 0.2"
30
+
31
+ spec.add_development_dependency "aruba"
32
+ spec.add_development_dependency "capybara_discoball"
33
+ spec.add_development_dependency "cucumber"
34
+ spec.add_development_dependency "json_spec"
35
+ spec.add_development_dependency "pry"
36
+ spec.add_development_dependency "rake", "~> 13.0"
37
+ spec.add_development_dependency "rspec", "~> 3.2"
38
+ spec.add_development_dependency "rubocop", "~> 1.7"
39
+ spec.add_development_dependency "sinatra"
40
+ spec.add_development_dependency "webmock"
41
+ end
metadata ADDED
@@ -0,0 +1,261 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: uppityrobot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Mark Cooper
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-09-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-cli
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: uptimerobot
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: aruba
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: capybara_discoball
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: cucumber
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: json_spec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rake
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '13.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '13.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.2'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.2'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.7'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1.7'
167
+ - !ruby/object:Gem::Dependency
168
+ name: sinatra
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: webmock
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ description: Command line wrapper for the UptimeRobot API (wrapper).
196
+ email:
197
+ - mark.c.cooper@outlook.com
198
+ executables:
199
+ - uppityrobot
200
+ extensions: []
201
+ extra_rdoc_files: []
202
+ files:
203
+ - ".github/workflows/main.yml"
204
+ - ".gitignore"
205
+ - ".rspec"
206
+ - ".rubocop.yml"
207
+ - ".vscode/settings.json"
208
+ - Gemfile
209
+ - Gemfile.lock
210
+ - LICENSE.txt
211
+ - README.md
212
+ - Rakefile
213
+ - bin/console
214
+ - bin/setup
215
+ - exe/uppityrobot
216
+ - fixtures/deleteMonitor.json
217
+ - fixtures/editMonitor.json
218
+ - fixtures/getAlertContacts.json
219
+ - fixtures/getMonitor.unknown.json
220
+ - fixtures/getMonitors.google.json
221
+ - fixtures/getMonitors.json
222
+ - fixtures/getMonitors.mywebpage.json
223
+ - fixtures/newMonitor.json
224
+ - lib/uppityrobot.rb
225
+ - lib/uppityrobot/cli/commands/exec.rb
226
+ - lib/uppityrobot/cli/commands/monitors/create.rb
227
+ - lib/uppityrobot/cli/commands/monitors/delete.rb
228
+ - lib/uppityrobot/cli/commands/monitors/exec.rb
229
+ - lib/uppityrobot/cli/commands/monitors/list.rb
230
+ - lib/uppityrobot/cli/commands/monitors/update.rb
231
+ - lib/uppityrobot/cli/commands/registry.rb
232
+ - lib/uppityrobot/cli/commands/version.rb
233
+ - lib/uppityrobot/client.rb
234
+ - lib/uppityrobot/version.rb
235
+ - uppityrobot.gemspec
236
+ homepage: https://github.com/lyrasis/uppityrobot.git
237
+ licenses:
238
+ - MIT
239
+ metadata:
240
+ homepage_uri: https://github.com/lyrasis/uppityrobot.git
241
+ source_code_uri: https://github.com/lyrasis/uppityrobot.git
242
+ post_install_message:
243
+ rdoc_options: []
244
+ require_paths:
245
+ - lib
246
+ required_ruby_version: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: 2.7.0
251
+ required_rubygems_version: !ruby/object:Gem::Requirement
252
+ requirements:
253
+ - - ">="
254
+ - !ruby/object:Gem::Version
255
+ version: '0'
256
+ requirements: []
257
+ rubygems_version: 3.1.6
258
+ signing_key:
259
+ specification_version: 4
260
+ summary: Command line wrapper for the UptimeRobot API (wrapper).
261
+ test_files: []