MuranoCLI 3.0.0 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +50 -27
- data/.trustme.vim +12 -8
- data/bin/murano +23 -8
- data/docs/basic_example.rst +1 -1
- data/docs/completions/murano_completion-bash +88 -0
- data/lib/MrMurano/Account.rb +3 -3
- data/lib/MrMurano/Business.rb +6 -6
- data/lib/MrMurano/Config-Migrate.rb +1 -3
- data/lib/MrMurano/Config.rb +16 -8
- data/lib/MrMurano/Content.rb +56 -45
- data/lib/MrMurano/Gateway.rb +62 -21
- data/lib/MrMurano/Mock.rb +27 -19
- data/lib/MrMurano/Passwords.rb +7 -7
- data/lib/MrMurano/ReCommander.rb +171 -28
- data/lib/MrMurano/Setting.rb +38 -40
- data/lib/MrMurano/Solution-ServiceConfig.rb +2 -1
- data/lib/MrMurano/Solution-Services.rb +196 -61
- data/lib/MrMurano/Solution-Users.rb +7 -7
- data/lib/MrMurano/Solution.rb +22 -8
- data/lib/MrMurano/SolutionId.rb +10 -4
- data/lib/MrMurano/SubCmdGroupContext.rb +14 -5
- data/lib/MrMurano/SyncAllowed.rb +42 -0
- data/lib/MrMurano/SyncUpDown.rb +122 -65
- data/lib/MrMurano/Webservice-Cors.rb +9 -3
- data/lib/MrMurano/Webservice-Endpoint.rb +39 -33
- data/lib/MrMurano/Webservice-File.rb +35 -24
- data/lib/MrMurano/commands/business.rb +18 -18
- data/lib/MrMurano/commands/content.rb +3 -2
- data/lib/MrMurano/commands/devices.rb +137 -22
- data/lib/MrMurano/commands/globals.rb +8 -2
- data/lib/MrMurano/commands/keystore.rb +3 -2
- data/lib/MrMurano/commands/link.rb +13 -13
- data/lib/MrMurano/commands/login.rb +3 -2
- data/lib/MrMurano/commands/mock.rb +4 -3
- data/lib/MrMurano/commands/password.rb +4 -2
- data/lib/MrMurano/commands/postgresql.rb +5 -3
- data/lib/MrMurano/commands/settings.rb +78 -62
- data/lib/MrMurano/commands/show.rb +79 -74
- data/lib/MrMurano/commands/solution.rb +6 -4
- data/lib/MrMurano/commands/solution_picker.rb +5 -4
- data/lib/MrMurano/commands/status.rb +15 -4
- data/lib/MrMurano/commands/timeseries.rb +3 -2
- data/lib/MrMurano/commands/tsdb.rb +3 -2
- data/lib/MrMurano/hash.rb +6 -6
- data/lib/MrMurano/http.rb +66 -67
- data/lib/MrMurano/makePretty.rb +18 -12
- data/lib/MrMurano/progress.rb +9 -2
- data/lib/MrMurano/verbosing.rb +14 -2
- data/lib/MrMurano/version.rb +2 -2
- data/spec/GatewayDevice_spec.rb +190 -149
- data/spec/Mock_spec.rb +3 -3
- data/spec/Solution-ServiceEventHandler_spec.rb +170 -137
- data/spec/SyncUpDown_spec.rb +205 -191
- metadata +3 -2
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.08.
|
1
|
+
# Last Modified: 2017.08.20 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -21,8 +21,6 @@ module MrMurano
|
|
21
21
|
return unless solsecret.exist?
|
22
22
|
# Is in JSON, which as a subset of YAML, so use YAML parser
|
23
23
|
solsecret.open do |io|
|
24
|
-
# rubocop:disable Security/YAMLLoad: Prefer using YAML.safe_load over YAML.load.
|
25
|
-
# MAYBE/2017-07-02: Switch to YAML.safe_load.
|
26
24
|
ss = YAML.load(io)
|
27
25
|
|
28
26
|
pff = $cfg.file_at('passwords', :user)
|
data/lib/MrMurano/Config.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.08.
|
1
|
+
# Last Modified: 2017.08.23 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -335,6 +335,8 @@ module MrMurano
|
|
335
335
|
@paths.each(&:load)
|
336
336
|
# If user wants curl commands dumped to a file, open that file.
|
337
337
|
init_curl_file
|
338
|
+
# If user doesn't want paging, disable it.
|
339
|
+
program :help_paging, !$cfg['tool.no-page'] unless $cfg['tool.no-page'].nil?
|
338
340
|
end
|
339
341
|
|
340
342
|
## Load specified file into the config stack
|
@@ -354,6 +356,7 @@ module MrMurano
|
|
354
356
|
|
355
357
|
section, ikey = key.split('.')
|
356
358
|
paths.each do |path|
|
359
|
+
next if path.data.nil?
|
357
360
|
next unless path.data.has_section?(section)
|
358
361
|
sec = path.data[section]
|
359
362
|
return sec if ikey.nil?
|
@@ -435,8 +438,12 @@ module MrMurano
|
|
435
438
|
end
|
436
439
|
|
437
440
|
paths = @paths.select { |p| scope == p.kind }
|
438
|
-
|
439
|
-
|
441
|
+
if paths.empty? || paths.length > 1
|
442
|
+
scope_q = fancy_ticks(scope)
|
443
|
+
raise "Unknown scope: #{scope_q}" if paths.empty?
|
444
|
+
paths_q = fancy_ticks(paths)
|
445
|
+
raise "Too many paths: #{paths_q} / scope: #{scope_q}" if paths.length > 1
|
446
|
+
end
|
440
447
|
|
441
448
|
cfg = paths.first
|
442
449
|
data = cfg.data
|
@@ -488,7 +495,8 @@ module MrMurano
|
|
488
495
|
|
489
496
|
cfg_paths = @paths.select { |p| p.kind == scope }
|
490
497
|
|
491
|
-
|
498
|
+
scope_q = fancy_ticks(scope)
|
499
|
+
msg = "Scope: #{scope_q}\n\n"
|
492
500
|
locats += Rainbow(msg).bright.underline
|
493
501
|
|
494
502
|
if !cfg_paths.empty?
|
@@ -498,9 +506,9 @@ module MrMurano
|
|
498
506
|
path = "Path: #{cfg.path}\n"
|
499
507
|
elsif %i[internal defaults].include? cfg.kind
|
500
508
|
# cfg.path is nil.
|
501
|
-
path = "Path:
|
509
|
+
path = "Path: #{scope_q} config is not saved.\n"
|
502
510
|
else
|
503
|
-
path = "Path:
|
511
|
+
path = "Path: #{scope_q} config does not exist.\n"
|
504
512
|
end
|
505
513
|
#locats += Rainbow(path).bright
|
506
514
|
locats += path
|
@@ -535,11 +543,11 @@ module MrMurano
|
|
535
543
|
locats += msg
|
536
544
|
end
|
537
545
|
else
|
538
|
-
msg = "No config found for
|
546
|
+
msg = "No config found for #{scope_q}.\n"
|
539
547
|
if scope != :specified
|
540
548
|
locats += Rainbow(msg).red.bright
|
541
549
|
else
|
542
|
-
locats += "Path:
|
550
|
+
locats += "Path: #{scope_q} config does not exist.\n\n"
|
543
551
|
locats += "Use --configfile to specify this config file.\n"
|
544
552
|
end
|
545
553
|
end
|
data/lib/MrMurano/Content.rb
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# Last Modified: 2017.08.23 /coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright © 2016-2017 Exosite LLC.
|
5
|
+
# License: MIT. See LICENSE.txt.
|
6
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
7
|
+
|
1
8
|
require 'uri'
|
2
9
|
require 'cgi'
|
3
10
|
require 'net/http'
|
@@ -8,6 +15,7 @@ require 'MrMurano/Config'
|
|
8
15
|
require 'MrMurano/http'
|
9
16
|
require 'MrMurano/verbosing'
|
10
17
|
require 'MrMurano/SolutionId'
|
18
|
+
require 'MrMurano/SyncAllowed'
|
11
19
|
require 'MrMurano/SyncUpDown'
|
12
20
|
|
13
21
|
module MrMurano
|
@@ -17,6 +25,7 @@ module MrMurano
|
|
17
25
|
include Http
|
18
26
|
include Verbose
|
19
27
|
include SolutionId
|
28
|
+
include SyncAllowed
|
20
29
|
|
21
30
|
def initialize
|
22
31
|
@solntype = 'product.id'
|
@@ -35,7 +44,7 @@ module MrMurano
|
|
35
44
|
def endpoint(path='')
|
36
45
|
super
|
37
46
|
parts = ['https:/', $cfg['net.host'], 'api:1'] + @uriparts
|
38
|
-
s = parts.map
|
47
|
+
s = parts.map(&:to_s).join('/')
|
39
48
|
URI(s + path.to_s)
|
40
49
|
end
|
41
50
|
|
@@ -73,16 +82,16 @@ module MrMurano
|
|
73
82
|
# ?type=
|
74
83
|
sha256 = Digest::SHA256.new
|
75
84
|
sha256.file(local_path.to_s)
|
76
|
-
mime = MIME::Types.type_for(local_path.to_s)[0] || MIME::Types[
|
85
|
+
mime = MIME::Types.type_for(local_path.to_s)[0] || MIME::Types['application/octet-stream'][0]
|
77
86
|
|
78
87
|
params = {
|
79
|
-
:
|
80
|
-
:
|
81
|
-
:
|
88
|
+
sha256: sha256.hexdigest,
|
89
|
+
expires_in: 30,
|
90
|
+
type: mime,
|
82
91
|
}
|
83
|
-
|
84
|
-
|
85
|
-
|
92
|
+
params[:tags] = tags.to_json if !tags.nil? && tags.is_a?(Hash)
|
93
|
+
|
94
|
+
return unless upload_item_allowed(name)
|
86
95
|
|
87
96
|
ret = get("/#{CGI.escape(name)}/upload?#{URI.encode_www_form(params)}")
|
88
97
|
debug "POST instructions: #{ret}"
|
@@ -91,24 +100,24 @@ module MrMurano
|
|
91
100
|
|
92
101
|
uri = URI(ret[:url])
|
93
102
|
request = Net::HTTP::Post.new(uri)
|
94
|
-
file = HTTP::FormData::File.new(local_path.to_s,
|
95
|
-
form = HTTP::FormData.create(ret[:inputs].merge(
|
103
|
+
file = HTTP::FormData::File.new(local_path.to_s, content_type: mime)
|
104
|
+
form = HTTP::FormData.create(ret[:inputs].merge(ret[:field] => file))
|
96
105
|
|
97
106
|
request['User-Agent'] = "MrMurano/#{MrMurano::VERSION}"
|
98
107
|
request.content_type = form.content_type
|
99
108
|
request.content_length = form.content_length
|
100
109
|
request.body = form.to_s
|
101
110
|
|
102
|
-
if $cfg['tool.curldebug']
|
111
|
+
if $cfg['tool.curldebug']
|
103
112
|
a = []
|
104
|
-
a << %
|
105
|
-
a << %
|
106
|
-
a << %
|
107
|
-
a << %
|
113
|
+
a << %(curl -s)
|
114
|
+
a << %(-H 'User-Agent: #{request['User-Agent']}')
|
115
|
+
a << %(-X #{request.method})
|
116
|
+
a << %('#{request.uri}')
|
108
117
|
ret[:inputs].each_pair do |key, value|
|
109
|
-
a << %
|
118
|
+
a << %(-F '#{key}=#{value}')
|
110
119
|
end
|
111
|
-
a << %
|
120
|
+
a << %(-F #{ret[:field]}=@#{local_path})
|
112
121
|
if $cfg.curlfile_f.nil?
|
113
122
|
puts a.join(' ')
|
114
123
|
else
|
@@ -117,14 +126,17 @@ module MrMurano
|
|
117
126
|
end
|
118
127
|
end
|
119
128
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
129
|
+
return if $cfg['tool.dry']
|
130
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |ihttp|
|
131
|
+
response = ihttp.request(request)
|
132
|
+
case response
|
133
|
+
# rubocop:disable Lint/EmptyWhen
|
134
|
+
# "Avoid when branches without a body."
|
135
|
+
# "I'm going to allow this."
|
136
|
+
when Net::HTTPSuccess
|
137
|
+
# pass
|
138
|
+
else
|
139
|
+
showHttpError(request, response)
|
128
140
|
end
|
129
141
|
end
|
130
142
|
end
|
@@ -132,6 +144,7 @@ module MrMurano
|
|
132
144
|
# Remove content by name
|
133
145
|
# @param name [String] Name of content to be deleted
|
134
146
|
def remove(name)
|
147
|
+
return unless remove_item_allowed(name)
|
135
148
|
delete("/#{CGI.escape(name)}")
|
136
149
|
end
|
137
150
|
|
@@ -139,6 +152,7 @@ module MrMurano
|
|
139
152
|
# @param name [String] Name of content to be downloaded
|
140
153
|
# @param block [Block] Block to process data as it is downloaded
|
141
154
|
def download(name, &block)
|
155
|
+
return unless download_item_allowed(name)
|
142
156
|
# This is a two step process.
|
143
157
|
# 1: Get the get instructions for S3.
|
144
158
|
# 2: fetch from S3.
|
@@ -150,12 +164,12 @@ module MrMurano
|
|
150
164
|
request = Net::HTTP::Get.new(uri)
|
151
165
|
request['User-Agent'] = "MrMurano/#{MrMurano::VERSION}"
|
152
166
|
|
153
|
-
if $cfg['tool.curldebug']
|
167
|
+
if $cfg['tool.curldebug']
|
154
168
|
a = []
|
155
|
-
a << %
|
156
|
-
a << %
|
157
|
-
a << %
|
158
|
-
a << %
|
169
|
+
a << %(curl -s)
|
170
|
+
a << %(-H 'User-Agent: #{request['User-Agent']}')
|
171
|
+
a << %(-X #{request.method})
|
172
|
+
a << %('#{request.uri}')
|
159
173
|
if $cfg.curlfile_f.nil?
|
160
174
|
puts a.join(' ')
|
161
175
|
else
|
@@ -164,28 +178,25 @@ module MrMurano
|
|
164
178
|
end
|
165
179
|
end
|
166
180
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
else
|
175
|
-
response.read_body do |chunk|
|
176
|
-
$stdout.write chunk
|
177
|
-
end
|
178
|
-
end
|
181
|
+
return if $cfg['tool.dry']
|
182
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |ihttp|
|
183
|
+
ihttp.request(request) do |response|
|
184
|
+
case response
|
185
|
+
when Net::HTTPSuccess
|
186
|
+
if block_given?
|
187
|
+
response.read_body(&block)
|
179
188
|
else
|
180
|
-
|
189
|
+
response.read_body do |chunk|
|
190
|
+
$stdout.write chunk
|
191
|
+
end
|
181
192
|
end
|
193
|
+
else
|
194
|
+
showHttpError(request, response)
|
182
195
|
end
|
183
196
|
end
|
184
197
|
end
|
185
198
|
end
|
186
|
-
|
187
199
|
end
|
188
200
|
end
|
189
201
|
end
|
190
202
|
|
191
|
-
# vim: set ai et sw=2 ts=2 :
|
data/lib/MrMurano/Gateway.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.08.
|
1
|
+
# Last Modified: 2017.08.23 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -25,6 +25,7 @@ module MrMurano
|
|
25
25
|
include Http
|
26
26
|
include Verbose
|
27
27
|
include SolutionId
|
28
|
+
include SyncAllowed
|
28
29
|
|
29
30
|
def initialize
|
30
31
|
@solntype = 'product.id'
|
@@ -155,10 +156,13 @@ module MrMurano
|
|
155
156
|
end
|
156
157
|
|
157
158
|
def remove(itemkey)
|
159
|
+
return unless remove_item_allowed(itemkey)
|
158
160
|
@there.delete_if { |item| item[@itemkey] == itemkey }
|
159
161
|
end
|
160
162
|
|
161
163
|
def upload(_local, remote, _modify)
|
164
|
+
# Not calling, e.g., `return unless upload_item_allowed(local)`
|
165
|
+
# See instead: syncup_after and syncdown_after/resources_write
|
162
166
|
@there.delete_if { |item| item[@itemkey] == remote[@itemkey] }
|
163
167
|
@there << remote.reject { |k, _v| %i[synckey synctype].include? k }
|
164
168
|
end
|
@@ -192,6 +196,8 @@ module MrMurano
|
|
192
196
|
end
|
193
197
|
|
194
198
|
def download(_local, item)
|
199
|
+
# Not calling, e.g., `return unless download_item_allowed(item[@itemkey])`
|
200
|
+
# See instead: syncup_after and syncdown_after/resources_write
|
195
201
|
@here = locallist if @here.nil?
|
196
202
|
# needs to append/merge with file
|
197
203
|
@here.delete_if do |i|
|
@@ -218,7 +224,9 @@ module MrMurano
|
|
218
224
|
end
|
219
225
|
|
220
226
|
def removelocal(_local, item)
|
221
|
-
#
|
227
|
+
# Not calling, e.g., `return unless removelocal_item_allowed(item[@itemkey])`
|
228
|
+
# See instead: syncup_after and syncdown_after/resources_write
|
229
|
+
# Append/merge with file.
|
222
230
|
key = @itemkey.to_sym
|
223
231
|
@here.delete_if do |it|
|
224
232
|
it[key] == item[key]
|
@@ -297,8 +305,6 @@ module MrMurano
|
|
297
305
|
end
|
298
306
|
|
299
307
|
here = {}
|
300
|
-
# rubocop:disable Security/YAMLLoad: Prefer using YAML.safe_load over YAML.load.
|
301
|
-
# MAYBE/2017-07-02: Convert to safe_load.
|
302
308
|
from.open { |io| here = YAML.load(io) }
|
303
309
|
here = {} if here == false
|
304
310
|
|
@@ -375,23 +381,39 @@ module MrMurano
|
|
375
381
|
## Create a device with given Identity
|
376
382
|
# @param id [String] The new identity
|
377
383
|
# @param opts [Hash] Options for the new device
|
384
|
+
# @option opts [Integer] :expire Time at microsecs since epoch when activation window closes.
|
385
|
+
# (EXPLAIN/2017-08-23: For a certificate, is this different? Time when it must be reprovisioned?)
|
386
|
+
# @option opts [String,Pathname,IO] :key Shared secret for hash, password, token types;
|
387
|
+
# or public key for certificate auth type.
|
388
|
+
# May be string or IO/Pathname to file.
|
378
389
|
# @option opts [String] :type One of: certificate, hash, password, signature, token
|
379
|
-
|
380
|
-
# @option opts [String] :privatekey Shared secret for hash, password, token types
|
381
|
-
# @option opts [String,Integer] :expire For Cert, when it must be reprovisioned, otherwise when the activation window closes.
|
390
|
+
DEVICE_AUTH_TYPES = %i[certificate hash password signature token].freeze
|
382
391
|
def enable(id, opts=nil)
|
383
|
-
if
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
392
|
+
opts = {} if opts.nil?
|
393
|
+
props = { auth: {}, locked: false }
|
394
|
+
# See: okami_api/api/swagger/swagger.yaml
|
395
|
+
unless opts[:expire].nil?
|
396
|
+
begin
|
397
|
+
props[:auth][:expire] = Integer(opts[:expire])
|
398
|
+
rescue ArgumentError
|
399
|
+
# Callers should prevent this, so ugly raise is okay.
|
400
|
+
raise ':expire option is not a valid number: #{fancy_ticks(opts[:expire])}'
|
389
401
|
end
|
390
|
-
|
391
|
-
|
402
|
+
end
|
403
|
+
unless opts[:type].nil?
|
404
|
+
opts[:type] = opts[:type].to_sym
|
405
|
+
unless DEVICE_AUTH_TYPES.include?(opts[:type])
|
406
|
+
complaint = ":type must be one of #{DEVICE_AUTH_TYPES.join('|')}"
|
407
|
+
raise complaint
|
408
|
+
end
|
409
|
+
props[:auth][:type] = opts[:type]
|
410
|
+
end
|
411
|
+
unless opts[:key].nil?
|
412
|
+
props[:auth][:key] = opts[:key].is_a?(String) && opts[:key] || opts[:key].read
|
413
|
+
props[:auth][:type] = :certificate if props[:auth][:type].nil?
|
392
414
|
end
|
393
415
|
whirly_start('Enabling Device...')
|
394
|
-
putted = put("/#{CGI.escape(id.to_s)}",
|
416
|
+
putted = put("/#{CGI.escape(id.to_s)}", props)
|
395
417
|
whirly_stop
|
396
418
|
putted
|
397
419
|
end
|
@@ -400,19 +422,21 @@ module MrMurano
|
|
400
422
|
|
401
423
|
## Create a bunch of devices at once
|
402
424
|
# @param local [String, Pathname] CSV file of identifiers
|
403
|
-
# @param expire [Number] Expire time for all identities
|
425
|
+
# @param expire [Number] Expire time for all identities
|
404
426
|
# @return [void]
|
405
|
-
def enable_batch(local,
|
427
|
+
def enable_batch(local, expire=nil)
|
406
428
|
# Need to modify @uriparts for just this endpoint call.
|
407
429
|
uriparts = @uriparts
|
408
430
|
@uriparts[-1] = :identities
|
409
431
|
uri = endpoint
|
410
432
|
@uriparts = uriparts
|
411
|
-
|
412
433
|
file = HTTP::FormData::File.new(local.to_s, content_type: 'text/csv')
|
413
|
-
|
434
|
+
opts = {}
|
435
|
+
opts[:identities] = file
|
436
|
+
opts[:expire] = expire unless expire.nil?
|
437
|
+
form = HTTP::FormData.create(**opts)
|
414
438
|
req = Net::HTTP::Post.new(uri)
|
415
|
-
|
439
|
+
add_headers(req)
|
416
440
|
req.content_type = form.content_type
|
417
441
|
req.content_length = form.content_length
|
418
442
|
req.body = form.to_s
|
@@ -425,6 +449,7 @@ module MrMurano
|
|
425
449
|
## Delete a device
|
426
450
|
# @param identifier [String] Who to delete.
|
427
451
|
def remove(identifier)
|
452
|
+
return unless remove_item_allowed(identifier)
|
428
453
|
delete("/#{CGI.escape(identifier.to_s)}")
|
429
454
|
end
|
430
455
|
|
@@ -475,14 +500,30 @@ module MrMurano
|
|
475
500
|
# @param values [Hash] Aliases and the values to write.
|
476
501
|
def write(identifier, values)
|
477
502
|
debug "Will Write: #{values}"
|
503
|
+
# EXPLAIN/2017-08-23: Why not escape the ID?
|
504
|
+
# #{CGI.escape(identifier.to_s)}
|
478
505
|
patch("/#{identifier}/state", values)
|
479
506
|
end
|
480
507
|
|
481
508
|
# Read the current state for a device
|
482
509
|
# @param identifier [String] The identifier for the device to read.
|
483
510
|
def read(identifier)
|
511
|
+
# EXPLAIN/2017-08-23: Why not escape the ID?
|
512
|
+
# #{CGI.escape(identifier.to_s)}
|
484
513
|
get("/#{identifier}/state")
|
485
514
|
end
|
515
|
+
|
516
|
+
def lock(identifier)
|
517
|
+
patch("/#{CGI.escape(identifier.to_s)}", locked: true)
|
518
|
+
end
|
519
|
+
|
520
|
+
def unlock(identifier)
|
521
|
+
patch("/#{CGI.escape(identifier.to_s)}", locked: false)
|
522
|
+
end
|
523
|
+
|
524
|
+
def revoke(identifier)
|
525
|
+
patch("/#{CGI.escape(identifier.to_s)}", auth: { expire: 0 })
|
526
|
+
end
|
486
527
|
end
|
487
528
|
end
|
488
529
|
end
|
data/lib/MrMurano/Mock.rb
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# Last Modified: 2017.08.20 /coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright © 2016-2017 Exosite LLC.
|
5
|
+
# License: MIT. See LICENSE.txt.
|
6
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
7
|
+
|
1
8
|
require 'erb'
|
2
9
|
require 'securerandom'
|
3
10
|
|
@@ -9,55 +16,56 @@ module MrMurano
|
|
9
16
|
end
|
10
17
|
|
11
18
|
def show
|
12
|
-
file = Pathname.new(
|
13
|
-
if file.exist?
|
14
|
-
authorization = %
|
19
|
+
file = Pathname.new(testpoint_path)
|
20
|
+
if file.exist?
|
21
|
+
authorization = %(if request.headers["authorization"] == ")
|
15
22
|
file.open('rb') do |io|
|
16
23
|
io.each_line do |line|
|
17
24
|
auth_line = line.include?(authorization)
|
18
|
-
if auth_line
|
25
|
+
if auth_line
|
19
26
|
capture = /\=\= "(.*)"/.match(line)
|
20
27
|
return capture.captures[0]
|
21
28
|
end
|
22
29
|
end
|
23
30
|
end
|
24
31
|
end
|
25
|
-
|
32
|
+
false
|
26
33
|
end
|
27
34
|
|
28
|
-
def
|
29
|
-
path =
|
30
|
-
|
35
|
+
def mock_template
|
36
|
+
path = mock_template_path
|
37
|
+
::File.read(path)
|
31
38
|
end
|
32
39
|
|
33
|
-
def
|
40
|
+
def testpoint_path
|
34
41
|
file_name = 'testpoint.post.lua'
|
35
|
-
path = %
|
36
|
-
|
42
|
+
path = %(#{$cfg['location.endpoints']}/#{file_name})
|
43
|
+
path
|
37
44
|
end
|
38
45
|
|
39
|
-
def
|
40
|
-
|
46
|
+
def mock_template_path
|
47
|
+
::File.join(::File.dirname(__FILE__), 'template', 'mock.erb')
|
41
48
|
end
|
42
49
|
|
43
50
|
def create_testpoint
|
44
51
|
uuid = SecureRandom.uuid
|
45
|
-
template = ERB.new(
|
52
|
+
template = ERB.new(mock_template)
|
46
53
|
endpoint = template.result(binding)
|
47
54
|
|
48
|
-
Pathname.new(
|
55
|
+
Pathname.new(testpoint_path).open('wb') do |io|
|
49
56
|
io << endpoint
|
50
57
|
end
|
51
|
-
|
58
|
+
uuid
|
52
59
|
end
|
53
60
|
|
54
61
|
def remove_testpoint
|
55
|
-
file = Pathname.new(
|
56
|
-
if file.exist?
|
62
|
+
file = Pathname.new(testpoint_path)
|
63
|
+
if file.exist?
|
57
64
|
file.unlink
|
58
65
|
return true
|
59
66
|
end
|
60
|
-
|
67
|
+
false
|
61
68
|
end
|
62
69
|
end
|
63
70
|
end
|
71
|
+
|