MrMurano 1.2.1 → 1.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dbf6540edd42b5a6cac68bb92b3f18f69cf0e90e
4
- data.tar.gz: 311ff88459a51b3af06604d89d5c9b58f32b849f
3
+ metadata.gz: 64252dab4d9f4551bfffef5723875d8aab4c2964
4
+ data.tar.gz: a24ed29a6a1726b9b54d75e9b34cdd6e5ef596f1
5
5
  SHA512:
6
- metadata.gz: d01eaf47965c58e51cd502e5a6268d799a5cc96d4eca6bc4930a4dbe555519114ecae0c8483c1876bfbf3bc29cde1ead1cb5a91ccf307d5580c86f0fec7df5ba
7
- data.tar.gz: 8b2b715ba8955ad9ea54c02ad9a5acbc8781f7f70129929f7a295d6b17a5bd53893934f190ef79d1803f633e679a2ccfafbd3d201bde83174ff183ec7af60dcf
6
+ metadata.gz: 85dfd850d6f21f917350de746cb94e57674346fa3d06ac21ef96243491fd7e59cec4e789809a2b8834c0b4549cd71a1802a8d0d143f12fa9b366fad9944fcd20
7
+ data.tar.gz: 5021da7e66050a1bed213c504bf7405632e5b2a3f5238b1810fb43104c66b7f658d81c42eafcfd3a52fd459dd9bc7a40bd77f9486a72c37469b7d3e67429f56a
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0
4
+ - 2.2
5
+
data/Gemfile CHANGED
@@ -10,3 +10,7 @@ gem 'inifile', '~> 3.0'
10
10
  gem 'http-form_data', '~> 1.0.1'
11
11
  gem 'rainbow', '~> 2.1.0'
12
12
 
13
+ group :test do
14
+ gem 'rake'
15
+ end
16
+
data/MrMurano.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
- require 'mrmurano/version'
3
+ require_relative 'lib/MrMurano/version.rb'
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = 'MrMurano'
@@ -32,7 +32,7 @@ Gem::Specification.new do |s|
32
32
 
33
33
  s.add_development_dependency('bundler', '~> 1.7.6')
34
34
  s.add_development_dependency('rspec', '~> 3.2')
35
- s.add_development_dependency('rake')
35
+ s.add_development_dependency('rake', '~> 10.1.1')
36
36
  end
37
37
 
38
38
 
data/README.markdown CHANGED
@@ -1,6 +1,7 @@
1
1
  # MrMurano
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/MrMurano.svg)](https://badge.fury.io/rb/MrMurano)
4
+ [![Build Status](https://travis-ci.org/tadpol/MrMurano.svg?branch=master)](https://travis-ci.org/tadpol/MrMurano)
4
5
 
5
6
  Do more from the command line with [Murano](https://exosite.com/platform/)
6
7
 
@@ -11,15 +12,13 @@ To start from an existing project in Murano
11
12
  mkdir myproject
12
13
  cd myproject
13
14
  mr config solution.id XXXXXX
14
- mr syncdown
15
+ mr syncdown -V
15
16
  ```
16
17
 
17
18
  Do stuff, see what changed: `mr status` or `mr diff`.
18
19
  Then deploy with `mr syncup`
19
20
 
20
21
 
21
-
22
-
23
22
  ## Install
24
23
 
25
24
  ```
@@ -32,6 +31,29 @@ Or
32
31
 
33
32
  ## Features
34
33
 
34
+ ### Logs
35
+
36
+ You can monitor the log messages from your solution with the `mr logs --follow`.
37
+ Or quickly get the last few with `mr logs`
38
+
39
+ MrMurano does a few things to make your log output easier to follow.
40
+ - Adds color to easily see where each log message starts.
41
+ - Reformats the timestamps to be in local time.
42
+ - Finds JSON blobs and pretty prints them.
43
+
44
+ All of these can be toggled with command line options.
45
+
46
+ ### Keystore
47
+
48
+ To aid with debugging, MrMurano has direct access to a solution's Keystore service.
49
+
50
+ To see all of the keys in the current solution: `mr keystore`
51
+
52
+ ### Timeseries
53
+
54
+ To aid with debugging, MrMurano has direct access to a solution's Timeseries service.
55
+
56
+
35
57
  ### Sub-directories
36
58
 
37
59
  For the endpoints, modules, and eventhandlers directories. The can contain both
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
- #task :default => []
3
+ task :default => [:test]
4
4
 
5
5
  # TODO: figure out better way to test.
6
6
  desc "Install gem in user dir"
@@ -21,5 +21,9 @@ task :run do
21
21
  sh %{ruby -Ilib bin/mr }
22
22
  end
23
23
 
24
+
25
+ task :test do
26
+ end
27
+
24
28
  # vim: set sw=4 ts=4 :
25
29
 
data/TODO.taskpaper CHANGED
@@ -1,3 +1,5 @@
1
+ Readme:
2
+ - Add more walk-thrus of common actions. (create new solution, …)
1
3
 
2
4
  Commands:
3
5
  - Status will show things have changes when they don’t.
@@ -11,28 +13,38 @@ Account:
11
13
  Endpoints:
12
14
  - Add support for multiple endpoints in one file (maybe)
13
15
  - Add directory support like in modules @done(2016-07-26)
14
-
16
+
15
17
  Files:
18
+ - Add ignore patterns to config
16
19
  - Switch to mime-types v3
17
20
  - Fix upload. @done(2016-08-01)
18
21
  - Files won't update, they always delete then add. @done(2016-07-28)
19
22
 
20
- Users:
23
+ Users and Roles:
21
24
  Much of this is stuck until we get more docs on the User/Role management
22
25
  - Figure out how to upload (create and update) user info.
23
26
  - Figure out how to add Roles to Users in the local data and upload it.
24
27
  - Fix diff for Users and Roles.
25
28
  - Have hash keys in the yaml be strings not symbols. (don't start with colon) @done(2016-07-27)
26
29
 
30
+ CORS:
31
+ - Get working with sync up/down.
32
+ - GET&PUT /cors data @done(2016-09-08)
33
+
27
34
  Product:
28
35
  - Need to add way to set the product ID on a device eventhandler. @done(2016-08-01)
29
36
 
30
37
  Config:
31
38
  - Think about adding dev,staging,prod system; how would that work?
32
39
  Would it work ok to just use the --configfile option?
40
+ I'm thinking so. To the point of dropping the :private scope.
41
+ - Add ENV support for some (or all?) options.
42
+ At least the --configfile option. (and --config option)
43
+ - Maybe add dotenv support.
33
44
 
34
45
  SolutionBase:
35
46
  - All network traffic is serialized. Make some parallel.
47
+ - JSON parse should use symbols for keys. @done(2016-09-01)
36
48
  - Add the --curl verbose option. @done(2016-08-12)
37
49
  - Rebuild how local names and paths are computed from remote items. @done(2016-07-27)
38
50
 
@@ -41,7 +53,7 @@ Bundles:
41
53
  - Work on design @done(2016-08-09)
42
54
  Thinking of something like VIM bundles. A directory of directories. Each with a
43
55
  manafest file? (maybe) A Bundle is a group of modules, endpoints, static files
44
- and the other things.
56
+ and the other things.
45
57
 
46
58
  There needs to be some layering logic added, where the bundles are stacked and
47
59
  then the top-level files are stack on top of that. This builds the final map of
data/bin/mr CHANGED
@@ -40,7 +40,7 @@ $cfg.load
40
40
  # Basic command support is:
41
41
  # - read/write config file in [Project, User, System] (all are optional)
42
42
  # - Introspection for tab completion.
43
- # - Look for tools in PATH that are +x and "mr-foo..."
43
+ # - Look for tools in PATH that are +x and "mr-foo..."
44
44
 
45
45
 
46
46
  # Look for plug-ins
data/lib/MrMurano.rb CHANGED
@@ -8,7 +8,11 @@ require 'MrMurano/Solution-File.rb'
8
8
  require 'MrMurano/Solution-Services.rb'
9
9
  require 'MrMurano/Solution-Users.rb'
10
10
  require 'MrMurano/Solution-ServiceConfig.rb'
11
+
12
+ require 'MrMurano/cors'
13
+ require 'MrMurano/keystore.rb'
11
14
  require 'MrMurano/logs.rb'
12
15
  require 'MrMurano/sync.rb'
13
16
  require 'MrMurano/status.rb'
17
+ require 'MrMurano/timeseries.rb'
14
18
  #require 'MrMurano/shelledCommand'
@@ -51,6 +51,13 @@ module MrMurano
51
51
  end
52
52
 
53
53
  class Account
54
+ def initialize
55
+ @json_opts = {
56
+ :allow_nan => true,
57
+ :symbolize_names => true,
58
+ :create_additions => false
59
+ }
60
+ end
54
61
 
55
62
 
56
63
  def endPoint(path)
@@ -91,8 +98,8 @@ module MrMurano
91
98
  response = http.request(request)
92
99
  case response
93
100
  when Net::HTTPSuccess
94
- token = JSON.parse(response.body)
95
- @token = token['token']
101
+ token = JSON.parse(response.body, @json_opts)
102
+ @token = token[:token]
96
103
  else
97
104
  say_error "No token! because: #{response}"
98
105
  @token = nil
@@ -113,7 +120,7 @@ module MrMurano
113
120
  response = http.request(request)
114
121
  case response
115
122
  when Net::HTTPSuccess
116
- busy = JSON.parse(response.body)
123
+ busy = JSON.parse(response.body, @json_opts)
117
124
  return busy
118
125
  else
119
126
  raise response
@@ -132,7 +139,7 @@ module MrMurano
132
139
  response = http.request(request)
133
140
  case response
134
141
  when Net::HTTPSuccess
135
- busy = JSON.parse(response.body)
142
+ busy = JSON.parse(response.body, @json_opts)
136
143
  return busy
137
144
  else
138
145
  raise response
@@ -151,7 +158,7 @@ module MrMurano
151
158
  response = http.request(request)
152
159
  case response
153
160
  when Net::HTTPSuccess
154
- busy = JSON.parse(response.body)
161
+ busy = JSON.parse(response.body, @json_opts)
155
162
  return busy
156
163
  else
157
164
  raise response
@@ -180,9 +187,9 @@ command :account do |c|
180
187
  if options.businesses then
181
188
  data = acc.businesses
182
189
  if options.idonly then
183
- say data.map{|row| row['bizid']}.join(' ')
190
+ say data.map{|row| row[:bizid]}.join(' ')
184
191
  else
185
- busy = data.map{|row| [row['bizid'], row['role'], row['name']]}
192
+ busy = data.map{|row| [row[:bizid], row[:role], row[:name]]}
186
193
  table = Terminal::Table.new :rows => busy, :headings => ['Biz ID', 'Role', 'Name']
187
194
  say table
188
195
  end
@@ -190,9 +197,9 @@ command :account do |c|
190
197
  elsif options.products then
191
198
  data = acc.products
192
199
  if options.idonly then
193
- say data.map{|row| row['pid']}.join(' ')
200
+ say data.map{|row| row[:pid]}.join(' ')
194
201
  else
195
- busy = data.map{|r| [r['label'], r['type'], r['pid'], r['modelId']]}
202
+ busy = data.map{|r| [r[:label], r[:type], r[:pid], r[:modelId]]}
196
203
  table = Terminal::Table.new :rows => busy, :headings => ['Label', 'Type', 'PID', 'ModelID']
197
204
  say table
198
205
  end
@@ -200,9 +207,9 @@ command :account do |c|
200
207
  elsif options.solutions then
201
208
  data = acc.solutions
202
209
  if options.idonly then
203
- say data.map{|row| row['apiId']}.join(' ')
210
+ say data.map{|row| row[:apiId]}.join(' ')
204
211
  else
205
- busy = data.map{|r| [r['apiId'], r['domain'], r['type'], r['sid']]}
212
+ busy = data.map{|r| [r[:apiId], r[:domain], r[:type], r[:sid]]}
206
213
  table = Terminal::Table.new :rows => busy, :headings => ['API ID', 'Domain', 'Type', 'SID']
207
214
  say table
208
215
  end
@@ -20,16 +20,16 @@ module MrMurano
20
20
 
21
21
  def fetch(id)
22
22
  ret = get('/' + id.to_s)
23
- aheader = ret['script'].lines.first.chomp
24
- dheader = /^--#ENDPOINT (?i:#{ret['method']}) #{ret['path']}$/
25
- rheader = %{--#ENDPOINT #{ret['method']} #{ret['path']}\n}
23
+ aheader = ret[:script].lines.first.chomp
24
+ dheader = /^--#ENDPOINT (?i:#{ret[:method]}) #{ret[:path]}$/
25
+ rheader = %{--#ENDPOINT #{ret[:method]} #{ret[:path]}\n}
26
26
  if block_given? then
27
27
  yield rheader unless dheader =~ aheader
28
- yield ret['script']
28
+ yield ret[:script]
29
29
  else
30
30
  res = ''
31
31
  res << rheader unless dheader =~ aheader
32
- res << ret['script']
32
+ res << ret[:script]
33
33
  res
34
34
  end
35
35
  end
@@ -9,30 +9,40 @@ module MrMurano
9
9
  end
10
10
 
11
11
  def list
12
- get()['items']
12
+ get()[:items]
13
13
  end
14
14
  def fetch(id)
15
15
  get('/' + id.to_s)
16
16
  end
17
17
 
18
+ def scid_for_name(name)
19
+ name = name.to_s unless name.kind_of? String
20
+ scr = list().select{|i| i[:service] == name}.first
21
+ scid = scr[:id]
22
+ end
23
+
24
+ def scid
25
+ return @scid unless @scid.nil?
26
+ @scid = scid_for_name(@serviceName)
27
+ end
28
+
29
+ # Below is Device ServiceConfig Specific. Should it be in its own class?
18
30
 
19
31
  def assignTriggers(products)
20
- scr = list().select{|i| i['service'] == 'device' or i[:service] == 'device'}.first
21
- scid = scr['id'] or scr[:id]
32
+ scid = scid_for_name('device')
22
33
 
23
- details = Hash.transform_keys_to_symbols(fetch(scid))
34
+ details = fetch(scid)
24
35
  products = [products] unless products.kind_of? Array
25
36
  details[:triggers] = {:pid=>products}
26
37
 
27
38
  put('/'+scid, details)
28
-
39
+
29
40
  end
30
41
 
31
42
  def showTriggers
32
- scr = list().select{|i| i['service'] == 'device' or i[:service] == 'device'}.first
33
- scid = scr['id'] or scr[:id]
43
+ scid = scid_for_name('device')
34
44
 
35
- details = Hash.transform_keys_to_symbols(fetch(scid))
45
+ details = fetch(scid)
36
46
 
37
47
  return [] if details[:triggers].nil?
38
48
  details[:triggers][:pid]
@@ -57,7 +67,7 @@ command :assign do |c|
57
67
  say trigs.join(' ')
58
68
  else
59
69
  acc = MrMurano::Account.new
60
- products = acc.products.map{|p| Hash.transform_keys_to_symbols(p)}
70
+ products = acc.products
61
71
  products.select!{|p| trigs.include? p[:pid] }
62
72
  busy = products.map{|r| [r[:label], r[:type], r[:pid], r[:modelId]]}
63
73
  table = Terminal::Table.new :rows => busy, :headings => ['Label', 'Type', 'PID', 'ModelID']
@@ -70,7 +80,7 @@ command :assign do |c|
70
80
  prid = $cfg['product.id']
71
81
  else
72
82
  acc = MrMurano::Account.new
73
- products = acc.products.map{|p| Hash.transform_keys_to_symbols(p)}
83
+ products = acc.products
74
84
  products.select!{|p| p[:label] == prname or p[:pid] == prname }
75
85
  prid = products.map{|p| p[:pid]}
76
86
  end
@@ -27,15 +27,15 @@ module MrMurano
27
27
 
28
28
  def list
29
29
  ret = get()
30
- ret['items']
30
+ ret[:items]
31
31
  end
32
32
 
33
33
  def fetch(name)
34
34
  ret = get('/'+name)
35
35
  if block_given? then
36
- yield ret['script']
36
+ yield ret[:script]
37
37
  else
38
- ret['script']
38
+ ret[:script]
39
39
  end
40
40
  end
41
41
 
@@ -127,20 +127,20 @@ module MrMurano
127
127
  def list
128
128
  ret = get()
129
129
  skiplist = ($cfg['eventhandler.skiplist'] or '').split
130
- ret['items'].reject{|i| i.has_key?('service') and skiplist.include? i['service'] }
130
+ ret[:items].reject{|i| i.has_key?(:service) and skiplist.include? i[:service] }
131
131
  end
132
132
 
133
133
  def fetch(name)
134
134
  ret = get('/'+name)
135
- aheader = (ret['script'].lines.first or "").chomp
136
- dheader = "--#EVENT #{ret['service']} #{ret['event']}"
135
+ aheader = (ret[:script].lines.first or "").chomp
136
+ dheader = "--#EVENT #{ret[:service]} #{ret[:event]}"
137
137
  if block_given? then
138
138
  yield dheader + "\n" if aheader != dheader
139
- yield ret['script']
139
+ yield ret[:script]
140
140
  else
141
141
  res = ''
142
142
  res << dheader + "\n" if aheader != dheader
143
- res << ret['script']
143
+ res << ret[:script]
144
144
  res
145
145
  end
146
146
  end
@@ -10,12 +10,18 @@ module MrMurano
10
10
  # This might also be a valid ProductBase.
11
11
  def initialize
12
12
  @token = Account.new.token
13
+ raise "Not logged in!" if @token.nil?
13
14
  @sid = $cfg['solution.id']
14
15
  raise "No solution!" if @sid.nil?
15
16
  @uriparts = [:solution, @sid]
16
17
  @itemkey = :id
17
18
  @locationbase = $cfg['location.base']
18
19
  @location = nil
20
+ @json_opts = {
21
+ :allow_nan => true,
22
+ :symbolize_names => true,
23
+ :create_additions => false
24
+ }
19
25
  end
20
26
 
21
27
  def verbose(msg)
@@ -70,7 +76,7 @@ module MrMurano
70
76
  when Net::HTTPSuccess
71
77
  return {} if response.body.nil?
72
78
  begin
73
- return JSON.parse(response.body)
79
+ return JSON.parse(response.body, @json_opts)
74
80
  rescue
75
81
  return response.body
76
82
  end
@@ -276,7 +282,7 @@ module MrMurano
276
282
  def syncdown(options=Commander::Command::Options.new)
277
283
  options.asdown = true
278
284
  dt = status(options)
279
- into = @locationbase + @location
285
+ into = @locationbase + @location ###
280
286
  toadd = dt[:toadd]
281
287
  todel = dt[:todel]
282
288
  tomod = dt[:tomod]
@@ -396,21 +402,6 @@ module MrMurano
396
402
 
397
403
  end
398
404
 
399
- # …/serviceconfig
400
- class ServiceConfig < SolutionBase
401
- def initialize
402
- super
403
- @uriparts << 'serviceconfig'
404
- end
405
-
406
- def list
407
- get()['items']
408
- end
409
- def fetch(id)
410
- get('/' + id.to_s)
411
- end
412
- end
413
-
414
405
  end
415
406
 
416
407
  # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,57 @@
1
+
2
+ module MrMurano
3
+ class Cors < SolutionBase
4
+ def initialize
5
+ super
6
+ @uriparts << 'cors'
7
+ @location = $cfg['location.cors']
8
+ end
9
+
10
+ def fetch()
11
+ ret = get()
12
+ ret[:cors]
13
+ end
14
+
15
+ # TODO: fill out other metheds so this could be part of sync up/down.
16
+
17
+ ##
18
+ # Upload CORS
19
+ # :local path to file to push
20
+ # :remote hash of method and endpoint path (ignored for now)
21
+ def upload(local, remote)
22
+ local = Pathname.new(local) unless local.kind_of? Pathname
23
+ raise "no file" unless local.exist?
24
+
25
+ local.open do |io|
26
+ data = YAML.load(io)
27
+ put('', data)
28
+ end
29
+ end
30
+
31
+ def tolocalpath(into, item)
32
+ into
33
+ end
34
+ end
35
+ end
36
+
37
+ command :cors do |c|
38
+ c.syntax = %{mr cors [options]}
39
+ c.description = %{Get or set the CORS for the solution.}
40
+ c.option '-f','--file FILE', String, %{File to set CORS from}
41
+
42
+ c.action do |args,options|
43
+ sol = MrMurano::Cors.new
44
+
45
+ if options.file then
46
+ #set
47
+ pp sol.upload(options.file, {})
48
+ else
49
+ # get
50
+ ret = sol.fetch()
51
+ puts ret
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,105 @@
1
+
2
+ module MrMurano
3
+ class Keystore < ServiceConfig
4
+ def initialize
5
+ super
6
+ @serviceName = 'keystore'
7
+ end
8
+
9
+ def keyinfo
10
+ ret = get("/#{scid}/call/info")
11
+ end
12
+
13
+ def listkeys
14
+ ret = get("/#{scid}/call/list")
15
+ ret[:keys]
16
+ end
17
+
18
+ def getkey(key)
19
+ ret = post("/#{scid}/call/get", {:key=>key})
20
+ ret[:value]
21
+ end
22
+
23
+ def setkey(key, value)
24
+ post("/#{scid}/call/set", { :key=>key, :value=>value })
25
+ end
26
+
27
+ def delkey(key)
28
+ post("/#{scid}/call/delete", { :key=>key})
29
+ end
30
+
31
+ def command(key, cmd, args)
32
+ post("/#{scid}/call/command", {:key=>key, :command=>cmd, :args=>args})
33
+ end
34
+
35
+ end
36
+ end
37
+
38
+ command 'keystore info' do |c|
39
+ c.syntax = %{mr keystore info}
40
+ c.description = %{Show info about the Keystore}
41
+ c.action do |args,options|
42
+ sol = MrMurano::Keystore.new
43
+ pp sol.keyinfo
44
+ end
45
+ end
46
+
47
+ command 'keystore list' do |c|
48
+ c.syntax = %{mr keystore list}
49
+ c.description = %{List all of the keys in the Keystore}
50
+ c.action do |args,options|
51
+ sol = MrMurano::Keystore.new
52
+ sol.listkeys.each do |key|
53
+ puts key
54
+ end
55
+ end
56
+ end
57
+ alias_command :keystore, 'keystore list'
58
+
59
+ command 'keystore get' do |c|
60
+ c.syntax = %{mr keystore get <key>}
61
+ c.description = %{Get the value of a key in the Keystore}
62
+ c.action do |args,options|
63
+ sol = MrMurano::Keystore.new
64
+ ret = sol.getkey(args[0])
65
+ puts ret
66
+ end
67
+ end
68
+
69
+ command 'keystore set' do |c|
70
+ c.syntax = %{mr keystore set <key> <value...>}
71
+ c.description = %{Set teh value of a key in the Keystore}
72
+ c.action do |args,options|
73
+ sol = MrMurano::Keystore.new
74
+ sol.setkey(args[0], args[1..-1].join(' '))
75
+ end
76
+ end
77
+
78
+ command 'keystore delete' do |c|
79
+ c.syntax = %{mr keystore delete <key>}
80
+ c.description = %{Delete a key from the Keystore}
81
+ c.action do |args,options|
82
+ sol = MrMurano::Keystore.new
83
+ sol.delkey(args[0])
84
+ end
85
+ end
86
+ alias_command 'keystore rm', 'keystore delete'
87
+
88
+ command 'keystore command' do |c|
89
+ c.syntax = %{mr keystore command <key> <command> <args...>}
90
+ c.description = %{Call some Redis commands in the Keystore.
91
+
92
+ Only a subset of all Redis commands is supported.
93
+ See http://docs.exosite.com/murano/services/keystore/#command for current list.
94
+ }
95
+ c.example %{mr keystore command mykey lpush myvalue}, %{Push a value onto list}
96
+ c.example %{mr keystore command mykey lpush A B C}, %{Push three values onto list}
97
+ c.example %{mr keystore command mykey lrem 0 B}, %{Remove all B values from list}
98
+ c.action do |args,options|
99
+ sol = MrMurano::Keystore.new
100
+ pp sol.command(args[0], args[1], args[2..-1])
101
+ end
102
+ end
103
+ alias_command 'keystore cmd', 'keystore command'
104
+
105
+ # vim: set ai et sw=2 ts=2 :
data/lib/MrMurano/logs.rb CHANGED
@@ -22,8 +22,8 @@ command :logs do |c|
22
22
  begin
23
23
  ret = sol.get('/logs') # TODO: ('/logs?polling=true') Currently ignored.
24
24
 
25
- if ret.kind_of?(Hash) and ret.has_key?('items') then
26
- ret['items'].reverse.each do |line|
25
+ if ret.kind_of?(Hash) and ret.has_key?(:items) then
26
+ ret[:items].reverse.each do |line|
27
27
  curtime = ""
28
28
  if line.kind_of?(String) then
29
29
 
@@ -53,7 +53,6 @@ command :logs do |c|
53
53
  out = line
54
54
 
55
55
  elsif line.kind_of?(Hash) then
56
- line = Hash.transform_keys_to_symbols(line)
57
56
  out=""
58
57
 
59
58
  out << "[#{line[:subject]}]".color(:red).background(:aliceblue)
@@ -0,0 +1,84 @@
1
+
2
+ module MrMurano
3
+ class Timeseries < ServiceConfig
4
+ def initialize
5
+ super
6
+ @serviceName = 'timeseries'
7
+ end
8
+
9
+ def query(query)
10
+ post("/#{scid}/call/query", {:q=>query})
11
+ end
12
+
13
+ def write(writestr)
14
+ post("/#{scid}/call/write", { :q=>writestr })
15
+ end
16
+
17
+ def command(cmd)
18
+ post("/#{scid}/call/command", { :q=>cmd})
19
+ end
20
+
21
+ end
22
+ end
23
+
24
+ command 'timeseries query' do |c|
25
+ c.syntax = %{mr timeseries query <query string>}
26
+ c.description = %{Query the timeseries database}
27
+ c.option '--[no-]json', %{Display results as raw json}
28
+ #c.option '--csv', %{Display results as csv}
29
+ # Should get a CSV formatter to make sure cells are properly escapped.
30
+ c.action do |args,options|
31
+ options.defalts :json=>false
32
+ sol = MrMurano::Timeseries.new
33
+ ret = sol.query args.join(' ')
34
+ if options.json then
35
+ puts ret.to_json
36
+ else
37
+ (ret[:results] or []).each do |res|
38
+ (res[:series] or []).each do |ser|
39
+ cols = ser[:columns]
40
+ table = Terminal::Table.new :title=>ser[:name], :headings=>cols, :rows=>ser[:values]
41
+ puts table
42
+ end
43
+ end
44
+ # If nothing displayed, Format wasn't what we expected, so do what?
45
+ end
46
+ end
47
+ end
48
+ alias_command :tsq, 'timeseries query'
49
+
50
+ command 'timeseries write' do |c|
51
+ c.syntax = %{mr timeseries <write string>}
52
+ c.description = %{Write data into the timeseries database}
53
+ c.option '--[no-]json', %{Display results as raw json}
54
+ c.action do |args,options|
55
+ options.defalts :json=>false
56
+ sol = MrMurano::Timeseries.new
57
+ ret = sol.write args.join(' ')
58
+ if options.json then
59
+ puts ret.to_json
60
+ else
61
+ pp ret
62
+ end
63
+ end
64
+ end
65
+ alias_command :tsw, 'timeseries write'
66
+
67
+ command 'timeseries command' do |c|
68
+ c.syntax = %{mr timeseries command <db command>}
69
+ c.description = %{Execute a non-query command in the database}
70
+ c.option '--[no-]json', %{Display results as raw json}
71
+ c.action do |args,options|
72
+ options.defalts :json=>false
73
+ sol = MrMurano::Timeseries.new
74
+ ret = sol.command args.join(' ')
75
+ if options.json then
76
+ puts ret.to_json
77
+ else
78
+ pp ret
79
+ end
80
+ end
81
+ end
82
+
83
+
84
+ # vim: set ai et sw=2 ts=2 :
@@ -1,4 +1,4 @@
1
1
  module MrMurano
2
- VERSION = '1.2.1'.freeze
2
+ VERSION = '1.3.0'.freeze
3
3
  end
4
4
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: MrMurano
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Conrad Tadpol Tilstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-07 00:00:00.000000000 Z
11
+ date: 2016-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: commander
@@ -140,16 +140,16 @@ dependencies:
140
140
  name: rake
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - '>='
143
+ - - ~>
144
144
  - !ruby/object:Gem::Version
145
- version: '0'
145
+ version: 10.1.1
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - '>='
150
+ - - ~>
151
151
  - !ruby/object:Gem::Version
152
- version: '0'
152
+ version: 10.1.1
153
153
  description: "Do more from the command line with Murano\n\n Push and pull data from
154
154
  Murano.\n Get status on what things have changed.\n See a diff of the changes
155
155
  before you push.\n "
@@ -161,6 +161,7 @@ extensions: []
161
161
  extra_rdoc_files: []
162
162
  files:
163
163
  - .gitignore
164
+ - .travis.yml
164
165
  - Gemfile
165
166
  - MrMurano.gemspec
166
167
  - README.markdown
@@ -176,11 +177,14 @@ files:
176
177
  - lib/MrMurano/Solution-Users.rb
177
178
  - lib/MrMurano/Solution.rb
178
179
  - lib/MrMurano/configFile.rb
180
+ - lib/MrMurano/cors.rb
179
181
  - lib/MrMurano/hash.rb
182
+ - lib/MrMurano/keystore.rb
180
183
  - lib/MrMurano/logs.rb
181
184
  - lib/MrMurano/shelledCommand.rb
182
185
  - lib/MrMurano/status.rb
183
186
  - lib/MrMurano/sync.rb
187
+ - lib/MrMurano/timeseries.rb
184
188
  - lib/MrMurano/version.rb
185
189
  homepage: https://github.com/tadpol/MrMurano
186
190
  licenses: