MuranoCLI 2.2.4 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.agignore +3 -0
- data/.gitignore +18 -1
- data/.rubocop.yml +222 -0
- data/.trustme.sh +185 -0
- data/.trustme.vim +24 -0
- data/Gemfile +23 -4
- data/LICENSE.txt +1 -1
- data/MuranoCLI.gemspec +43 -8
- data/README.markdown +9 -11
- data/Rakefile +187 -143
- data/TODO.taskpaper +2 -2
- data/bin/murano +51 -52
- data/docs/basic_example.rst +436 -0
- data/docs/completions/murano_completion-bash +3484 -0
- data/docs/demo.md +32 -32
- data/docs/develop.rst +391 -0
- data/lib/MrMurano.rb +21 -7
- data/lib/MrMurano/Account.rb +159 -174
- data/lib/MrMurano/Business.rb +381 -0
- data/lib/MrMurano/Config-Migrate.rb +32 -26
- data/lib/MrMurano/Config.rb +407 -128
- data/lib/MrMurano/Content.rb +191 -0
- data/lib/MrMurano/Gateway.rb +489 -0
- data/lib/MrMurano/Keystore.rb +48 -0
- data/lib/MrMurano/Passwords.rb +103 -0
- data/lib/MrMurano/ProjectFile.rb +121 -79
- data/lib/MrMurano/ReCommander.rb +114 -10
- data/lib/MrMurano/Setting.rb +90 -0
- data/lib/MrMurano/Solution-ServiceConfig.rb +89 -45
- data/lib/MrMurano/Solution-Services.rb +461 -166
- data/lib/MrMurano/Solution-Users.rb +70 -31
- data/lib/MrMurano/Solution.rb +372 -13
- data/lib/MrMurano/SolutionId.rb +73 -0
- data/lib/MrMurano/SyncRoot.rb +137 -0
- data/lib/MrMurano/SyncUpDown.rb +594 -284
- data/lib/MrMurano/Webservice-Cors.rb +71 -0
- data/lib/MrMurano/Webservice-Endpoint.rb +234 -0
- data/lib/MrMurano/Webservice-File.rb +193 -0
- data/lib/MrMurano/Webservice.rb +51 -0
- data/lib/MrMurano/commands.rb +18 -15
- data/lib/MrMurano/commands/business.rb +300 -6
- data/lib/MrMurano/commands/completion-bash.erb +166 -0
- data/lib/MrMurano/commands/{zshcomplete.erb → completion-zsh.erb} +0 -0
- data/lib/MrMurano/commands/completion.rb +76 -39
- data/lib/MrMurano/commands/config.rb +108 -44
- data/lib/MrMurano/commands/content.rb +115 -72
- data/lib/MrMurano/commands/cors.rb +29 -14
- data/lib/MrMurano/commands/devices.rb +286 -0
- data/lib/MrMurano/commands/domain.rb +52 -12
- data/lib/MrMurano/commands/gb.rb +24 -9
- data/lib/MrMurano/commands/globals.rb +64 -0
- data/lib/MrMurano/commands/init.rb +377 -155
- data/lib/MrMurano/commands/keystore.rb +92 -82
- data/lib/MrMurano/commands/link.rb +300 -0
- data/lib/MrMurano/commands/login.rb +74 -11
- data/lib/MrMurano/commands/logs.rb +63 -32
- data/lib/MrMurano/commands/mock.rb +57 -29
- data/lib/MrMurano/commands/password.rb +57 -39
- data/lib/MrMurano/commands/postgresql.rb +127 -94
- data/lib/MrMurano/commands/settings.rb +203 -0
- data/lib/MrMurano/commands/show.rb +79 -38
- data/lib/MrMurano/commands/solution.rb +423 -5
- data/lib/MrMurano/commands/solution_picker.rb +547 -0
- data/lib/MrMurano/commands/status.rb +195 -61
- data/lib/MrMurano/commands/sync.rb +78 -39
- data/lib/MrMurano/commands/timeseries.rb +71 -55
- data/lib/MrMurano/commands/tsdb.rb +113 -87
- data/lib/MrMurano/commands/usage.rb +57 -15
- data/lib/MrMurano/hash.rb +100 -10
- data/lib/MrMurano/http.rb +187 -43
- data/lib/MrMurano/makePretty.rb +16 -14
- data/lib/MrMurano/optparse.rb +2178 -0
- data/lib/MrMurano/progress.rb +138 -0
- data/lib/MrMurano/schema/resource-v1.0.0.yaml +32 -0
- data/lib/MrMurano/template/projectFile.murano.erb +16 -13
- data/lib/MrMurano/verbosing.rb +166 -29
- data/lib/MrMurano/version.rb +30 -1
- data/spec/Account-Passwords_spec.rb +21 -4
- data/spec/Account_spec.rb +69 -146
- data/spec/Business_spec.rb +290 -0
- data/spec/ConfigFile_spec.rb +1 -0
- data/spec/ConfigMigrate_spec.rb +12 -8
- data/spec/Config_spec.rb +40 -34
- data/spec/Content_spec.rb +363 -0
- data/spec/GatewayBase_spec.rb +54 -0
- data/spec/GatewayDevice_spec.rb +321 -0
- data/spec/GatewayResource_spec.rb +266 -0
- data/spec/GatewaySettings_spec.rb +120 -0
- data/spec/Http_spec.rb +18 -8
- data/spec/Mock_spec.rb +2 -2
- data/spec/ProjectFile_spec.rb +25 -14
- data/spec/Setting_spec.rb +110 -0
- data/spec/Solution-ServiceConfig_spec.rb +44 -5
- data/spec/Solution-ServiceEventHandler_spec.rb +23 -14
- data/spec/Solution-ServiceModules_spec.rb +47 -37
- data/spec/Solution-UsersRoles_spec.rb +10 -8
- data/spec/Solution_spec.rb +17 -8
- data/spec/SyncRoot_spec.rb +46 -20
- data/spec/SyncUpDown_spec.rb +437 -201
- data/spec/Verbosing_spec.rb +12 -4
- data/spec/{Solution-Cors_spec.rb → Webservice-Cors_spec.rb} +23 -20
- data/spec/{Solution-Endpoint_spec.rb → Webservice-Endpoint_spec.rb} +43 -41
- data/spec/{Solution-File_spec.rb → Webservice-File_spec.rb} +44 -33
- data/spec/Webservice-Setting_spec.rb +89 -0
- data/spec/_workspace.rb +4 -4
- data/spec/cmd_business_spec.rb +9 -4
- data/spec/cmd_common.rb +44 -1
- data/spec/cmd_content_spec.rb +43 -17
- data/spec/cmd_cors_spec.rb +4 -4
- data/spec/cmd_device_spec.rb +61 -16
- data/spec/cmd_domain_spec.rb +29 -6
- data/spec/cmd_init_spec.rb +281 -126
- data/spec/cmd_keystore_spec.rb +3 -3
- data/spec/cmd_link_spec.rb +98 -0
- data/spec/cmd_password_spec.rb +1 -1
- data/spec/cmd_setting_application_spec.rb +260 -0
- data/spec/cmd_setting_product_spec.rb +220 -0
- data/spec/cmd_status_spec.rb +223 -114
- data/spec/cmd_syncdown_spec.rb +115 -35
- data/spec/cmd_syncup_spec.rb +68 -15
- data/spec/cmd_usage_spec.rb +35 -8
- data/spec/fixtures/dumped_config +6 -4
- data/spec/fixtures/gateway_resource_files/resources.notyaml +12 -0
- data/spec/fixtures/gateway_resource_files/resources.yaml +13 -0
- data/spec/fixtures/gateway_resource_files/resources_invalid.yaml +13 -0
- data/spec/fixtures/mrmuranorc_deleted_bob +0 -2
- data/spec/fixtures/product_spec_files/lightbulb.yaml +20 -13
- data/spec/fixtures/{syncable_content → syncable_conflict}/services/devdata.lua +1 -1
- data/spec/fixtures/{syncable_content → syncable_conflict}/services/timers.lua +0 -0
- data/spec/spec_helper.rb +5 -0
- metadata +262 -171
- data/bin/mr +0 -8
- data/lib/MrMurano/Product-1P-Device.rb +0 -145
- data/lib/MrMurano/Product-Resources.rb +0 -205
- data/lib/MrMurano/Product.rb +0 -358
- data/lib/MrMurano/Solution-Cors.rb +0 -47
- data/lib/MrMurano/Solution-Endpoint.rb +0 -191
- data/lib/MrMurano/Solution-File.rb +0 -166
- data/lib/MrMurano/commands/assign.rb +0 -57
- data/lib/MrMurano/commands/businessList.rb +0 -45
- data/lib/MrMurano/commands/product.rb +0 -14
- data/lib/MrMurano/commands/productCreate.rb +0 -39
- data/lib/MrMurano/commands/productDelete.rb +0 -33
- data/lib/MrMurano/commands/productDevice.rb +0 -87
- data/lib/MrMurano/commands/productDeviceIdCmds.rb +0 -89
- data/lib/MrMurano/commands/productList.rb +0 -45
- data/lib/MrMurano/commands/productWrite.rb +0 -27
- data/lib/MrMurano/commands/solutionCreate.rb +0 -41
- data/lib/MrMurano/commands/solutionDelete.rb +0 -34
- data/lib/MrMurano/commands/solutionList.rb +0 -45
- data/spec/ProductBase_spec.rb +0 -113
- data/spec/ProductContent_spec.rb +0 -162
- data/spec/ProductResources_spec.rb +0 -329
- data/spec/Product_1P_Device_spec.rb +0 -202
- data/spec/Product_1P_RPC_spec.rb +0 -175
- data/spec/Product_spec.rb +0 -153
- data/spec/Solution-ServiceDevice_spec.rb +0 -176
- data/spec/cmd_assign_spec.rb +0 -51
@@ -1,20 +1,30 @@
|
|
1
|
+
# Last Modified: 2017.08.16 /coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright © 2016-2017 Exosite LLC.
|
5
|
+
# License: MIT. See LICENSE.txt.
|
6
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
7
|
+
|
8
|
+
require 'MrMurano/ReCommander'
|
1
9
|
require 'MrMurano/Solution-ServiceConfig'
|
2
10
|
|
3
11
|
module MrMurano
|
4
12
|
class Postgresql < ServiceConfig
|
5
|
-
def initialize
|
13
|
+
def initialize(sid=nil)
|
14
|
+
# FIXME/2017-07-03: What soln types have PSQLs?
|
15
|
+
@solntype = 'application.id'
|
6
16
|
super
|
7
|
-
@
|
17
|
+
@service_name = 'postgresql'
|
8
18
|
end
|
9
19
|
|
10
20
|
def query(query, params=nil)
|
11
|
-
aqr = {:
|
21
|
+
aqr = { sql: query }
|
12
22
|
aqr[:parameters] = params unless params.nil?
|
13
23
|
call(:query, :post, aqr)
|
14
24
|
end
|
15
25
|
|
16
26
|
def queries(query, params=nil)
|
17
|
-
aqr = {:
|
27
|
+
aqr = { sql: query }
|
18
28
|
aqr[:parameters] = params unless params.nil?
|
19
29
|
call(:queries, :post, aqr)
|
20
30
|
end
|
@@ -22,163 +32,186 @@ module MrMurano
|
|
22
32
|
end
|
23
33
|
|
24
34
|
command :postgresql do |c|
|
25
|
-
c.syntax = %
|
26
|
-
c.summary = %
|
27
|
-
c.description = %
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
c.option '
|
34
|
-
c.option '-
|
35
|
+
c.syntax = %(murano postgresql <SQL Commands>)
|
36
|
+
c.summary = %(Query the relational database)
|
37
|
+
c.description = %(
|
38
|
+
Query the relational database.
|
39
|
+
|
40
|
+
Queries can include $# escapes that are filled from the --param option.
|
41
|
+
).strip
|
42
|
+
|
43
|
+
c.option '--param LIST', Array, %(Values to fill $# with)
|
44
|
+
c.option '-f', '--file FILE', %(File of SQL commands)
|
45
|
+
c.option '-o', '--output FILE', %(Download to file instead of STDOUT)
|
46
|
+
|
47
|
+
c.example %(murano postgresql 'select * from bob'), %(Run a SQL command)
|
48
|
+
c.example(
|
49
|
+
%(murano postgresql 'select * from prices' -c outformat=csv -o prices.csv),
|
50
|
+
%(Download all values in prices to a CSV file.)
|
51
|
+
)
|
52
|
+
c.example(
|
53
|
+
%(murano postgresql 'INSERT INTO prices (price, item) VALUES ($1,$2)' --param 1.24,Food),
|
54
|
+
%(Insert using parameters.)
|
55
|
+
)
|
56
|
+
c.example %(murano postgresql -f cmds.sql), %(Run multiple commands from a file)
|
57
|
+
|
58
|
+
c.action do |args, options|
|
59
|
+
# SKIP: c.verify_arg_count!(args)
|
35
60
|
|
36
|
-
c.example %{murano postgresql 'select * from bob'}, %{Run a SQL command}
|
37
|
-
c.example %{murano postgresql 'select * from prices' -c outformat=csv -o prices.csv}, %{Download all values in prices to a CSV file.}
|
38
|
-
c.example %{murano postgresql 'INSERT INTO prices (price, item) VALUES ($1,$2)' --param 1.24,Food}, %{Insert using parameters.}
|
39
|
-
c.example %{murano postgresql -f cmds.sql}, %{Run multiple commands from a file}
|
40
|
-
|
41
|
-
c.action do |args,options|
|
42
61
|
pg = MrMurano::Postgresql.new
|
43
|
-
if options.file
|
62
|
+
if options.file
|
44
63
|
sqls = File.read(options.file)
|
45
|
-
|
46
64
|
ret = pg.queries(sqls, options.param)
|
47
65
|
else
|
48
66
|
ret = pg.query(args.join(' '), options.param)
|
49
67
|
end
|
50
68
|
|
51
|
-
|
69
|
+
exit 1 if ret.nil?
|
70
|
+
unless ret[:error].nil?
|
52
71
|
pg.error "Returned error: #{ret[:error]}"
|
53
72
|
exit 1
|
54
73
|
end
|
55
74
|
|
56
|
-
io=nil
|
57
|
-
if options.output
|
58
|
-
io = File.open(options.output, 'w')
|
59
|
-
end
|
75
|
+
io = nil
|
76
|
+
io = File.open(options.output, 'w') if options.output
|
60
77
|
|
61
78
|
pg.outf(ret, io) do |dd, ios|
|
62
79
|
dd = dd[:result]
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
80
|
+
# Look for date cells and pretty them. (a Hash with specific fields)
|
81
|
+
# All others, call to_s
|
82
|
+
rows = dd[:rows].map do |row|
|
83
|
+
row.map do |cell|
|
84
|
+
if cell.is_a?(Hash) && cell.keys.sort == %i[day hour min month sec usec year]
|
85
|
+
t = Time.gm(
|
86
|
+
cell[:year], cell[:month], cell[:day], cell[:hour], cell[:min], cell[:sec], cell[:usec]
|
87
|
+
)
|
88
|
+
t.getlocal.strftime('%F %T.%6N %z')
|
89
|
+
else
|
90
|
+
cell.to_s
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
pg.tabularize(
|
95
|
+
{
|
96
|
+
headers: dd[:columns],
|
97
|
+
rows: rows,
|
98
|
+
},
|
99
|
+
ios
|
100
|
+
)
|
67
101
|
end
|
68
102
|
io.close unless io.nil?
|
69
|
-
|
70
103
|
end
|
71
104
|
end
|
72
105
|
|
73
106
|
command 'postgresql migrate' do |c|
|
74
|
-
c.syntax = %
|
75
|
-
c.summary = %
|
76
|
-
c.description = %
|
107
|
+
c.syntax = %(murano postgresql migrate (up|down) [<level>])
|
108
|
+
c.summary = %(Run database migration scripts.)
|
109
|
+
c.description = %(
|
110
|
+
Run database migration scripts.
|
77
111
|
|
78
|
-
|
79
|
-
|
112
|
+
The names of the script files must be in the "<level>-<name>-<up|down>.sql"
|
113
|
+
format. Each file is a series of Postgres SQL commands.
|
80
114
|
|
81
|
-
|
82
|
-
|
115
|
+
The current version of the migrations (last <level> ran) will be stored in an
|
116
|
+
extra table in your database. (__murano_cli__.migrate_version)
|
117
|
+
).strip
|
83
118
|
|
84
|
-
|
119
|
+
c.option '--dir DIR', %(Directory where migrations live)
|
85
120
|
|
86
|
-
c.
|
121
|
+
c.example %(murano postgresql migrate up), %(Run migrations up to largest version.)
|
122
|
+
c.example %(murano postgresql migrate up 2), %(Run migrations up to version 2.)
|
123
|
+
c.example %(murano postgresql migrate down 1), %(Run migrations down to version 1.)
|
124
|
+
c.example %(murano postgresql migrate down 0), %(Run migrations down to version 0.)
|
87
125
|
|
88
|
-
c.
|
89
|
-
|
90
|
-
|
91
|
-
c.example %{murano postgresql migrate down 0}, %{Run migrations down to version 0.}
|
126
|
+
c.action do |args, options|
|
127
|
+
c.verify_arg_count!(args, 2, ['Missing direction'])
|
128
|
+
options.default(dir: File.join($cfg['location.base'], ($cfg['postgresql.migrations_dir'] || '')))
|
92
129
|
|
93
|
-
|
94
|
-
options.default :dir => File.join($cfg['location.base'], $cfg['postgresql.migrations_dir'])
|
130
|
+
pg = MrMurano::Postgresql.new
|
95
131
|
|
96
132
|
direction = args.shift
|
97
|
-
if direction =~ /down/i
|
133
|
+
if direction =~ /down/i
|
98
134
|
direction = 'down'
|
99
|
-
|
135
|
+
elsif direction =~ /up/i
|
100
136
|
direction = 'up'
|
137
|
+
else
|
138
|
+
pg.error "Unrecogized direction: ‘#{direction}’"
|
139
|
+
exit 1
|
101
140
|
end
|
102
141
|
|
103
142
|
want_version = args.first
|
104
143
|
|
105
|
-
pg = MrMurano::Postgresql.new
|
106
|
-
|
107
144
|
# get current version of DB.
|
108
|
-
ret = pg.queries %
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
unless ret[:error].nil?
|
145
|
+
ret = pg.queries %(
|
146
|
+
CREATE SCHEMA IF NOT EXISTS __murano_cli__;
|
147
|
+
CREATE TABLE IF NOT EXISTS __murano_cli__.migrate_version (version integer);
|
148
|
+
SELECT version FROM __murano_cli__.migrate_version ORDER BY version DESC;
|
149
|
+
).gsub(/^\s+/, '')
|
150
|
+
unless ret[:error].nil?
|
114
151
|
pp ret
|
115
152
|
exit 1
|
116
153
|
end
|
117
154
|
pg.debug "create/select: #{ret}"
|
118
|
-
current_version = (((((ret[:result]
|
155
|
+
current_version = (((((ret[:result] || []).last || {})[:rows] || []).first || []).first || 0).to_i
|
119
156
|
|
120
157
|
# Get migrations
|
121
158
|
migrations = Dir[File.join(options.dir, "*-#{direction}.sql")].sort
|
122
|
-
if migrations.empty?
|
123
|
-
pg.error
|
159
|
+
if migrations.empty?
|
160
|
+
pg.error 'No migrations to run.'
|
124
161
|
exit 1
|
125
162
|
end
|
126
163
|
migrations.reverse! if direction == 'down'
|
127
164
|
|
128
|
-
if want_version.nil?
|
129
|
-
want_version, _ = File.basename(migrations.last).split('-')
|
130
|
-
end
|
165
|
+
want_version, = File.basename(migrations.last).split('-') if want_version.nil?
|
131
166
|
want_version = want_version.to_i
|
132
167
|
pg.verbose "Will migrate from version #{current_version} to #{want_version}"
|
133
|
-
if direction == 'down'
|
134
|
-
if want_version >= current_version
|
135
|
-
say
|
136
|
-
exit 0
|
137
|
-
end
|
138
|
-
else
|
139
|
-
if want_version <= current_version then
|
140
|
-
say "Nothing to do."
|
168
|
+
if direction == 'down'
|
169
|
+
if want_version >= current_version
|
170
|
+
say 'Nothing to do.'
|
141
171
|
exit 0
|
142
172
|
end
|
173
|
+
elsif want_version <= current_version
|
174
|
+
say 'Nothing to do.'
|
175
|
+
exit 0
|
143
176
|
end
|
144
177
|
|
145
178
|
pg.debug "Migrations before: #{migrations}"
|
146
179
|
# Select migrations between current and desired
|
147
180
|
migrations.select! do |m|
|
148
|
-
mvrs,
|
181
|
+
mvrs, = File.basename(m).split('-')
|
149
182
|
mvrs = mvrs.to_i
|
150
|
-
if direction == 'down'
|
151
|
-
mvrs <= current_version
|
183
|
+
if direction == 'down'
|
184
|
+
mvrs <= current_version && mvrs > want_version
|
152
185
|
else
|
153
|
-
mvrs > current_version
|
186
|
+
mvrs > current_version && mvrs <= want_version
|
154
187
|
end
|
155
188
|
end
|
156
189
|
pg.debug "Migrations after: #{migrations}"
|
157
190
|
|
158
191
|
# Run migrations.
|
159
192
|
migrations.each do |m|
|
160
|
-
mvrs,
|
193
|
+
mvrs, = File.basename(m).split('-')
|
161
194
|
pg.verbose "Running migration: #{File.basename(m)}"
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
195
|
+
next if $cfg['tool.dry']
|
196
|
+
pg.query 'BEGIN;'
|
197
|
+
ret = pg.queries File.read(m)
|
198
|
+
if !ret[:error].nil?
|
199
|
+
pg.query 'ROLLBACK;'
|
200
|
+
pg.error "Migrations failed at level #{mvrs}"
|
201
|
+
pg.error "Because: #{ret[:error]}"
|
202
|
+
exit 5
|
203
|
+
elsif direction == 'down'
|
204
|
+
pg.queries %(
|
205
|
+
DELETE FROM __murano_cli__.migrate_version WHERE version = #{mvrs};
|
206
|
+
COMMIT;
|
207
|
+
).gsub(/^\s+/, '')
|
208
|
+
else
|
209
|
+
pg.queries %(
|
210
|
+
INSERT INTO __murano_cli__.migrate_version values (#{mvrs});
|
211
|
+
COMMIT;
|
212
|
+
).gsub(/^\s+/, '')
|
179
213
|
end
|
180
214
|
end
|
181
215
|
end
|
182
216
|
end
|
183
217
|
|
184
|
-
# vim: set ai et sw=2 ts=2 :
|
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'vine'
|
2
|
+
require 'yaml'
|
3
|
+
require 'MrMurano/hash'
|
4
|
+
require 'MrMurano/ReCommander'
|
5
|
+
require 'MrMurano/Setting'
|
6
|
+
|
7
|
+
command 'setting list' do |c|
|
8
|
+
c.syntax = %{murano setting list}
|
9
|
+
c.summary = %{List which services and settings are avalible.}
|
10
|
+
c.description = %{
|
11
|
+
List which services and settings are avalible.
|
12
|
+
}.strip
|
13
|
+
c.project_not_required = true
|
14
|
+
|
15
|
+
c.action do |args, options|
|
16
|
+
c.verify_arg_count!(args)
|
17
|
+
|
18
|
+
setting = MrMurano::Setting.new
|
19
|
+
|
20
|
+
ret = setting.list
|
21
|
+
|
22
|
+
dd = []
|
23
|
+
ret.each_pair { |k,v| v.each { |s| dd << "#{k}.#{s}" } }
|
24
|
+
|
25
|
+
setting.outf dd
|
26
|
+
end
|
27
|
+
end
|
28
|
+
alias_command 'settings list', 'setting list'
|
29
|
+
|
30
|
+
command 'setting read' do |c|
|
31
|
+
c.syntax = %{murano setting read <service>.<setting> [<sub-key>]}
|
32
|
+
c.summary = %{Read a setting on a Service}
|
33
|
+
c.description = %{
|
34
|
+
Read a setting on a Service.
|
35
|
+
}.strip
|
36
|
+
|
37
|
+
c.option '-o', '--output FILE', String, %{File to save output to}
|
38
|
+
|
39
|
+
c.action do |args, options|
|
40
|
+
c.verify_arg_count!(args, 2, ['Missing <service>.<setting>'])
|
41
|
+
|
42
|
+
setting = MrMurano::Setting.new
|
43
|
+
|
44
|
+
service, pref = args[0].split('.')
|
45
|
+
subkey = args[1]
|
46
|
+
|
47
|
+
ret = setting.read(service, pref)
|
48
|
+
|
49
|
+
ret = ret.access(subkey) unless subkey.nil?
|
50
|
+
|
51
|
+
io = nil
|
52
|
+
if options.output then
|
53
|
+
io = File.open(options.output, 'w')
|
54
|
+
end
|
55
|
+
setting.outf(ret, io)
|
56
|
+
io.close unless io.nil?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
command 'setting write' do |c|
|
61
|
+
c.syntax = %{murano setting write <service>.<setting> <sub-key> [<value>...]}
|
62
|
+
c.summary = %{Write a setting on a Service}
|
63
|
+
c.description = %{
|
64
|
+
Write a setting on a Service, or just part of a setting.
|
65
|
+
|
66
|
+
if <value> is omitted on command line, then it is read from STDIN.
|
67
|
+
|
68
|
+
This always does a read-modify-write.
|
69
|
+
|
70
|
+
If a sub-key doesn't exist, that entire path will be created as dicts.
|
71
|
+
}.strip
|
72
|
+
|
73
|
+
c.option '--bool', %{Set Value type to boolean}
|
74
|
+
c.option '--num', %{Set Value type to number}
|
75
|
+
c.option '--string', %{Set Value type to string (this is default)}
|
76
|
+
c.option '--json', %{Value is parsed as JSON}
|
77
|
+
c.option '--array', %{Set Value type to array of strings}
|
78
|
+
c.option '--dict', %{Set Value type to a dictionary of strings}
|
79
|
+
|
80
|
+
c.option '--append', %{When sub-key is an array, append values instead of replacing}
|
81
|
+
c.option '--merge', %{When sub-key is a dict, merge values instead of replacing (child dicts are also merged)}
|
82
|
+
|
83
|
+
c.example %{murano setting write Gateway.protocol devmode --bool yes}, %{}
|
84
|
+
c.example %{murano setting write Gateway.identity_format options.length --int 24}, %{}
|
85
|
+
|
86
|
+
c.example %{murano setting write Webservice.cors methods --array HEAD GET POST}, %{}
|
87
|
+
c.example %{murano setting write Webservice.cors headers --append --array X-My-Token}, %{}
|
88
|
+
|
89
|
+
c.example %{murano setting write Webservice.cors --type=json - < }, %{}
|
90
|
+
|
91
|
+
c.action do |args, options|
|
92
|
+
c.verify_arg_count!(args, nil, ['Missing <service>.<setting>', 'Missing <sub-key>'])
|
93
|
+
options.default(
|
94
|
+
bool: false,
|
95
|
+
num: false,
|
96
|
+
string: true,
|
97
|
+
json: false,
|
98
|
+
array: false,
|
99
|
+
dict: false,
|
100
|
+
append: false,
|
101
|
+
merge: false,
|
102
|
+
)
|
103
|
+
|
104
|
+
service, pref = args.shift.split('.')
|
105
|
+
subkey = args.shift
|
106
|
+
value = args.first
|
107
|
+
|
108
|
+
setting = MrMurano::Setting.new
|
109
|
+
|
110
|
+
# If value is '-', pull from $stdin
|
111
|
+
if value.nil? and args.count == 0 then
|
112
|
+
value = $stdin.read
|
113
|
+
end
|
114
|
+
|
115
|
+
# Set value to correct type.
|
116
|
+
if options.bool then
|
117
|
+
if value =~ /(yes|y|true|t|1|on)/i then
|
118
|
+
value = true
|
119
|
+
elsif value =~ /(no|n|false|f|0|off)/i then
|
120
|
+
value = false
|
121
|
+
else
|
122
|
+
setting.error %{Value "#{value}" is not a bool type!}
|
123
|
+
exit 2
|
124
|
+
end
|
125
|
+
elsif options.num then
|
126
|
+
begin
|
127
|
+
value = Integer(value)
|
128
|
+
rescue Exception => e
|
129
|
+
setting.debug e.to_s
|
130
|
+
begin
|
131
|
+
value = Float(value)
|
132
|
+
rescue Exception => e
|
133
|
+
setting.error %{Value "#{value}" is not a number}
|
134
|
+
setting.debug e.to_s
|
135
|
+
exit 2
|
136
|
+
end
|
137
|
+
end
|
138
|
+
elsif options.json then
|
139
|
+
# We use the YAML parser since it will handle most common typos in json and
|
140
|
+
# product the intended output.
|
141
|
+
begin
|
142
|
+
value = YAML.load(value)
|
143
|
+
rescue Exception => e
|
144
|
+
setting.error %{Value not valid JSON (or YAML)}
|
145
|
+
setting.debug e.to_s
|
146
|
+
exit 2
|
147
|
+
end
|
148
|
+
|
149
|
+
elsif options.array then
|
150
|
+
# take remaining args as an array
|
151
|
+
value = args
|
152
|
+
|
153
|
+
elsif options.dict then
|
154
|
+
# take remaining args and convert to hash
|
155
|
+
begin
|
156
|
+
value = Hash.transform_keys_to_symbols(Hash[*args])
|
157
|
+
rescue ArgumentError => e
|
158
|
+
setting.error %{Odd number of arguments to dictionary}
|
159
|
+
setting.debug e.to_s
|
160
|
+
exit 2
|
161
|
+
rescue Exception => e
|
162
|
+
setting.error %{Cannot make dictionary from args}
|
163
|
+
setting.debug e.to_s
|
164
|
+
exit 2
|
165
|
+
end
|
166
|
+
|
167
|
+
elsif options.string then
|
168
|
+
value = value.to_s
|
169
|
+
else
|
170
|
+
# is a string.
|
171
|
+
value = value.to_s
|
172
|
+
end
|
173
|
+
|
174
|
+
ret = setting.read(service, pref)
|
175
|
+
setting.verbose %{Read value: #{ret}}
|
176
|
+
|
177
|
+
# modify and merge.
|
178
|
+
if options.append then
|
179
|
+
g = ret.access(subkey)
|
180
|
+
unless g.kind_of? Array then
|
181
|
+
setting.error %{Cannot append; "#{subkey}" is not an array.}
|
182
|
+
exit 3
|
183
|
+
end
|
184
|
+
g.push(*value)
|
185
|
+
|
186
|
+
elsif options.merge then
|
187
|
+
g = ret.access(subkey)
|
188
|
+
unless g.kind_of? Hash then
|
189
|
+
setting.error %{Cannot append; "#{subkey}" is not a dictionary.}
|
190
|
+
exit 3
|
191
|
+
end
|
192
|
+
g.deep_merge!(value)
|
193
|
+
else
|
194
|
+
ret.set(subkey, value)
|
195
|
+
end
|
196
|
+
setting.verbose %{Going to write composed value: #{ret}}
|
197
|
+
|
198
|
+
setting.write(service, pref, ret)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# vim: set ai et sw=2 ts=2 :
|
203
|
+
|