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