MuranoCLI 2.0.0

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 (151) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +21 -0
  5. data/Gemfile +27 -0
  6. data/LICENSE.txt +19 -0
  7. data/MuranoCLI.gemspec +50 -0
  8. data/MuranoCLI.iss +50 -0
  9. data/README.markdown +208 -0
  10. data/Rakefile +188 -0
  11. data/TODO.taskpaper +122 -0
  12. data/bin/mr +8 -0
  13. data/bin/murano +84 -0
  14. data/docs/demo.md +109 -0
  15. data/lib/MrMurano/Account.rb +211 -0
  16. data/lib/MrMurano/Config-Migrate.rb +47 -0
  17. data/lib/MrMurano/Config.rb +286 -0
  18. data/lib/MrMurano/Mock.rb +63 -0
  19. data/lib/MrMurano/Product-1P-Device.rb +145 -0
  20. data/lib/MrMurano/Product-Resources.rb +195 -0
  21. data/lib/MrMurano/Product.rb +358 -0
  22. data/lib/MrMurano/ProjectFile.rb +349 -0
  23. data/lib/MrMurano/Solution-Cors.rb +46 -0
  24. data/lib/MrMurano/Solution-Endpoint.rb +177 -0
  25. data/lib/MrMurano/Solution-File.rb +150 -0
  26. data/lib/MrMurano/Solution-ServiceConfig.rb +140 -0
  27. data/lib/MrMurano/Solution-Services.rb +326 -0
  28. data/lib/MrMurano/Solution-Users.rb +129 -0
  29. data/lib/MrMurano/Solution.rb +59 -0
  30. data/lib/MrMurano/SubCmdGroupContext.rb +49 -0
  31. data/lib/MrMurano/SyncUpDown.rb +565 -0
  32. data/lib/MrMurano/commands/assign.rb +57 -0
  33. data/lib/MrMurano/commands/businessList.rb +45 -0
  34. data/lib/MrMurano/commands/completion.rb +152 -0
  35. data/lib/MrMurano/commands/config.rb +67 -0
  36. data/lib/MrMurano/commands/content.rb +130 -0
  37. data/lib/MrMurano/commands/cors.rb +30 -0
  38. data/lib/MrMurano/commands/domain.rb +17 -0
  39. data/lib/MrMurano/commands/gb.rb +33 -0
  40. data/lib/MrMurano/commands/init.rb +138 -0
  41. data/lib/MrMurano/commands/keystore.rb +157 -0
  42. data/lib/MrMurano/commands/logs.rb +78 -0
  43. data/lib/MrMurano/commands/mock.rb +63 -0
  44. data/lib/MrMurano/commands/password.rb +88 -0
  45. data/lib/MrMurano/commands/postgresql.rb +41 -0
  46. data/lib/MrMurano/commands/product.rb +14 -0
  47. data/lib/MrMurano/commands/productCreate.rb +39 -0
  48. data/lib/MrMurano/commands/productDelete.rb +33 -0
  49. data/lib/MrMurano/commands/productDevice.rb +84 -0
  50. data/lib/MrMurano/commands/productDeviceIdCmds.rb +86 -0
  51. data/lib/MrMurano/commands/productList.rb +45 -0
  52. data/lib/MrMurano/commands/productWrite.rb +27 -0
  53. data/lib/MrMurano/commands/show.rb +80 -0
  54. data/lib/MrMurano/commands/solution.rb +14 -0
  55. data/lib/MrMurano/commands/solutionCreate.rb +39 -0
  56. data/lib/MrMurano/commands/solutionDelete.rb +34 -0
  57. data/lib/MrMurano/commands/solutionList.rb +45 -0
  58. data/lib/MrMurano/commands/status.rb +92 -0
  59. data/lib/MrMurano/commands/sync.rb +60 -0
  60. data/lib/MrMurano/commands/timeseries.rb +115 -0
  61. data/lib/MrMurano/commands/tsdb.rb +271 -0
  62. data/lib/MrMurano/commands/usage.rb +23 -0
  63. data/lib/MrMurano/commands/zshcomplete.erb +112 -0
  64. data/lib/MrMurano/commands.rb +32 -0
  65. data/lib/MrMurano/hash.rb +20 -0
  66. data/lib/MrMurano/http.rb +153 -0
  67. data/lib/MrMurano/makePretty.rb +75 -0
  68. data/lib/MrMurano/schema/pf-v1.0.0.yaml +114 -0
  69. data/lib/MrMurano/schema/sf-v0.2.0.yaml +77 -0
  70. data/lib/MrMurano/schema/sf-v0.3.0.yaml +78 -0
  71. data/lib/MrMurano/template/mock.erb +9 -0
  72. data/lib/MrMurano/template/projectFile.murano.erb +81 -0
  73. data/lib/MrMurano/verbosing.rb +99 -0
  74. data/lib/MrMurano/version.rb +4 -0
  75. data/lib/MrMurano.rb +20 -0
  76. data/spec/Account-Passwords_spec.rb +242 -0
  77. data/spec/Account_spec.rb +272 -0
  78. data/spec/ConfigFile_spec.rb +50 -0
  79. data/spec/ConfigMigrate_spec.rb +89 -0
  80. data/spec/Config_spec.rb +409 -0
  81. data/spec/Http_spec.rb +204 -0
  82. data/spec/MakePretties_spec.rb +118 -0
  83. data/spec/Mock_spec.rb +53 -0
  84. data/spec/ProductBase_spec.rb +113 -0
  85. data/spec/ProductContent_spec.rb +162 -0
  86. data/spec/ProductResources_spec.rb +329 -0
  87. data/spec/Product_1P_Device_spec.rb +202 -0
  88. data/spec/Product_1P_RPC_spec.rb +175 -0
  89. data/spec/Product_spec.rb +153 -0
  90. data/spec/ProjectFile_spec.rb +324 -0
  91. data/spec/Solution-Cors_spec.rb +164 -0
  92. data/spec/Solution-Endpoint_spec.rb +581 -0
  93. data/spec/Solution-File_spec.rb +212 -0
  94. data/spec/Solution-ServiceConfig_spec.rb +202 -0
  95. data/spec/Solution-ServiceDevice_spec.rb +176 -0
  96. data/spec/Solution-ServiceEventHandler_spec.rb +385 -0
  97. data/spec/Solution-ServiceModules_spec.rb +465 -0
  98. data/spec/Solution-UsersRoles_spec.rb +207 -0
  99. data/spec/Solution_spec.rb +92 -0
  100. data/spec/SyncRoot_spec.rb +83 -0
  101. data/spec/SyncUpDown_spec.rb +495 -0
  102. data/spec/Verbosing_spec.rb +279 -0
  103. data/spec/_workspace.rb +27 -0
  104. data/spec/cmd_assign_spec.rb +51 -0
  105. data/spec/cmd_business_spec.rb +59 -0
  106. data/spec/cmd_common.rb +72 -0
  107. data/spec/cmd_config_spec.rb +68 -0
  108. data/spec/cmd_content_spec.rb +71 -0
  109. data/spec/cmd_cors_spec.rb +50 -0
  110. data/spec/cmd_device_spec.rb +96 -0
  111. data/spec/cmd_domain_spec.rb +32 -0
  112. data/spec/cmd_init_spec.rb +30 -0
  113. data/spec/cmd_keystore_spec.rb +97 -0
  114. data/spec/cmd_password_spec.rb +62 -0
  115. data/spec/cmd_status_spec.rb +239 -0
  116. data/spec/cmd_syncdown_spec.rb +86 -0
  117. data/spec/cmd_syncup_spec.rb +62 -0
  118. data/spec/cmd_usage_spec.rb +36 -0
  119. data/spec/fixtures/.mrmuranorc +9 -0
  120. data/spec/fixtures/ProjectFiles/invalid.yaml +9 -0
  121. data/spec/fixtures/ProjectFiles/only_meta.yaml +24 -0
  122. data/spec/fixtures/ProjectFiles/with_routes.yaml +27 -0
  123. data/spec/fixtures/SolutionFiles/0.2.0.json +20 -0
  124. data/spec/fixtures/SolutionFiles/0.2.0_invalid.json +18 -0
  125. data/spec/fixtures/SolutionFiles/0.2.json +21 -0
  126. data/spec/fixtures/SolutionFiles/0.3.0.json +20 -0
  127. data/spec/fixtures/SolutionFiles/0.3.0_invalid.json +19 -0
  128. data/spec/fixtures/SolutionFiles/0.3.json +20 -0
  129. data/spec/fixtures/SolutionFiles/basic.json +20 -0
  130. data/spec/fixtures/SolutionFiles/secret.json +6 -0
  131. data/spec/fixtures/configfile +9 -0
  132. data/spec/fixtures/dumped_config +42 -0
  133. data/spec/fixtures/mrmuranorc_deleted_bob +8 -0
  134. data/spec/fixtures/mrmuranorc_tool_bob +3 -0
  135. data/spec/fixtures/product_spec_files/example.exoline.spec.yaml +116 -0
  136. data/spec/fixtures/product_spec_files/example.murano.spec.yaml +14 -0
  137. data/spec/fixtures/product_spec_files/gwe.exoline.spec.yaml +21 -0
  138. data/spec/fixtures/product_spec_files/gwe.murano.spec.yaml +16 -0
  139. data/spec/fixtures/product_spec_files/lightbulb-no-state.yaml +11 -0
  140. data/spec/fixtures/product_spec_files/lightbulb.yaml +14 -0
  141. data/spec/fixtures/roles-three.yaml +11 -0
  142. data/spec/fixtures/syncable_content/assets/icon.png +0 -0
  143. data/spec/fixtures/syncable_content/assets/index.html +0 -0
  144. data/spec/fixtures/syncable_content/assets/js/script.js +0 -0
  145. data/spec/fixtures/syncable_content/modules/table_util.lua +58 -0
  146. data/spec/fixtures/syncable_content/routes/manyRoutes.lua +11 -0
  147. data/spec/fixtures/syncable_content/routes/singleRoute.lua +5 -0
  148. data/spec/fixtures/syncable_content/services/devdata.lua +18 -0
  149. data/spec/fixtures/syncable_content/services/timers.lua +4 -0
  150. data/spec/spec_helper.rb +119 -0
  151. metadata +498 -0
data/TODO.taskpaper ADDED
@@ -0,0 +1,122 @@
1
+ Readme:
2
+ - Add more walk-thrus of common actions. (create new solution, …)
3
+ - Look into using VCR for testing. @pri(low)
4
+
5
+ Commands:
6
+ - Init command. @done(2016-11-28)
7
+ - Empty sub-commands should return help. @done(2016-11-21)
8
+ There are a bunch of empty sub-commands that prefix another layer. Such as
9
+ assign, content, product, and others. Those should be impemented as a ‘help’
10
+ only command. That is they should return help like the plain `mr` command, but
11
+ just for their sub-section of things
12
+ - Errors and Warnings should get sent to STDERR @done(2016-11-03)
13
+ - Need a more consistent output format. 'pp' is still used in many places. @done(2016-11-03)
14
+ Maybe have a tool setting for output format? json, yaml, pp, csv, table ?
15
+ - Do we need rainbow since highline does ANSI color too? @done(2016-11-02)
16
+ - Status will show {modules,eventhandlers} have changes when they don’t. @done(2016-09-23)
17
+ - First time run needs to be smoothed out. @done(2016-08-09)
18
+ - Default for most commands should be -same @done(2016-08-02)
19
+ - Add Diff Command @done(2016-07-27)
20
+
21
+ Account:
22
+ - token is refetched many times. Do this once per run. @done(2016-09-12)
23
+ - Netrc library (or the netrc format) doesn't allow '#' in passwords. @done(2016-08-10)
24
+
25
+ Endpoints:
26
+ - In fetch(); add content_type to script header if not application/json @done(2016-12-06)
27
+ - Add support for multiple endpoints in one file @pri(high) @done(2016-11-18)
28
+ - Add directory support like in modules @done(2016-07-26)
29
+
30
+ Files:
31
+ - Switch to mime-types v3 @pri(low)
32
+ - Add ignore patterns to config @done(2016-12-20)
33
+ - Figure out how to make the hexed-sha checksum faster. @done(2016-09-23)
34
+ - Fix upload. @done(2016-08-01)
35
+ - Files won't update, they always delete then add. @done(2016-07-28)
36
+
37
+ Users and Roles:
38
+ Much of this is stuck until we get more docs on the User/Role management
39
+ - Figure out how to upload (create and update) user info.
40
+ - Figure out how to add Roles to Users in the local data and upload it.
41
+ - Fix diff for Users and Roles.
42
+ - Have hash keys in the yaml be strings not symbols. (don't start with colon) @done(2016-07-27)
43
+
44
+ CORS:
45
+ - Get working with sync up/down. @done(2016-10-28)
46
+ - GET&PUT /cors data @done(2016-09-08)
47
+
48
+ TSDB:
49
+ - For query, if no metrics on cmdline, then do listMetrics and use all. @done(2016-11-21)
50
+ well, the first 1000 or whatever we get from a single call to listMetrics
51
+ - Query should handle tags prefixed with @ to match write. @done(2016-11-21)
52
+ - Add support for new TSDB service. @pri(high) @done(2016-11-03)
53
+
54
+ Timeseries:
55
+ - Add CSV output option. @done(2016-09-09)
56
+
57
+ Product:
58
+ - Add option for progress bar when uploading content files.
59
+ - Support multiple products. @pri(low)
60
+ Think about how this would work. There is the syncing of the resources, and then
61
+ some of the commands that use product.id.
62
+ Which product.id maps to which resource file?
63
+ - Auto convert exoline spec files into murano spec files on upload? @done(2016-10-27)
64
+ Not doing this. Convert is there if you need it.
65
+ - write alias command @done(2016-09-26)
66
+ - Need to add way to set the product ID on a device eventhandler. @done(2016-08-01)
67
+
68
+ Service Device:
69
+ - When listing and business.id is missing, gracefully fall back to --idonly @done(2016-09-12)
70
+
71
+ Config:
72
+ - Store passwords in system Keychain on system that have a Keychain.
73
+ mac OS does, various Linux desktops have a couple differnet ones. Not sure about
74
+ Windows.
75
+ MacOS: https://github.com/xli/mac-keychain
76
+ Windows8+: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh465069.aspx
77
+ Linux: https://en.wikipedia.org/wiki/GNOME_Keyring
78
+ https://en.wikipedia.org/wiki/KWallet
79
+
80
+ Plus things like 1Password, LastPass, KeePass, and others.
81
+
82
+ - Add config sync.bydefault to set which things sync{up,down} by default @done(2017-01-05)
83
+ It is internally hardcoded to be -s, -a, -m, -e right now.
84
+ - Add ENV['MR_CONFIGFILE'] path to file to load like --configfile @done(2016-09-22)
85
+ - Maybe add dotenv support. @done(2016-09-22)
86
+ - Think about adding dev,staging,prod system; how would that work? @done(2016-09-16)
87
+
88
+ SyncUpDown:
89
+ - Document the hash keys for an item. @pri(high)
90
+ Also consider turning that hash into a Struct
91
+ - Allow specifying local files to limit actions to. @done(2017-03-03)
92
+
93
+ SolutionBase:
94
+ - All network traffic is serialized. Make some parallel.
95
+ This might break some things.
96
+ - Errors from the server should be displayed prettier. @done(2016-09-26)
97
+ - JSON parse should use symbols for keys. @done(2016-09-01)
98
+ - Add the --curl verbose option. @done(2016-08-12)
99
+ - Rebuild how local names and paths are computed from remote items. @done(2016-07-27)
100
+
101
+ Windows:
102
+ - Need to test with http://rubyinstaller.org on Windows. @pri(high) @done(2016-12-21)
103
+ - Look into http://ocra.rubyforge.org for building an exec. @pri(high) @done(2016-12-21)
104
+
105
+ Bundles:
106
+ - Revisit this idea. Its complexity may not be worth its value.
107
+ - Test syncdown behavor.
108
+ - Work on design @done(2016-08-09)
109
+ Thinking of something like VIM bundles. A directory of directories. Each with a
110
+ manafest file? (maybe) A Bundle is a group of modules, endpoints, static files
111
+ and the other things.
112
+
113
+ There needs to be some layering logic added, where the bundles are stacked and
114
+ then the top-level files are stack on top of that. This builds the final map of
115
+ what gets uploaded to the server.
116
+
117
+ For syncdown, bundles are considered to be read-only.
118
+
119
+ The goal is to have things like Users or Debug that you just include into a
120
+ project. And it gives all of the library, routes, statics and whatnot that you
121
+ need.
122
+
data/bin/mr ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ require 'highline'
3
+
4
+ puts HighLine.color("!"*80, :yellow)
5
+ puts HighLine.color("The command 'mr' is deprecated. Use 'murano' instead.", :yellow)
6
+ puts HighLine.color("!"*80, :yellow)
7
+
8
+ exec 'murano', *ARGV
data/bin/murano ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'commander/import'
5
+ require 'pathname'
6
+ require 'MrMurano'
7
+ require 'pp'
8
+ require 'dotenv'
9
+ Dotenv.load
10
+
11
+ Signal.trap('INT', 'EXIT') # Don't drop traces on ^C
12
+
13
+ program :version, MrMurano::VERSION
14
+ program :description, %{Manage a Solution and Product in Exosite's Murano}
15
+
16
+ global_option('-V', '--verbose', 'Be chatty') {
17
+ $cfg['tool.verbose'] = true
18
+ }
19
+ global_option('-n', '--dry', %{Don't run actions that make changes}) {
20
+ $cfg['tool.dry'] = true
21
+ $cfg['tool.verbose'] = true # dry implies verbose
22
+ }
23
+ global_option('-L', '--curl', 'Print out a curl command for each network call') {
24
+ $cfg['tool.curldebug'] = true
25
+ }
26
+ global_option '--skip-plugins', %{Don't load plugins. Good for when one goes bad.}
27
+
28
+ global_option('-C', '--configfile FILE', %{Load additional configuration file}) {|file|
29
+ # this is called after all of the top level code in this file.
30
+ $cfg.load_specific(file)
31
+ }
32
+ global_option('-c', '--config KEY=VALUE', %{Set a single config key}) {|param|
33
+ key, value = param.split('=', 2)
34
+ # a=b :> ["a","b"]
35
+ # a= :> ["a",""]
36
+ # a :> ["a"]
37
+ raise "Bad config '#{param}'" if key.nil?
38
+ if value.nil? then
39
+ $cfg[key] = 'true'
40
+ else
41
+ $cfg[key] = value
42
+ end
43
+ }
44
+
45
+ default_command :help
46
+ #default_command :syncup
47
+
48
+ $cfg = MrMurano::Config.new
49
+ $cfg.load
50
+ $project = MrMurano::ProjectFile.new
51
+ $project.load
52
+
53
+ # Basic command support is:
54
+ # - read/write config file in [Project, User, System] (all are optional)
55
+ # - Introspection for tab completion.
56
+ # - Look for tools in PATH that are +x and "mr-foo..."
57
+
58
+
59
+ # Look for plug-ins
60
+ pgds = [
61
+ Pathname.new(Dir.home) + '.mrmurano' + 'plugins',
62
+ Pathname.new(Dir.home) + '.murano' + 'plugins'
63
+ ]
64
+ # Add plugin dirs from configs
65
+ # This is run before the command line options are parsed, so need to check old way.
66
+ if not ARGV.include? '--skip-plugins' then
67
+ pgds << Pathname.new(ENV['MR_MURANO_PLUGIN_DIR']) if ENV.has_key? 'MR_MURANO_PLUGIN_DIR'
68
+ pgds << Pathname.new(ENV['MURANO_PLUGIN_DIR']) if ENV.has_key? 'MURANO_PLUGIN_DIR'
69
+ pgds.each do |path|
70
+ next unless path.exist?
71
+ path.each_child do |plugin|
72
+ next if plugin.directory?
73
+ next unless plugin.readable?
74
+ next if plugin.basename.fnmatch('.*') # don't read anything starting with .
75
+ begin
76
+ require plugin.to_s
77
+ rescue Exception => e
78
+ $stderr.puts "Failed to load plugin at #{plugin} because #{e}"
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ # vim: set ai et sw=2 ts=2 :
data/docs/demo.md ADDED
@@ -0,0 +1,109 @@
1
+
2
+
3
+ # Every sub-command will --help
4
+
5
+ # Start anew
6
+ - Clone project: `git clone https://github.com/tadpol/GWE-Multitool.git demo01`
7
+ - `cd demo01`
8
+
9
+ - Pick a bussiness: `mr business list`
10
+ - Set it: `mr config business.id ZZZZZZZZZ`
11
+
12
+ - Create a product: `mr product create myawesomeproduct`
13
+ - Save the result: `mr config product.id YYYYYYYYY`
14
+
15
+ - Set the product definition: `mr config product.spec gwe-multitool.yaml`
16
+ - Set the directory to look for specs. `mr config location.specs spec`
17
+ - Sync the product definition up: `mr syncup -V --specs`
18
+
19
+ - Create a solution: `mr solution create myawesomesolution`
20
+ - Save the result: `mr config solution.id XXXXXX`
21
+ - Assign the product to the solution: `mr assign set`
22
+
23
+ # What got configured?
24
+ `mr config --dump`
25
+
26
+
27
+
28
+
29
+
30
+
31
+ # <voice type='orc'>Work Work</voice>
32
+
33
+ - What is going to change? `mr status`
34
+ - Sync solution code up: `mr syncup -V`
35
+
36
+ - Change a file
37
+ - What is going to change? `mr status`
38
+ - Details of change: `mr diff`
39
+
40
+
41
+
42
+
43
+ # Devices
44
+ - Add a real device: `mr product device enable 42:42:42:42:42:42`
45
+ - !!!cheet and activate by hand: `mr product device activate 42:42:42:42:42:42`
46
+ - Which resources are there? `mr product spec pull`
47
+ - What did the device write to that one resource?
48
+ `mr product device read 42:42:42:42:42:42 update_interval`
49
+ - `mr product device write 42:42:42:42:42:42 update_interval 300`
50
+
51
+
52
+
53
+ # Multiple configs
54
+ Because Developing, Staging, Production.
55
+
56
+ Set addition config file to load with `MR_CONFIGFILE`
57
+
58
+ Also supports '.env'
59
+
60
+
61
+
62
+
63
+ # Device Content Area
64
+
65
+ See GWE.
66
+
67
+
68
+
69
+
70
+
71
+ # Debugging
72
+
73
+ ## Logs
74
+ - `mr logs`
75
+ - `mr logs --follow`
76
+
77
+
78
+
79
+
80
+
81
+
82
+ ## Keystore
83
+ ### What is in the Keystore?
84
+ `mr keystore list`
85
+
86
+ ### Write and Read a Key
87
+ - `mr keystore set test greebled`
88
+ - `mr keystore get test`
89
+
90
+ ### Write to a Set
91
+ - `mr keystore command sadd myset greebled`
92
+ Or any other supported Redis command.
93
+
94
+ ### Remove just the ones with 'socketmap'
95
+ `mr keystore list | grep socketmap | xargs -L1 mr keystore delete`
96
+
97
+
98
+
99
+
100
+ ## TSDB
101
+
102
+ - `mr tsdb list metrics`
103
+ - `mr tsdb list tags`
104
+ - `mr tsdb query @sn=1 temp0`
105
+ - `mr tsdb query @sn=1 temp0 --limit=4`
106
+ - `mr tsdb query @sn=1 --limit=10 -c outformat=csv --epoch ms`
107
+
108
+
109
+
@@ -0,0 +1,211 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'json'
4
+ require 'date'
5
+ require 'pathname'
6
+ require 'yaml'
7
+ require 'MrMurano/Config'
8
+ require 'MrMurano/http'
9
+ require 'MrMurano/verbosing'
10
+
11
+ module MrMurano
12
+ class Passwords
13
+ include Verbose
14
+ def initialize(path=nil)
15
+ path = $cfg.file_at('passwords', :user) if path.nil?
16
+ path = Pathname.new(path) unless path.kind_of? Pathname
17
+ @path = path
18
+ @data = nil
19
+ end
20
+ def load()
21
+ if @path.exist? then
22
+ @path.chmod(0600)
23
+ @path.open('rb') do |io|
24
+ @data = YAML.load(io)
25
+ end
26
+ end
27
+ end
28
+ def save()
29
+ @path.dirname.mkpath unless @path.dirname.exist?
30
+ @path.open('wb') do |io|
31
+ io << @data.to_yaml
32
+ end
33
+ @path.chmod(0600)
34
+ end
35
+ def set(host, user, pass)
36
+ unless @data.kind_of? Hash then
37
+ @data = {host=>{user=>pass}}
38
+ return
39
+ end
40
+ hd = @data[host]
41
+ if hd.nil? or not hd.kind_of?(Hash) then
42
+ @data[host] = {user=>pass}
43
+ return
44
+ end
45
+ @data[host][user] = pass
46
+ return
47
+ end
48
+ def get(host, user)
49
+ return ENV['MURANO_PASSWORD'] unless ENV['MURANO_PASSWORD'].nil?
50
+ unless ENV['MR_PASSWORD'].nil? then
51
+ warning %{Using depercated ENV "MR_PASSWORD", please rename to "MURANO_PASSWORD"}
52
+ return ENV['MR_PASSWORD']
53
+ end
54
+ return nil unless @data.kind_of? Hash
55
+ return nil unless @data.has_key? host
56
+ return nil unless @data[host].kind_of? Hash
57
+ return nil unless @data[host].has_key? user
58
+ return @data[host][user]
59
+ end
60
+
61
+ ## Remove the password for a user
62
+ def remove(host, user)
63
+ if @data.kind_of? Hash then
64
+ hd = @data[host]
65
+ if not hd.nil? and hd.kind_of?(Hash) then
66
+ if hd.has_key? user then
67
+ @data[host].delete user
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ ## Get all hosts and usernames. (does not return the passwords)
74
+ def list
75
+ ret = {}
76
+ @data.each_pair{|key,value| ret[key] = value.keys} unless @data.nil?
77
+ ret
78
+ end
79
+ end
80
+
81
+ class Account
82
+ include Http
83
+ include Verbose
84
+
85
+ def endPoint(path)
86
+ URI('https://' + $cfg['net.host'] + '/api:1/' + path.to_s)
87
+ end
88
+
89
+ def _loginInfo
90
+ host = $cfg['net.host']
91
+ user = $cfg['user.name']
92
+ if user.nil? or user.empty? then
93
+ error("No Murano user account found; please login")
94
+ user = ask("User name: ")
95
+ $cfg.set('user.name', user, :user)
96
+ end
97
+ pff = $cfg.file_at('passwords', :user)
98
+ pf = Passwords.new(pff)
99
+ pf.load
100
+ pws = pf.get(host, user)
101
+ if pws.nil? then
102
+ error("Couldn't find password for #{user}")
103
+ pws = ask("Password: ") { |q| q.echo = "*" }
104
+ pf.set(host, user, pws)
105
+ pf.save
106
+ end
107
+ {
108
+ :email => $cfg['user.name'],
109
+ :password => pws
110
+ }
111
+ end
112
+
113
+ # Store the token in a class variable so that we only fetch it once per run
114
+ # session of this tool
115
+ @@token = nil
116
+ def token
117
+ if @@token.nil? then
118
+ # Cannot have token call token, so cannot use workit.
119
+ uri = endPoint('token/')
120
+ request = Net::HTTP::Post.new(uri)
121
+ request['User-Agent'] = "MrMurano/#{MrMurano::VERSION}"
122
+ request.content_type = 'application/json'
123
+ curldebug(request)
124
+ #request.basic_auth(username(), password())
125
+ request.body = JSON.generate(_loginInfo)
126
+
127
+ response = http.request(request)
128
+ case response
129
+ when Net::HTTPSuccess
130
+ token = JSON.parse(response.body, json_opts)
131
+ @@token = token[:token]
132
+ else
133
+ showHttpError(request, response)
134
+ error "Check to see if username and password are correct."
135
+ @@token = nil
136
+ end
137
+ end
138
+ @@token
139
+ end
140
+
141
+ def token_reset(value=nil)
142
+ @@token = value
143
+ end
144
+
145
+ def new_account(email, name, company="")
146
+ post('/key/', {
147
+ :email=>email,
148
+ :name=>name,
149
+ :company=>company,
150
+ :source=>'signup',
151
+ })
152
+ end
153
+
154
+ def reset_account(email)
155
+ post('/key/', { :email=>email, :source=>'reset' })
156
+ end
157
+
158
+ def accept_account(token, password)
159
+ post("/key/#{token}", {:password=>password})
160
+ end
161
+
162
+ def businesses
163
+ _loginInfo if $cfg['user.name'].nil?
164
+ get('user/' + $cfg['user.name'] + '/membership/')
165
+ end
166
+
167
+ def new_business(name)
168
+ post('/business/', {:name=>name})
169
+ end
170
+
171
+ def delete_business(id)
172
+ delete("/business/#{id}")
173
+ end
174
+
175
+ def products
176
+ raise "Missing Business ID" if $cfg['business.id'].nil?
177
+ get('business/' + $cfg['business.id'] + '/product/')
178
+ end
179
+
180
+ ## Create a new product in the current business
181
+ def new_product(name, type='onepModel')
182
+ raise "Missing Business ID" if $cfg['business.id'].nil?
183
+ post('business/' + $cfg['business.id'] + '/product/', {:label=>name, :type=>type})
184
+ end
185
+
186
+ def delete_product(modelId)
187
+ raise "Missing Business ID" if $cfg['business.id'].nil?
188
+ delete('business/' + $cfg['business.id'] + '/product/' + modelId)
189
+ end
190
+
191
+ def solutions
192
+ raise "Missing Business ID" if $cfg['business.id'].nil?
193
+ get('business/' + $cfg['business.id'] + '/solution/')
194
+ end
195
+
196
+ ## Create a new solution
197
+ def new_solution(name, type='dataApi')
198
+ raise "Missing Business ID" if $cfg['business.id'].nil?
199
+ raise "Solution name must be a valid domain name component" unless name.match(/^[a-zA-Z0-9]([-a-zA-Z0-9]{0,61}[a-zA-Z0-9]{0,1}|[a-zA-Z0-9]{0,62})$/)
200
+ post('business/' + $cfg['business.id'] + '/solution/', {:label=>name, :type=>type})
201
+ end
202
+
203
+ def delete_solution(apiId)
204
+ raise "Missing Business ID" if $cfg['business.id'].nil?
205
+ delete('business/' + $cfg['business.id'] + '/solution/' + apiId)
206
+ end
207
+
208
+ end
209
+ end
210
+
211
+ # vim: set ai et sw=2 ts=2 :