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.
- checksums.yaml +7 -0
- data/.gitignore +28 -0
- data/.rspec +2 -0
- data/.travis.yml +21 -0
- data/Gemfile +27 -0
- data/LICENSE.txt +19 -0
- data/MuranoCLI.gemspec +50 -0
- data/MuranoCLI.iss +50 -0
- data/README.markdown +208 -0
- data/Rakefile +188 -0
- data/TODO.taskpaper +122 -0
- data/bin/mr +8 -0
- data/bin/murano +84 -0
- data/docs/demo.md +109 -0
- data/lib/MrMurano/Account.rb +211 -0
- data/lib/MrMurano/Config-Migrate.rb +47 -0
- data/lib/MrMurano/Config.rb +286 -0
- data/lib/MrMurano/Mock.rb +63 -0
- data/lib/MrMurano/Product-1P-Device.rb +145 -0
- data/lib/MrMurano/Product-Resources.rb +195 -0
- data/lib/MrMurano/Product.rb +358 -0
- data/lib/MrMurano/ProjectFile.rb +349 -0
- data/lib/MrMurano/Solution-Cors.rb +46 -0
- data/lib/MrMurano/Solution-Endpoint.rb +177 -0
- data/lib/MrMurano/Solution-File.rb +150 -0
- data/lib/MrMurano/Solution-ServiceConfig.rb +140 -0
- data/lib/MrMurano/Solution-Services.rb +326 -0
- data/lib/MrMurano/Solution-Users.rb +129 -0
- data/lib/MrMurano/Solution.rb +59 -0
- data/lib/MrMurano/SubCmdGroupContext.rb +49 -0
- data/lib/MrMurano/SyncUpDown.rb +565 -0
- data/lib/MrMurano/commands/assign.rb +57 -0
- data/lib/MrMurano/commands/businessList.rb +45 -0
- data/lib/MrMurano/commands/completion.rb +152 -0
- data/lib/MrMurano/commands/config.rb +67 -0
- data/lib/MrMurano/commands/content.rb +130 -0
- data/lib/MrMurano/commands/cors.rb +30 -0
- data/lib/MrMurano/commands/domain.rb +17 -0
- data/lib/MrMurano/commands/gb.rb +33 -0
- data/lib/MrMurano/commands/init.rb +138 -0
- data/lib/MrMurano/commands/keystore.rb +157 -0
- data/lib/MrMurano/commands/logs.rb +78 -0
- data/lib/MrMurano/commands/mock.rb +63 -0
- data/lib/MrMurano/commands/password.rb +88 -0
- data/lib/MrMurano/commands/postgresql.rb +41 -0
- data/lib/MrMurano/commands/product.rb +14 -0
- data/lib/MrMurano/commands/productCreate.rb +39 -0
- data/lib/MrMurano/commands/productDelete.rb +33 -0
- data/lib/MrMurano/commands/productDevice.rb +84 -0
- data/lib/MrMurano/commands/productDeviceIdCmds.rb +86 -0
- data/lib/MrMurano/commands/productList.rb +45 -0
- data/lib/MrMurano/commands/productWrite.rb +27 -0
- data/lib/MrMurano/commands/show.rb +80 -0
- data/lib/MrMurano/commands/solution.rb +14 -0
- data/lib/MrMurano/commands/solutionCreate.rb +39 -0
- data/lib/MrMurano/commands/solutionDelete.rb +34 -0
- data/lib/MrMurano/commands/solutionList.rb +45 -0
- data/lib/MrMurano/commands/status.rb +92 -0
- data/lib/MrMurano/commands/sync.rb +60 -0
- data/lib/MrMurano/commands/timeseries.rb +115 -0
- data/lib/MrMurano/commands/tsdb.rb +271 -0
- data/lib/MrMurano/commands/usage.rb +23 -0
- data/lib/MrMurano/commands/zshcomplete.erb +112 -0
- data/lib/MrMurano/commands.rb +32 -0
- data/lib/MrMurano/hash.rb +20 -0
- data/lib/MrMurano/http.rb +153 -0
- data/lib/MrMurano/makePretty.rb +75 -0
- data/lib/MrMurano/schema/pf-v1.0.0.yaml +114 -0
- data/lib/MrMurano/schema/sf-v0.2.0.yaml +77 -0
- data/lib/MrMurano/schema/sf-v0.3.0.yaml +78 -0
- data/lib/MrMurano/template/mock.erb +9 -0
- data/lib/MrMurano/template/projectFile.murano.erb +81 -0
- data/lib/MrMurano/verbosing.rb +99 -0
- data/lib/MrMurano/version.rb +4 -0
- data/lib/MrMurano.rb +20 -0
- data/spec/Account-Passwords_spec.rb +242 -0
- data/spec/Account_spec.rb +272 -0
- data/spec/ConfigFile_spec.rb +50 -0
- data/spec/ConfigMigrate_spec.rb +89 -0
- data/spec/Config_spec.rb +409 -0
- data/spec/Http_spec.rb +204 -0
- data/spec/MakePretties_spec.rb +118 -0
- data/spec/Mock_spec.rb +53 -0
- data/spec/ProductBase_spec.rb +113 -0
- data/spec/ProductContent_spec.rb +162 -0
- data/spec/ProductResources_spec.rb +329 -0
- data/spec/Product_1P_Device_spec.rb +202 -0
- data/spec/Product_1P_RPC_spec.rb +175 -0
- data/spec/Product_spec.rb +153 -0
- data/spec/ProjectFile_spec.rb +324 -0
- data/spec/Solution-Cors_spec.rb +164 -0
- data/spec/Solution-Endpoint_spec.rb +581 -0
- data/spec/Solution-File_spec.rb +212 -0
- data/spec/Solution-ServiceConfig_spec.rb +202 -0
- data/spec/Solution-ServiceDevice_spec.rb +176 -0
- data/spec/Solution-ServiceEventHandler_spec.rb +385 -0
- data/spec/Solution-ServiceModules_spec.rb +465 -0
- data/spec/Solution-UsersRoles_spec.rb +207 -0
- data/spec/Solution_spec.rb +92 -0
- data/spec/SyncRoot_spec.rb +83 -0
- data/spec/SyncUpDown_spec.rb +495 -0
- data/spec/Verbosing_spec.rb +279 -0
- data/spec/_workspace.rb +27 -0
- data/spec/cmd_assign_spec.rb +51 -0
- data/spec/cmd_business_spec.rb +59 -0
- data/spec/cmd_common.rb +72 -0
- data/spec/cmd_config_spec.rb +68 -0
- data/spec/cmd_content_spec.rb +71 -0
- data/spec/cmd_cors_spec.rb +50 -0
- data/spec/cmd_device_spec.rb +96 -0
- data/spec/cmd_domain_spec.rb +32 -0
- data/spec/cmd_init_spec.rb +30 -0
- data/spec/cmd_keystore_spec.rb +97 -0
- data/spec/cmd_password_spec.rb +62 -0
- data/spec/cmd_status_spec.rb +239 -0
- data/spec/cmd_syncdown_spec.rb +86 -0
- data/spec/cmd_syncup_spec.rb +62 -0
- data/spec/cmd_usage_spec.rb +36 -0
- data/spec/fixtures/.mrmuranorc +9 -0
- data/spec/fixtures/ProjectFiles/invalid.yaml +9 -0
- data/spec/fixtures/ProjectFiles/only_meta.yaml +24 -0
- data/spec/fixtures/ProjectFiles/with_routes.yaml +27 -0
- data/spec/fixtures/SolutionFiles/0.2.0.json +20 -0
- data/spec/fixtures/SolutionFiles/0.2.0_invalid.json +18 -0
- data/spec/fixtures/SolutionFiles/0.2.json +21 -0
- data/spec/fixtures/SolutionFiles/0.3.0.json +20 -0
- data/spec/fixtures/SolutionFiles/0.3.0_invalid.json +19 -0
- data/spec/fixtures/SolutionFiles/0.3.json +20 -0
- data/spec/fixtures/SolutionFiles/basic.json +20 -0
- data/spec/fixtures/SolutionFiles/secret.json +6 -0
- data/spec/fixtures/configfile +9 -0
- data/spec/fixtures/dumped_config +42 -0
- data/spec/fixtures/mrmuranorc_deleted_bob +8 -0
- data/spec/fixtures/mrmuranorc_tool_bob +3 -0
- data/spec/fixtures/product_spec_files/example.exoline.spec.yaml +116 -0
- data/spec/fixtures/product_spec_files/example.murano.spec.yaml +14 -0
- data/spec/fixtures/product_spec_files/gwe.exoline.spec.yaml +21 -0
- data/spec/fixtures/product_spec_files/gwe.murano.spec.yaml +16 -0
- data/spec/fixtures/product_spec_files/lightbulb-no-state.yaml +11 -0
- data/spec/fixtures/product_spec_files/lightbulb.yaml +14 -0
- data/spec/fixtures/roles-three.yaml +11 -0
- data/spec/fixtures/syncable_content/assets/icon.png +0 -0
- data/spec/fixtures/syncable_content/assets/index.html +0 -0
- data/spec/fixtures/syncable_content/assets/js/script.js +0 -0
- data/spec/fixtures/syncable_content/modules/table_util.lua +58 -0
- data/spec/fixtures/syncable_content/routes/manyRoutes.lua +11 -0
- data/spec/fixtures/syncable_content/routes/singleRoute.lua +5 -0
- data/spec/fixtures/syncable_content/services/devdata.lua +18 -0
- data/spec/fixtures/syncable_content/services/timers.lua +4 -0
- data/spec/spec_helper.rb +119 -0
- 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
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 :
|