Project

General

Profile

migrate_json.sh

Roger Borrello, 03/11/2026 06:58 PM

Download (8.49 KB)

 
1
#!/bin/bash
2
set -e
3

    
4
# Retrieve a subkey under the main group from the JSON. Allow default
5
function sub_getval()
6
{
7
   local parent="$1"   # e.g. broker1
8
   local key="$2"
9
   local default="$3"
10
   local file="$4"
11

    
12
   if val=$(_sub_getval "$parent" "$key" "$file"); then
13
      printf '%s\n' "$val"
14
   else
15
      printf '%s\n' "$default"
16
   fi
17
}
18
# Retrieve a subkey under the main group from the JSON.
19
function _sub_getval()
20
{
21
   local parent="$1"   # e.g. broker1
22
   local key="$2"      # e.g. client_xml_file
23
   local file="$3"
24
   local val
25

    
26
   if [[ -z "$parent" || -z "$key" || -z "$file" ]]; then
27
      echo "get_json_subkey: missing arguments" >&2
28
      return 1
29
   fi
30

    
31
   if ! val=$(jq -er --arg p "$parent" --arg k "$key" \
32
      '.[$p][$k]' "$file" 2>/dev/null); then
33
      return 2   # missing key or invalid
34
   fi
35

    
36
   printf '%s\n' "$val"
37
}
38

    
39
# Retrieve a key from the JSON. Allow default
40
function getval()
41
{
42
   local key="$1"
43
   local default="$2"
44
   local file="$3"
45

    
46
   if val=$(_getval "$key" "$file"); then
47
      printf '%s\n' "$val"
48
   else
49
      printf '%s\n' "$default"
50
   fi
51
}
52
# Retrieve a key from the JSON.
53
function _getval()
54
{
55
   local key="$1"
56
   local file="$2"
57
   local val
58

    
59
   if ! val=$(jq -er ".$key" "$file" 2>/dev/null); then
60
      return 2   # missing or jq error
61
   fi
62

    
63
   if [[ "$val" == "null" ]]; then
64
      return 3   # explicit null
65
   fi
66

    
67
   printf '%s\n' "$val"
68
   return 0
69
}
70

    
71
# Function to load list in JSON into array. Backward compatible with old string keys
72
# Returns: 0 - all good, even empty array if not required
73
#          1 - Fail, since array is empty and required
74
function load_array_from_json()
75
{
76
   local key="$1"                # e.g. "dbnames" or "parent.child.list"
77
   local file="$2"
78
   local -n out_array="$3"       # nameref target
79
   local required="${4:-true}"   # true = must exist and non-empty
80

    
81
   # Verify key exists
82
   if ! jq -e "getpath([\"${key//./\",\"}\"])" "$file" >/dev/null 2>&1; then
83
      if [[ "$required" == "true" ]]; then
84
         echo "ERROR: Required key missing: $key" >&2
85
         return 1
86
      else
87
         out_array=()
88
         return 0
89
      fi
90
   fi
91

    
92
   local type
93
   type=$(jq -r "getpath([\"${key//./\",\"}\"]) | type" "$file")
94

    
95
   case "$type" in
96
      array )
97
         mapfile -t out_array < <(
98
             jq -r "getpath([\"${key//./\",\"}\"])[]" "$file"
99
         )
100
         ;;
101
      string )
102
         local raw
103
         raw=$(jq -r "getpath([\"${key//./\",\"}\"])" "$file")
104
         IFS=',' read -r -a out_array <<< "$raw"
105
         ;;
106
      null )
107
         if [[ "$required" == "true" ]]; then
108
            echo "ERROR: Required key is null: $key" >&2
109
            return 1
110
         else
111
            out_array=()
112
            return 0
113
         fi
114
         ;;
115
      * )
116
         echo "ERROR: $key must be string or array (got $type)" >&2
117
         return 1
118
         ;;
119
   esac
120

    
121
   # Enforce non-empty if required
122
   if [[ "$required" == "true" ]] && ((${#out_array[@]} == 0)); then
123
      echo "ERROR: Required key is empty: $key" >&2
124
      return 1
125
   fi
126

    
127
   return 0
128
}
129

    
130
add_object_if_present()
131
{
132
   local key="$1"
133
   local file="$2"
134
   local json="$3"
135
   local obj
136

    
137
   if obj=$(jq -ce ".$key" "$file" 2>/dev/null); then
138
      json=$(jq --arg k "$key" --argjson v "$obj" '. + {($k): $v}' <<<"$json")
139
   fi
140

    
141
   echo "$json"
142
}
143

    
144
add_if_present()
145
{
146
   local key="$1"
147
   local file="$2"
148
   local json="$3"
149
   local val
150

    
151
   if ! val=$(_getval $key $file); then
152
      echo "$json"
153
      return
154
   fi
155

    
156
   # Determine if value is valid JSON (number/bool/object/array)
157
   if [[ "$val" =~ ^-?[0-9]+$ ]]; then
158
      json=$(jq --arg k "$key" --argjson v "$val" '. + {($k): $v}' <<<"$json")
159
   else
160
      json=$(jq --arg k "$key" --arg v "$val" '. + {($k): $v}' <<<"$json")
161
   fi
162

    
163
   echo "$json"
164
}
165

    
166
infile="$1"
167
outfile="$2"
168

    
169
if [[ -z "$infile" ]]; then
170
   echo "Usage: $0 original.json [original_migrated.json]"
171
   exit 1
172
fi
173

    
174
if [[ ! -f "$infile" ]]; then
175
   echo "ERROR: input JSON not found: $infile"
176
   exit 1
177
fi
178

    
179
# If outfile not provided, derive it from infile
180
if [[ -z "$outfile" ]]; then
181
   base="${infile%.json}"          # strip .json if present
182
   outfile="${base}_migrated.json"
183
fi
184

    
185
############################################
186
# Determine database list
187
############################################
188
load_array_from_json "dbnames" "$infile" dbnames false
189

    
190
if [[ ${#dbnames[@]} -eq 0 ]]; then
191
   dbnames=("hotel")
192
fi
193

    
194
############################################
195
# Build database array
196
############################################
197
db_json="[]"
198

    
199
for db in "${dbnames[@]}"; do
200
   dbtype=$(sub_getval "$db" "dbtype" "h2" "$infile")
201
   dbhost=$(sub_getval "$db" "dbhost" "localhost" "$infile")
202
   db_obj=$(jq -n \
203
      --arg name "$db" \
204
      --arg dbtype "$dbtype" \
205
      --arg dbhost "$dbhost" \
206
      '{name:$name,dbtype:$dbtype,dbhost:$dbhost}')
207

    
208
   if [[ "$dbtype" == "postgres" ]]; then
209
      dbport=$(sub_getval "$db" "dbport" "5432" "$infile")
210
      db_obj=$(jq --argjson dbport "$dbport" '. + {dbport:$dbport}' <<<"$db_obj")
211

    
212
      # Optional dbpath
213
      if dbpath=$(_sub_getval "$db" "dbpath" "$infile"); then
214
         db_obj=$(jq --arg dbpath "$dbpath" '. + {dbpath:$dbpath}' <<<"$db_obj")
215
      fi
216
   else
217
      dbpath=$(sub_getval "$db" "dbpath" "../db" "$infile")
218
      db_obj=$(jq --arg dbpath "$dbpath" '. + {dbpath:$dbpath}' <<<"$db_obj")
219
   fi
220

    
221
   # Optional collation
222
   if collation=$(_sub_getval "$db" "collation" "$infile"); then
223
      db_obj=$(jq --arg collation "$collation" '. + {collation:$collation}' <<<"$db_obj")
224
   fi
225

    
226
   db_json=$(jq --argjson obj "$db_obj" '. += [$obj]' <<<"$db_json")
227

    
228
done
229

    
230
############################################
231
# Build brokers list
232
############################################
233
broker_json="[]"
234

    
235
mapfile -t brokers < <(
236
jq -r '
237
   if .brokers == null then empty
238
   elif (.brokers|type) == "array" then .brokers[]
239
   elif (.brokers|type) == "string" then .brokers | split(",")[]
240
   else empty
241
   end
242
' "$infile"
243
)
244

    
245
i=0
246
for br in "${brokers[@]}"; do
247
   ((i++))
248

    
249
   br_obj=$(jq -c --arg b "$br" --arg i "$i" '
250
      .[$b] // {} |
251
      {
252
        name: ("localhost-broker"+$i),
253
        client_xml_file: (.client_xml_file // ("../etc/broker"+$i+"_client.xml")),
254
        broker_os_user: (.broker_os_user // "fwd"),
255
        broker_process_acl: (.broker_process_acl // "00000"),
256
        spawner_path: (.spawner_path // "/opt/spawner/spawn"),
257
        broker_client: (.broker_client // "localhost"),
258
        broker_server: (.broker_server // "localhost"),
259
        storepath: (.storepath // "./deploy/security"),
260
        logpath: (.logpath // "./deploy/logs"),
261
        fwd_lib: (.fwd_lib // "/opt/fwd/build/lib")
262
      }
263
   ' "$infile")
264

    
265
   broker_json=$(jq --argjson obj "$br_obj" '. += [$obj]' <<<"$broker_json")
266

    
267
done
268

    
269
############################################
270
# Build server object
271
############################################
272
server_json='{"name":"localhost"}'
273
for key in \
274
   spawner_path \
275
   server_xml_file \
276
   directory_xml_file \
277
   client_start_dir \
278
   dateFormat \
279
   numberGroupSep \
280
   numberDecimalSep \
281
   p2j_entry \
282
   pkgroot \
283
   propath \
284
   search_path \
285
   path_separator \
286
   file_separator \
287
   case_sensitive \
288
   os_user \
289
   kbd_layout \
290
   dbuser \
291
   dbuserpass \
292
   dbadmin \
293
   dbadminpass \
294
   server_log \
295
   client_log \
296
   embedded_host \
297
   admin_port \
298
   log_rotation_limit \
299
   log_rotation_count
300
do
301
   server_json=$(add_if_present "$key" "$infile" "$server_json")
302
done
303

    
304
# Add non-flat objects
305
server_json=$(add_object_if_present "proxy" "$infile" "$server_json")
306
server_json=$(add_object_if_present "webcert" "$infile" "$server_json")
307
server_json=$(add_object_if_present "soap" "$infile" "$server_json")
308
server_json=$(add_object_if_present "session_management" "$infile" "$server_json")
309

    
310
############################################
311
# Convert dbnames array → JSON array
312
############################################
313
db_array_json=$(printf '%s\n' "${dbnames[@]}" | jq -R . | jq -s .)
314

    
315
############################################
316
# Add databases to server
317
############################################
318

    
319
server_json=$(jq \
320
   --argjson dbs "$db_array_json" \
321
   '. + {databases: $dbs}' \
322
   <<<"$server_json")
323

    
324
# Add brokers, if any
325
if [[ "$broker_json" != "[]" ]]; then
326
   server_json=$(jq \
327
      --argjson brokers "$broker_json" \
328
      '. + {brokers: $brokers}' \
329
      <<<"$server_json")
330
fi
331

    
332
############################################
333
# Assemble final JSON
334
############################################
335
jq -n \
336
   --argjson server "$server_json" \
337
   --argjson dbs "$db_json" \
338
'
339
{
340
   servers: [$server],
341
   databases: $dbs
342
}
343
' > "$outfile"
344

    
345
echo "Migration complete:"
346
echo "Old: $infile"
347
echo "New: $outfile"