MuranoCLI 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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 :