MuranoCLI 3.0.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.agignore +1 -0
  3. data/.rubocop.yml +67 -5
  4. data/Gemfile +6 -3
  5. data/MuranoCLI.gemspec +14 -10
  6. data/README.markdown +299 -126
  7. data/Rakefile +6 -1
  8. data/bin/murano +2 -2
  9. data/docs/completions/murano_completion-bash +93 -0
  10. data/lib/MrMurano.rb +19 -2
  11. data/lib/MrMurano/Business.rb +22 -19
  12. data/lib/MrMurano/Config.rb +19 -9
  13. data/lib/MrMurano/Content.rb +4 -4
  14. data/lib/MrMurano/Exchange-Element.rb +99 -0
  15. data/lib/MrMurano/Exchange.rb +137 -0
  16. data/lib/MrMurano/Gateway.rb +9 -9
  17. data/lib/MrMurano/Keystore.rb +4 -2
  18. data/lib/MrMurano/ReCommander.rb +3 -5
  19. data/lib/MrMurano/Solution-ServiceConfig.rb +12 -12
  20. data/lib/MrMurano/Solution-Services.rb +15 -14
  21. data/lib/MrMurano/Solution-Users.rb +2 -2
  22. data/lib/MrMurano/Solution.rb +43 -49
  23. data/lib/MrMurano/SolutionId.rb +28 -28
  24. data/lib/MrMurano/SyncUpDown.rb +32 -22
  25. data/lib/MrMurano/Webservice-Endpoint.rb +2 -1
  26. data/lib/MrMurano/Webservice.rb +5 -5
  27. data/lib/MrMurano/commands.rb +2 -1
  28. data/lib/MrMurano/commands/business.rb +21 -19
  29. data/lib/MrMurano/commands/domain.rb +16 -2
  30. data/lib/MrMurano/commands/exchange.rb +272 -0
  31. data/lib/MrMurano/commands/globals.rb +17 -1
  32. data/lib/MrMurano/commands/init.rb +3 -3
  33. data/lib/MrMurano/commands/link.rb +16 -16
  34. data/lib/MrMurano/commands/postgresql.rb +2 -2
  35. data/lib/MrMurano/commands/show.rb +13 -7
  36. data/lib/MrMurano/commands/solution.rb +23 -17
  37. data/lib/MrMurano/commands/solution_picker.rb +49 -44
  38. data/lib/MrMurano/commands/sync.rb +2 -1
  39. data/lib/MrMurano/commands/timeseries.rb +2 -2
  40. data/lib/MrMurano/commands/tsdb.rb +2 -2
  41. data/lib/MrMurano/hash.rb +19 -7
  42. data/lib/MrMurano/http.rb +12 -2
  43. data/lib/MrMurano/orderedhash.rb +200 -0
  44. data/lib/MrMurano/spec_commander.rb +98 -0
  45. data/lib/MrMurano/verbosing.rb +2 -2
  46. data/lib/MrMurano/version.rb +2 -2
  47. data/spec/Business_spec.rb +8 -6
  48. data/spec/Solution-ServiceConfig_spec.rb +1 -1
  49. data/spec/SyncUpDown_spec.rb +6 -6
  50. data/spec/_workspace.rb +9 -4
  51. data/spec/cmd_business_spec.rb +8 -2
  52. data/spec/cmd_common.rb +266 -25
  53. data/spec/cmd_exchange_spec.rb +118 -0
  54. data/spec/cmd_help_spec.rb +54 -13
  55. data/spec/cmd_init_spec.rb +1 -12
  56. data/spec/cmd_link_spec.rb +94 -72
  57. data/spec/spec_helper.rb +11 -16
  58. metadata +23 -17
@@ -0,0 +1,137 @@
1
+ # Last Modified: 2017.08.31 /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
+
8
+ require 'MrMurano/Exchange-Element'
9
+
10
+ module MrMurano
11
+ # The Exchange class represents an end user's Murano IoT Exchange Elements.
12
+ class Exchange < Business
13
+ include Http
14
+ include Verbose
15
+
16
+ def get(path='', query=nil, &block)
17
+ super
18
+ end
19
+
20
+ def element(element_id)
21
+ ret = get('exchange/' + bid + '/element/' + element_id)
22
+ return nil unless ret.is_a?(Hash) && !ret.key?(:error)
23
+ ret
24
+ end
25
+
26
+ def fetch_type(part)
27
+ whirly_start('Fetching Elements...')
28
+ ret = get('exchange/' + bid + part) do |request, http|
29
+ response = http.request(request)
30
+ case response
31
+ when Net::HTTPSuccess
32
+ workit_response(response)
33
+ else
34
+ showHttpError(request, response)
35
+ end
36
+ end
37
+ whirly_stop
38
+ return [] unless ret.is_a?(Hash) && !ret.key?(:error)
39
+ return [] unless ret.key?(:items)
40
+ unless ret[:count] == ret[:items].length
41
+ warning(
42
+ 'Unexpected: ret[:count] != ret[:items].length: ' \
43
+ "#{ret[:count]} != #{ret[:items].length}"
44
+ )
45
+ end
46
+ ret[:items]
47
+ end
48
+
49
+ def elements(**opts)
50
+ lookp = {}
51
+ # Get the user's Business metadata, including their Business tier.
52
+ overview if @ometa.nil?
53
+ # Fetch the list of Elements, including Added, Available, and Upgradeable.
54
+ items = fetch_type('/element/')
55
+ # Prepare a lookup of the Elements.
56
+ elems = items.map do |meta|
57
+ elem = MrMurano::ExchangeElement.new(meta)
58
+ lookp[elem.elementId] = elem
59
+ elem
60
+ end
61
+ # Fetch the list of Purchased elements.
62
+ items = fetch_type('/purchase/')
63
+ # Update the list of all Elements to indicate which have been purchased.
64
+ items.each do |meta|
65
+ elem = lookp[meta[:elementId]]
66
+ if !elem.nil?
67
+ elem.purchaseId = meta[:purchaseId]
68
+ # Sanity check.
69
+ meta[:element].each do |key, val|
70
+ next if elem.send(key) == val
71
+ warning(
72
+ 'Unexpected: Exchange Purchase element meta differs: ' \
73
+ "key: #{key} / elem: #{elem.send(key)} / purchase: #{val}"
74
+ )
75
+ end
76
+ else
77
+ warning("Unexpected: No Element found for Exchange Purchase: elementId: #{meta[:elementId]}")
78
+ end
79
+ end
80
+ prepare_elements(elems, **opts)
81
+ end
82
+
83
+ def prepare_elements(elems, filter_id: nil, filter_name: nil, filter_fuzzy: nil)
84
+ if filter_id || filter_name || filter_fuzzy
85
+ elems.select! do |elem|
86
+ if (
87
+ (filter_id && elem.elementId == filter_id) || \
88
+ (filter_name && elem.name == filter_name) || \
89
+ (filter_fuzzy &&
90
+ (
91
+ elem.elementId =~ /#{Regexp.escape(filter_fuzzy)}/i || \
92
+ elem.name =~ /#{Regexp.escape(filter_fuzzy)}/i
93
+ )
94
+ )
95
+ )
96
+ true
97
+ else
98
+ false
99
+ end
100
+ end
101
+ end
102
+
103
+ available = []
104
+ purchased = []
105
+ elems.sort_by(&:name)
106
+ elems.each do |elem|
107
+ if elem.purchaseId.nil?
108
+ available.push(elem)
109
+ if !@ometa[:tier].nil? && elem.tiers.include?(@ometa[:tier][:id])
110
+ elem.statusable = :available
111
+ else
112
+ elem.statusable = :upgrade
113
+ end
114
+ else
115
+ purchased.push(elem)
116
+ elem.statusable = :added
117
+ end
118
+ #@ometa[:status] = elem.status
119
+ end
120
+
121
+ [elems, available, purchased]
122
+ end
123
+
124
+ def purchase(element_id)
125
+ whirly_start('Purchasing Element...')
126
+ ret = post(
127
+ 'exchange/' + bid + '/purchase/',
128
+ elementId: element_id,
129
+ )
130
+ # Returns, e.g.,
131
+ # { bizid: "XXX", elementId: "YYY", purchaseId: "ZZZ" }
132
+ whirly_stop
133
+ ret
134
+ end
135
+ end
136
+ end
137
+
@@ -1,4 +1,4 @@
1
- # Last Modified: 2017.08.23 /coding: utf-8
1
+ # Last Modified: 2017.09.11 /coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Copyright © 2016-2017 Exosite LLC.
@@ -29,10 +29,10 @@ module MrMurano
29
29
 
30
30
  def initialize
31
31
  @solntype = 'product.id'
32
- @uriparts_sidex = 1
33
- init_sid!
34
- @uriparts = [:service, @sid, :device2]
35
- @uriparts_sidex = 1
32
+ @uriparts_apidex = 1
33
+ init_api_id!
34
+ @uriparts = [:service, @api_id, :device2]
35
+ @uriparts_apidex = 1
36
36
  @itemkey = :id
37
37
  end
38
38
 
@@ -195,7 +195,7 @@ module MrMurano
195
195
  @here = locallist
196
196
  end
197
197
 
198
- def download(_local, item)
198
+ def download(_local, item, _options=nil)
199
199
  # Not calling, e.g., `return unless download_item_allowed(item[@itemkey])`
200
200
  # See instead: syncup_after and syncdown_after/resources_write
201
201
  @here = locallist if @here.nil?
@@ -463,7 +463,7 @@ module MrMurano
463
463
  raise "Gateway info not found for #{identifier}" if info.nil?
464
464
  fqdn = info[:fqdn]
465
465
  debug "Found FQDN: #{fqdn}"
466
- fqdn = "#{@sid}.m2.exosite.io" if fqdn.nil?
466
+ fqdn = "#{@api_id}.m2.exosite.io" if fqdn.nil?
467
467
 
468
468
  uri = URI("https://#{fqdn}/provision/activate")
469
469
  http = Net::HTTP.new(uri.host, uri.port)
@@ -471,8 +471,8 @@ module MrMurano
471
471
  http.start
472
472
  request = Net::HTTP::Post.new(uri)
473
473
  request.form_data = {
474
- vendor: @sid,
475
- model: @sid,
474
+ vendor: @api_id,
475
+ model: @api_id,
476
476
  sn: identifier,
477
477
  }
478
478
  request['User-Agent'] = "MrMurano/#{MrMurano::VERSION}"
@@ -1,13 +1,15 @@
1
- # Last Modified: 2017.08.16 /coding: utf-8
1
+ # Last Modified: 2017.09.11 /coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Copyright © 2016-2017 Exosite LLC.
5
5
  # License: MIT. See LICENSE.txt.
6
6
  # vim:tw=0:ts=2:sw=2:et:ai
7
7
 
8
+ require 'MrMurano/Solution-ServiceConfig'
9
+
8
10
  module MrMurano
9
11
  class Keystore < ServiceConfig
10
- def initialize(sid=nil)
12
+ def initialize(api_id=nil)
11
13
  # FIXME/2017-07-03: Do products have a keystore service? What about other soln types?
12
14
  @solntype = 'application.id'
13
15
  super
@@ -1,4 +1,4 @@
1
- # Last Modified: 2017.08.23 /coding: utf-8
1
+ # Last Modified: 2017.08.29 /coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Copyright © 2016-2017 Exosite LLC.
@@ -77,7 +77,7 @@ module Commander
77
77
  # We override -- monkey patch -- it to do other stuff.
78
78
  alias old_run_active_command run_active_command
79
79
  def run_active_command
80
- exit @command_exit if @command_exit
80
+ exit @command_exit if defined?(@command_exit) && @command_exit
81
81
  section = active_command.name
82
82
  hooked = MrMurano::Hooked.new(section)
83
83
  hooked.check_run_pre_hook
@@ -227,9 +227,7 @@ module Commander
227
227
  opt[:switches].map { |sw| MrMurano::Verbose.fancy_ticks(sw) }.join('|')
228
228
  end
229
229
  match = match.flatten
230
- if match.length > 1
231
- match[-1] = "and #{match[-1]}"
232
- end
230
+ match[-1] = "and #{match[-1]}" if match.length > 1
233
231
  match = match.join(', ')
234
232
  MrMurano::Verbose.error("Ambiguous option: #{ambig} matches: #{match}")
235
233
  exit 2
@@ -1,4 +1,4 @@
1
- # Last Modified: 2017.08.22 /coding: utf-8
1
+ # Last Modified: 2017.09.11 /coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Copyright © 2016-2017 Exosite LLC.
@@ -10,7 +10,7 @@ require 'MrMurano/Solution'
10
10
  module MrMurano
11
11
  # …/serviceconfig
12
12
  class ServiceConfig < SolutionBase
13
- def initialize(sid=nil)
13
+ def initialize(api_id=nil)
14
14
  super
15
15
  @uriparts << :serviceconfig
16
16
  @scid = nil
@@ -58,7 +58,7 @@ module MrMurano
58
58
  post(
59
59
  '/',
60
60
  {
61
- solution_id: @sid,
61
+ solution_id: @api_id,
62
62
  service: pid,
63
63
  # 2017-06-26: "name" seems to work, but "script_key" is what web UI uses.
64
64
  # See yeti-ui/bridge/src/js/api/services.js::linkApplicationService
@@ -112,20 +112,20 @@ module MrMurano
112
112
  # A much better UI/UX happens with human intervention.
113
113
  # :nocov:
114
114
  class Services < SolutionBase
115
- def initialize(sid=nil)
115
+ def initialize(api_id=nil)
116
116
  super
117
117
  @uriparts << :service
118
118
  end
119
119
 
120
- def sid_for_name(name)
120
+ def api_id_for_name(name)
121
121
  name = name.to_s unless name.is_a? String
122
122
  scr = list.select { |i| i[:alias] == name }.first
123
123
  scr[:id]
124
124
  end
125
125
 
126
- def sid
127
- return @sid unless @sid.nil?
128
- @sid = sid_for_name(@service_name)
126
+ def api_id
127
+ return @api_id unless @api_id.nil?
128
+ @api_id = api_id_for_name(@service_name)
129
129
  end
130
130
 
131
131
  def list
@@ -137,13 +137,13 @@ module MrMurano
137
137
  # sort_by_name(ret[:items])
138
138
  end
139
139
 
140
- def schema(id=sid)
140
+ def schema(id=api_id)
141
141
  # TODO: cache schema in user dir?
142
142
  get("/#{id}/schema")
143
143
  end
144
144
 
145
145
  ## Get list of call operations from a schema
146
- def callable(id=sid, all=false)
146
+ def callable(id=api_id, all=false)
147
147
  scm = schema(id)
148
148
  calls = []
149
149
  scm[:paths].each do |path, methods|
@@ -174,14 +174,14 @@ module MrMurano
174
174
  # :nocov:
175
175
 
176
176
  class ServiceConfigApplication < ServiceConfig
177
- def initialize(sid=nil)
177
+ def initialize(api_id=nil)
178
178
  @solntype = 'application.id'
179
179
  super
180
180
  end
181
181
  end
182
182
 
183
183
  class ServiceConfigProduct < ServiceConfig
184
- def initialize(sid=nil)
184
+ def initialize(api_id=nil)
185
185
  @solntype = 'product.id'
186
186
  super
187
187
  end
@@ -1,4 +1,4 @@
1
- # Last Modified: 2017.08.23 /coding: utf-8
1
+ # Last Modified: 2017.09.11 /coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Copyright © 2016-2017 Exosite LLC.
@@ -21,7 +21,7 @@ module MrMurano
21
21
  ##
22
22
  # Things that servers do that is common.
23
23
  class ServiceBase < SolutionBase
24
- def initialize(sid=nil)
24
+ def initialize(api_id=nil)
25
25
  super
26
26
  end
27
27
 
@@ -67,6 +67,7 @@ module MrMurano
67
67
  else
68
68
  # I.e., thereitem.phantom, an "undeletable" file that does not
69
69
  # exist locally but should not be deleted from server.
70
+ # MAYBE/2017-09-07: Honor options.ignore_errors here?
70
71
  raise 'no file' unless thereitem.script
71
72
  script = thereitem.script
72
73
  end
@@ -77,7 +78,7 @@ module MrMurano
77
78
  name = mkname(thereitem)
78
79
  pst = thereitem.to_h.merge(
79
80
  #solution_id: $cfg[@solntype],
80
- solution_id: @sid,
81
+ solution_id: @api_id,
81
82
  script: script,
82
83
  alias: mkalias(thereitem),
83
84
  name: name,
@@ -174,7 +175,7 @@ module MrMurano
174
175
  [
175
176
  'cache',
176
177
  self.class.to_s.gsub(/\W+/, '_'),
177
- @sid,
178
+ @api_id,
178
179
  'yaml',
179
180
  ].join('.')
180
181
  end
@@ -258,7 +259,7 @@ module MrMurano
258
259
  attr_accessor :solution_id
259
260
  end
260
261
 
261
- def initialize(sid=nil)
262
+ def initialize(api_id=nil)
262
263
  @solntype = 'application.id'
263
264
  super
264
265
  @uriparts << :module
@@ -283,7 +284,7 @@ module MrMurano
283
284
  def mkalias(remote)
284
285
  raise "Missing parts! #{remote.to_h.to_json}" if remote.name.nil?
285
286
  #[$cfg[@solntype], remote[:name]].join('_')
286
- [@sid, remote[:name]].join('_')
287
+ [@api_id, remote[:name]].join('_')
287
288
  end
288
289
 
289
290
  def mkname(remote)
@@ -349,7 +350,7 @@ module MrMurano
349
350
  attr_accessor :updated_at
350
351
  # @return [String] Timestamp when this was created.
351
352
  attr_accessor :created_at
352
- # @return [String] The soln's product.id or application.id (Murano's apiId).
353
+ # @return [String] The soln's product.id or application.id (Murano's api_id).
353
354
  attr_accessor :solution_id
354
355
  # @return [String] Which service triggers this script.
355
356
  attr_accessor :service
@@ -366,7 +367,7 @@ module MrMurano
366
367
  attr_accessor :phantom
367
368
  end
368
369
 
369
- def initialize(sid=nil)
370
+ def initialize(api_id=nil)
370
371
  super
371
372
  @uriparts << :eventhandler
372
373
  @itemkey = :alias
@@ -378,7 +379,7 @@ module MrMurano
378
379
  def mkalias(remote)
379
380
  raise "Missing parts! #{remote.to_h.to_json}" if remote.service.nil? || remote.event.nil?
380
381
  #[$cfg[@solntype], remote[:service], remote[:event]].join('_')
381
- [@sid, remote[:service], remote[:event]].join('_')
382
+ [@api_id, remote[:service], remote[:event]].join('_')
382
383
  end
383
384
 
384
385
  def mkname(remote)
@@ -482,12 +483,12 @@ module MrMurano
482
483
  end
483
484
  end
484
485
 
485
- def default_event_script(service_or_sid, &block)
486
+ def default_event_script(service_or_api_id, &block)
486
487
  post(
487
488
  '/',
488
489
  {
489
- solution_id: @sid,
490
- service: service_or_sid,
490
+ solution_id: @api_id,
491
+ service: service_or_api_id,
491
492
  event: 'event',
492
493
  script: 'print(event)',
493
494
  },
@@ -712,7 +713,7 @@ module MrMurano
712
713
  PRODUCT_SERVICES = %w[device2 interface].freeze
713
714
 
714
715
  class EventHandlerSolnPrd < EventHandler
715
- def initialize(sid=nil)
716
+ def initialize(api_id=nil)
716
717
  @solntype = 'product.id'
717
718
  # FIXME/2017-06-20: Should we use separate directories for prod vs app?
718
719
  # See also :services in PrfFile and elsewhere;
@@ -748,7 +749,7 @@ module MrMurano
748
749
  end
749
750
 
750
751
  class EventHandlerSolnApp < EventHandler
751
- def initialize(sid=nil)
752
+ def initialize(api_id=nil)
752
753
  @solntype = 'application.id'
753
754
  # FIXME/2017-06-20: Should we use separate directories for prod vs app?
754
755
  @project_section = :services
@@ -1,4 +1,4 @@
1
- # Last Modified: 2017.08.22 /coding: utf-8
1
+ # Last Modified: 2017.09.07 /coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Copyright © 2016-2017 Exosite LLC.
@@ -56,7 +56,7 @@ module MrMurano
56
56
  post('/', remote)
57
57
  end
58
58
 
59
- def download(local, item)
59
+ def download(local, item, _options=nil)
60
60
  # needs to append/merge with file
61
61
  # for now, we'll read, modify, write
62
62
  here = []
@@ -1,4 +1,4 @@
1
- # Last Modified: 2017.08.23 /coding: utf-8
1
+ # Last Modified: 2017.09.11 /coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Copyright © 2016-2017 Exosite LLC.
@@ -20,19 +20,19 @@ module MrMurano
20
20
  include SolutionId
21
21
 
22
22
  def initialize(from=nil)
23
- @uriparts_sidex = 1
23
+ @uriparts_apidex = 1
24
24
  # Introspection. Feels hacky.
25
25
  if from.is_a? MrMurano::Solution
26
- init_sid!(from.sid)
27
- @valid_sid = from.valid_sid
26
+ init_api_id!(from.api_id)
27
+ @valid_api_id = from.valid_api_id
28
28
  # We shouldn't need to worry about other things...
29
29
  #@token = from.token
30
30
  #@http = from.http
31
31
  #@json_opts = from.json_opts
32
32
  else
33
- init_sid!(from)
33
+ init_api_id!(from)
34
34
  end
35
- @uriparts = [:solution, @sid]
35
+ @uriparts = [:solution, @api_id]
36
36
  @itemkey = :id
37
37
  @project_section = nil unless defined?(@project_section)
38
38
  end
@@ -44,7 +44,7 @@ module MrMurano
44
44
  protected
45
45
 
46
46
  def state
47
- [@sid, @valid_sid, @uriparts, @solntype, @itemkey, @project_section]
47
+ [@api_id, @valid_api_id, @sid, @uriparts, @solntype, @itemkey, @project_section]
48
48
  end
49
49
 
50
50
  public
@@ -69,7 +69,7 @@ module MrMurano
69
69
  while remaining != 0
70
70
  ret = super
71
71
  if ret.nil? && !@suppress_error
72
- warning "No solution with ID: #{@sid}"
72
+ warning "No solution with ID: #{@api_id}"
73
73
  whirly_interject { say 'Run `murano show` to see the business and list of solutions.' }
74
74
  MrMurano::SolutionBase.warn_configfile_env_maybe
75
75
  exit 1
@@ -146,11 +146,10 @@ module MrMurano
146
146
  end
147
147
 
148
148
  class Solution < SolutionBase
149
- def initialize(sid=nil)
150
- # Does it matter if we use :sid or :apiId?
151
- meta = sid if sid.is_a?(Hash)
152
- sid = sid[:sid] if sid.is_a?(Hash)
153
- super(sid)
149
+ def initialize(api_id=nil)
150
+ meta = api_id if api_id.is_a?(Hash)
151
+ api_id = api_id[:api_id] || api_id[:apiId] if api_id.is_a?(Hash)
152
+ super(api_id)
154
153
  set_name
155
154
  @meta = {}
156
155
  @valid = false
@@ -189,10 +188,10 @@ module MrMurano
189
188
  resp = get
190
189
  if resp.is_a?(Hash) && !resp.key?(:error)
191
190
  self.meta = resp
192
- @valid_sid = true
191
+ @valid_api_id = true
193
192
  else
194
193
  self.meta = {}
195
- @valid_sid = false
194
+ @valid_api_id = false
196
195
  end
197
196
  @suppress_error = false
198
197
  end
@@ -230,24 +229,22 @@ module MrMurano
230
229
  @meta = data
231
230
  # Verify the solution ID.
232
231
  # NOTE: The Solution info fetched from business/<bizid>/solutions endpoint
233
- # includes the keys, :name, :sid, and :domain (see calls to solutions()).
234
- # The solution details fetched from a call to Solution.get() include the
235
- # keys, :name, :id, and :domain, among others.
232
+ # includes the keys, :name, :api_id, :sid, and :domain (see calls to
233
+ # solutions()). The solution details fetched from a call to Solution.get()
234
+ # include the keys, :name, :id, and :domain, among others.
236
235
  # Note that the info() response does not include :type.
237
- # Also, :apiId is indicated by solutions(), too.
238
- sid = @meta[:sid] || @meta[:id] || nil
239
- unless @meta[:apiId].to_s.empty?
240
- if @meta[:apiId] != @meta[:sid]
241
- warning "Unexpected: apiId != sid: #{@meta[:apiId]} != #{@meta[:sid]}"
242
- end
243
- end
244
- unless @sid.to_s.empty? || sid.to_s == @sid.to_s
236
+ api_id = @meta[:apiId] || @meta[:id]
237
+ unless @api_id.to_s.empty? || api_id.to_s.empty? || api_id.to_s == @api_id.to_s
245
238
  warning(
246
- "#{type_name} ID mismatch. Server says #{fancy_ticks(sid)}, " \
247
- "but config says #{fancy_ticks(@sid)}."
239
+ "#{type_name} ID mismatch. Server says #{fancy_ticks(api_id)}, " \
240
+ "but config says #{fancy_ticks(@api_id)}."
248
241
  )
249
242
  end
250
- self.sid = sid
243
+ self.api_id = api_id
244
+ # NOTE: In Murano 1.0 (pre-ADC), api_id != sid; in Murano 1.1, they're ==.
245
+ # The sid is used in business/<bid>/solution/<sid>
246
+ # The apiId is used in solution/<apiId>
247
+ @sid = @meta[:sid]
251
248
  # Verify/set the name.
252
249
  unless @name.to_s.empty? || @meta[:name].to_s == @name.to_s
253
250
  warning(
@@ -256,21 +253,18 @@ module MrMurano
256
253
  )
257
254
  end
258
255
  if !@meta[:name].to_s.empty?
259
- set_name(@meta[:name])
260
- unless @valid_name || type == :solution
261
- warning(
262
- "Unexpected: Server returned invalid name: #{fancy_ticks(@meta[:name])}"
263
- )
256
+ # NOTE: Pre-ADC (a/k/a migrated) applications are not named, at least
257
+ # when you query the business/<bid>/solution/ endpoint. But when you
258
+ # call info_safe, which GETs the solution details, the name is
259
+ # the domain and contains dots, which is considered an illegal name!
260
+ if @meta[:name] != @meta[:domain]
261
+ set_name(@meta[:name])
262
+ unless @valid_name || type == :solution
263
+ warning(
264
+ "Unexpected: Server returned invalid name: #{fancy_ticks(@meta[:name])}"
265
+ )
266
+ end
264
267
  end
265
- elsif @meta[:domain]
266
- # This could be a pre-ADC/pre-Murano business.
267
- warning(
268
- "Unexpected: Server returned no name for domain: #{fancy_ticks(@meta[:domain])}"
269
- )
270
- else
271
- warning(
272
- "Unexpected: Server returned no name for solution: #{fancy_ticks(@meta)}"
273
- )
274
268
  end
275
269
  end
276
270
 
@@ -283,9 +277,9 @@ module MrMurano
283
277
  # classes should not be formatting output), but this seems okay.
284
278
  desc = ''
285
279
  desc += "#{type.to_s.capitalize}: " if add_type
286
- name = self.name || '~Unnamed~'
287
- sid = self.sid || '~No-ID~'
288
- desc += "#{Rainbow(name).underline} <#{sid}>"
280
+ name = !self.name.empty? && self.name || '~Unnamed~'
281
+ api_id = !self.api_id.empty? && self.api_id || '~No-ID~'
282
+ desc += "#{Rainbow(name).underline} <#{api_id}>"
289
283
  if domain
290
284
  desc += ' '
291
285
  desc += 'https://' unless raw_url
@@ -341,7 +335,7 @@ module MrMurano
341
335
  end
342
336
 
343
337
  def valid?
344
- @valid_sid && @valid_name
338
+ @valid_api_id && @valid_name
345
339
  end
346
340
 
347
341
  def valid_name?
@@ -358,7 +352,7 @@ module MrMurano
358
352
  end
359
353
 
360
354
  class Application < Solution
361
- def initialize(sid=nil)
355
+ def initialize(api_id=nil)
362
356
  @solntype = 'application.id'
363
357
  super
364
358
  end
@@ -391,7 +385,7 @@ The name must contain at least 1 character and no more than 63.
391
385
  end
392
386
 
393
387
  class Product < Solution
394
- def initialize(sid=nil)
388
+ def initialize(api_id=nil)
395
389
  # Code path for `murano domain`.
396
390
  @solntype = 'product.id'
397
391
  super