New Feature Request: Enhance descriptor package creation script
[osm/devops.git] / src / generate_descriptor_pkg.sh
1 #!/bin/bash
2
3 ############################################################################
4 # Copyright 2016 RIFT.io Inc #
5 # #
6 # Licensed under the Apache License, Version 2.0 (the "License"); #
7 # you may not use this file except in compliance with the License. #
8 # You may obtain a copy of the License at #
9 # #
10 # http://www.apache.org/licenses/LICENSE-2.0 #
11 # #
12 # Unless required by applicable law or agreed to in writing, software #
13 # distributed under the License is distributed on an "AS IS" BASIS, #
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15 # See the License for the specific language governing permissions and #
16 # limitations under the License. #
17 ############################################################################
18
19 #
20 # This shell script is used to create a descriptor package
21 # The main functions of this script include:
22 # - Generate checksums.txt file
23 # - Generate a tar.gz file
24 # This script can be used to create the required folders for
25 # a descriptor package and a template descriptor
26
27 # Usage: generate_descriptor_pkg.sh <base-directory> <package-directory>
28
29 # Descriptor names should be
30 # - (nsd|vnfd).(yaml|yml|json|xml)
31 # - *_(nsd|vnfd).(yaml|yml|json|xml)
32 # - *_(nsd|vnfd)_*.(yaml|yml|json|xml)
33 # - (nsd|vnfd)/*.(yaml|yml|json|xml)
34 #
35
36 SCRIPTNAME=`basename $0`
37
38 # From https://osm.etsi.org/wikipub/index.php/Release_0_Data_Model_Details
39 # Supported folders for VNFD
40 # cloud_init - Rel 4.3, not yet part of OSM
41 VNFD_FOLDERS=(images scripts icons charms cloud_init)
42
43 # Supported folders for NSD
44 # OSM document specifies (ns|vnf)-config folder, while Rel 4.3
45 # is using (ns|vnf)_config.
46 NSD_FOLDERS=(scripts icons ns_config vnf_config)
47
48 # Other files allowed in the descriptor base directory
49 ALLOWED_FILES=(README)
50
51 DESC_TYPES=(vnfd nsd)
52 DESC_EXTN=(yml yaml json xml)
53 CHKSUM='checksums.txt'
54
55 VERBOSE=false
56 DRY_RUN=false
57 CREATE=false
58 RM="--remove-files"
59 DEBUG=false
60
61 function usage() {
62 cat <<EOF
63 Usage:
64 $SCRIPTNAME [-t <type>] [-N] [-c] [base-directory] <package-dir>
65
66 -h|--help : show this message
67
68 -t|--package-type <nsd|vnfd> : Descriptor package type
69 is NSD or VNFD. Script will try to
70 determine the type if not provided.
71 Default is vnfd for create-folders.
72
73 -d|--destination-dir <destination directory>: Directory to create the
74 archived file.
75
76 -N|--no-remove-files : Do not remove the package files after creating
77 archive
78
79 -c|--create-folder : Create folder with the structure for the
80 package type using the base-dir and package-dir
81 and a descriptor template
82
83 -v| --verbose : Generate logs
84
85 -n| --dry-run : Validate the package dir
86
87 base-dir : Directory where the archive file or folders are created,
88 if destination directory is not specified.
89 Default is current directory
90
91 package-dir : The descriptor name and directory
92 EOF
93 }
94
95 function write_vnfd_tmpl() {
96 name=$(basename $1)
97 desc_file="${name}_vnfd.yaml"
98
99 cat >$desc_file <<EOF
100 # Only one VNFD per descriptor package is supported
101 # Update the <update> tag with correct values
102 # Update or remove <update, optional> tags
103 vnfd:vnfd-catalog:
104 vnfd:
105 - id: ${name}
106 name: ${name}
107 short-name: ${name}
108 description: ${name}
109
110 # Place the logo as png in icons directory and provide the name here
111 logo: <update, optional>
112
113 # This is an optional section and can be removed
114 vnf-configuration:
115 config-attributes:
116 config-delay: '0'
117 config-priority: '1'
118
119 # Specify the config method
120 # Remove this section if the VNF does not use a config method
121 juju:
122 charm: <update>
123
124 # config-primitive specifies the config and actions for the VNF/charm
125 # This is an optional section
126 config-primitive:
127 # If there are no config to be set, remove this section
128 - name: config
129 # There can be multiple parameter sections
130 # The name and type should be same as VNF/charm specification
131 parameter:
132 - name: <update>
133 data-type: STRING
134 mandatory: <true|false>
135 default-value: <update>
136
137 # If there are no actions specified at VNF level, remove this section
138 # Multiple action sections can be specified
139 # The name should be the name of the action
140 - name: <update, optional>
141 # There can be multiple parameter sections
142 # The name and type should be same as charm specification
143 parameter:
144 - name: <update, optional>
145 data-type: STRING
146 mandatory: <true|false>
147
148 # Any config or action that need to be executed when VNF comes up
149 # This is an optional section
150 initial-config-primitive:
151 - name: config
152 # Any config to be set when VNF comes up
153 # For charm normally the VNF management IP need to be set
154 # in one of the config parameters
155 # Sepcifying the value a <rw_mgmt_ip> will cause the MANO
156 # to replace this with the management ip of VNF when it is
157 # instantiated
158 parameter:
159 - name: <update>
160 value: <rw_mgmt_ip>
161 seq: '1'
162
163 mgmt-interface:
164 # This should be id of one of the VDUs specified for this VNF
165 vdu-id: ${name}-VM
166 port: <update, optional>
167
168 connection-point:
169 # Specify the connection points from VDU
170 # Can specify multiple connection points here
171 - name: eth0
172 type: VPORT
173 - name: eth1
174 type: VPORT
175
176 # Atleast one VDU need to be specified
177 vdu:
178 - id: ${name}-VM
179 name: ${name}-VM
180 description: ${name}-VM
181
182 # Image including the full path
183 image: <update>
184
185 # Flavour of the VM to be instantiated for the VDU
186 vm-flavor:
187 memory-mb: '4096'
188 storage-gb: '10'
189 vcpu-count: '2'
190
191 external-interface:
192 # Specify the external interfaces
193 # There can be multiple interfaces defined
194 - name: eth0
195 virtual-interface:
196 bandwidth: '0'
197 type: VIRTIO
198 vpci: 0000:00:0a.0
199 vnfd-connection-point-ref: eth0
200 - name: eth1
201 virtual-interface:
202 bandwidth: '0'
203 type: OM-MGMT
204 vpci: 0000:00:0b.0
205 vnfd-connection-point-ref: eth1
206
207 # Mgmt vpci, match with the specification in the
208 # external interface for mgmt
209 mgmt-vpci: 0000:00:0a.0
210
211 # Specify EPA parameters
212 # This section is optional
213 guest-epa:
214 cpu-pinning-policy: DEDICATED
215 cpu-thread-pinning-policy: PREFER
216 mempage-size: LARGE
217 numa-node-policy:
218 mem-policy: STRICT
219 node:
220 - id: '0'
221 paired-threads:
222 num-paired-threads: '1'
223 node-cnt: '1'
224
225 EOF
226
227 if [ $VERBOSE == true ]; then
228 echo "INFO: Created $desc_file"
229 fi
230 }
231
232 function write_nsd_tmpl() {
233 name=$(basename $1)
234 desc_file="${name}_nsd.yaml"
235
236 cat >$desc_file <<EOF
237 # Only one NSD per descriptor package is supported
238 # Update the <update> tag with correct values
239 # Update or remove <update, optional> tags
240 nsd:nsd-catalog:
241 nsd:
242 - id: ${name}
243 name: ${name}
244 short-name: ${name}
245 description: ${name}
246
247 # Place the logo as png in icons directory and provide the name here
248 logo: <update, optional>
249
250 # Specify the VNFDs that are part of this NSD
251 constituent-vnfd:
252 # The member-vnf-index needs to be unique, starting from 1
253 # vnfd-id-ref is the id of the VNFD
254 # Multiple constituent VNFDs can be specified
255 - member-vnf-index: <update>
256 vnfd-id-ref: <update>
257
258 vld:
259 # Management network for the VNFs
260 - id: management
261 name: management
262 provider-network:
263 overlay-type: VLAN
264 physical-network: <update>
265 type: ELAN
266 vnfd-connection-point-ref:
267 # Specify all the constituent VNFs
268 # member-vnf-index-ref - entry from constituent vnf
269 # vnfd-id-ref - VNFD id
270 # vnfd-connection-point-ref - connection point name in the VNFD
271 - member-vnf-index-ref: '1'
272 vnfd-connection-point-ref: <update>
273 vnfd-id-ref: <update>
274 - member-vnf-index-ref: '2'
275 vnfd-connection-point-ref: <update>
276 vnfd-id-ref: <update>
277
278 # Addtional netowrk can be specified for data, etc
279 - id: <update>
280 name: <update>
281 type: ELAN
282 provider-network:
283 overlay-type: VLAN
284 physical-network: <update>
285 vnfd-connection-point-ref:
286 - member-vnf-index-ref: <update>
287 vnfd-connection-point-ref: <update>
288 vnfd-id-ref: <update>
289
290 # NS level configuration primitive
291 # This section is optional
292 config-primitive:
293 - name: <update>
294 # List of parameters, optional
295 parameter:
296 - name: <update>
297 data-type: string
298 default-value: <update>
299 mandatory: <true|false>
300
301 # List of parameters grouped by name
302 # optional section
303 parameter-group:
304 - mandatory: <true|false>
305 name: <update>
306 parameter:
307 - name: <update>
308 data-type: integer
309 default-value: <update>
310 hidden: <true|false>
311 mandatory: <true|false>
312
313 # Script based NS level configuration
314 user-defined-script: <update>
315 EOF
316
317 if [ $VERBOSE == true ]; then
318 echo "INFO: Created $desc_file"
319 fi
320 }
321
322 function write_nsd_config_tmpl() {
323 name=$(basename $1)
324 cfg_file="ns_config/$name.yaml"
325
326 cat >$cfg_file <<EOF
327
328 EOF
329
330 if [ $VERBOSE == true ]; then
331 echo "INFO: Created $cfg_file"
332 fi
333 }
334
335 OPTS=`getopt -o vhnt:d:cN --long verbose,dry-run,help,package-type:,destination-dir,create-folder,no-remove-files,debug -n $SCRIPTNAME -- "$@"`
336
337 if [ $? != 0 ] ; then
338 echo "ERROR: Failed parsing options ($?)." >&2
339 usage
340 exit 1
341 fi
342
343 echo "$OPTS"
344 eval set -- "$OPTS"
345
346 cur_dir=`pwd`
347
348 # Check if the array contains a specific value
349 # Taken from
350 # http://stackoverflow.com/questions/3685970/check-if-an-array-contains-a-value
351 function contains() {
352 local n=$#
353 local value=${!n}
354 for ((i=1;i < $#;i++)); do
355 if [ "${!i}" == "${value}" ]; then
356 echo "y"
357 return 0
358 fi
359 done
360 echo "n"
361 return 1
362 }
363
364 function check_type() {
365 type=$1
366 if [ $(contains "${DESC_TYPES[@]}" $type) == "y" ]; then
367 TYPE=$type
368 else
369 echo "ERROR: Unknown descriptor type $type!" >&2
370 exit 1
371 fi
372 }
373
374 function get_expr(){
375 # First argument is to specify if this is a negative match or match
376 # Rest are filename expressions without extension
377 #
378
379 local regex=" "
380 local n=$1
381 local neg="${1}"
382 for ((i=2;i <= $#;i++)); do
383 if [ $i -eq 2 ]; then
384 if [ $neg == true ]; then
385 subexpr='! -name'
386 else
387 subexpr='-name'
388 fi
389 else
390 if [ $neg == true ]; then
391 subexpr=' -a ! -name'
392 else
393 subexpr=' -o -name'
394 fi
395 fi
396
397 for extn in ${DESC_EXTN[$@]}; do
398 regex="$regex $subexpr ${!i}.$extn"
399 done
400 done
401
402 if [ $VERBOSE == true ]; then
403 echo "INFO: Generate expression: $expr"
404 fi
405
406 echo "$expr"
407 }
408
409 function get_expr(){
410 # First argument is to specify if this is a negative match or not
411 # Rest are filename expressions without extension
412
413 local regex=" "
414 local n=$#
415 local neg="${1}"
416 local first="true"
417 for ((i=2;i <= $#;i++)); do
418 for extn in "${DESC_EXTN[@]}"; do
419 if [ $first == true ]; then
420 if [ $neg == true ]; then
421 subexpr='! -name'
422 else
423 subexpr='-name'
424 fi
425 first=false
426 else
427 if [ $neg == true ]; then
428 subexpr=' -a ! -name'
429 else
430 subexpr=' -o -name'
431 fi
432 fi
433
434 regex="$regex $subexpr ${!i}.$extn"
435 done
436 done
437
438 echo "$regex"
439 }
440
441 while true; do
442 case "$1" in
443 -v | --verbose ) VERBOSE=true; shift ;;
444 -h | --help ) usage; exit 0; shift ;;
445 -n | --dry-run ) DRY_RUN=true; shift ;;
446 -t | --package-type ) check_type "$2"; shift; shift ;;
447 -d | --destination-dir ) DEST_DIR=$2; shift; shift;;
448 -c | --create-folder ) CREATE=true; shift;;
449 -N | --no-remove-files ) RM=''; shift;;
450 --debug ) DEBUG=true; shift;;
451 -- ) shift; break ;;
452 * ) break ;;
453 esac
454 done
455
456 if [ $DEBUG == true ]; then
457 echo "INFO: Debugging ON"
458 set -x
459 fi
460
461 if [ $VERBOSE == true ]; then
462 echo "INFO: Descriptor type: $TYPE"
463 fi
464
465 # Dry run is to validate existing descriptor folders
466 if [ $DRY_RUN == true ] && [ $CREATE == true ]; then
467 echo "ERROR: Option dry-run with create-folders not supported!" >&2
468 exit 1
469 fi
470
471 if [ $# -gt 1 ]; then
472 BASE_DIR=$1
473 PKG=$(basename $2)
474 else
475 BASE_DIR=$(dirname $1)
476 PKG=$(basename $1)
477 fi
478
479 if [ $VERBOSE == true ]; then
480 echo "INFO: Using base dir: $BASE_DIR"
481 fi
482
483 if [ $VERBOSE == true ]; then
484 echo "INFO: Using package: $PKG"
485 fi
486
487 if [ -z "$PKG" ]; then
488 echo "ERROR: Need to specify the package-dir" >&2
489 usage >&2
490 exit 1
491 fi
492
493 cd $BASE_DIR
494 if [ $? -ne 0 ]; then
495 echo "ERROR: Unable to change to base directory $BASE_DIR!" >&2
496 exit 1
497 fi
498
499 # Get full base dir path
500 BASE_DIR=`pwd`
501 cd $cur_dir
502
503 if [ -z $DEST_DIR ]; then
504 DEST_DIR=$BASE_DIR # Default to base directory
505 fi
506
507 mkdir -p $DEST_DIR
508
509 cd $DEST_DIR
510 if [ $? -ne 0 ]; then
511 echo "ERROR: Not able to access destination directory $DEST_DIR!" >&2
512 exit 1
513 fi
514
515 # Get the full destination dir path
516 DEST_DIR=`pwd`
517 cd $cur_dir
518
519 dir=${BASE_DIR}/${PKG}
520
521 function add_chksum() {
522 if [ $VERBOSE == true ]; then
523 echo "INFO: Add file $1 to $CHKSUM"
524 fi
525
526 md5sum $1 >> $CHKSUM
527 }
528
529 if [ $CREATE == false ]; then
530 if [ ! -d $dir ]; then
531 echo "INFO: Package folder $dir not found!" >&2
532 exit 1
533 fi
534
535 cd $dir
536 if [ $? -ne 0 ]; then
537 rc=$?
538 echo "ERROR: changing directory to $dir ($rc)" >&2
539 exit $rc
540 fi
541
542 # Remove checksum file, if present
543 rm -f $CHKSUM
544
545 # Check if the descriptor file is present
546 if [ -z $TYPE ]; then
547 # Desc type not specified, look for the desc file and guess the type
548 # Required for backward compatibility
549 for ty in ${DESC_TYPES[@]}; do
550 re=$(get_expr false "$ty" "*_$ty" "*_${ty}_*")
551 desc=$(find * -maxdepth 0 -type f $re 2>/dev/null)
552
553 if [ -z $desc ] || [ ${#desc[@]} -eq 0 ]; then
554 # Check the vnfd|nsd folder
555 if [ ! -d $ty ]; then
556 continue
557 fi
558 re=$(get_expr false "*")
559 desc=$(find $ty/* -maxdepth 0 -type f $re 2>/dev/null)
560 if [ -z $desc ] || [ ${#desc[@]} -eq 0 ]; then
561 continue
562 elif [ ${#desc[@]} -gt 1 ]; then
563 echo "ERROR: Found multiple descriptor files: ${desc[@]}" >&2
564 exit 1
565 fi
566 # Descriptor sub directory
567 desc_sub_dir=$ty
568 fi
569
570 TYPE=$ty
571 if [ $TYPE == 'nsd' ]; then
572 folders=("${NSD_FOLDERS[@]}")
573 else
574 folders=("${VNFD_FOLDERS[@]}")
575 fi
576
577 if [ $VERBOSE == true ]; then
578 echo "INFO: Determined descriptor is of type $TYPE"
579 fi
580 break
581 done
582
583 if [ -z $TYPE ]; then
584 echo "ERROR: Unable to determine the descriptor type!" >&2
585 exit 1
586 fi
587 else
588 if [ $TYPE == 'nsd' ]; then
589 folders=("${NSD_FOLDERS[@]}")
590 else
591 folders=("${VNFD_FOLDERS[@]}")
592 fi
593
594 # Check for descriptor of type provided on command line
595 re=$(get_expr false "$TYPE" "*_${TYPE}" "*_${TYPE}_*")
596 desc=$(find * -maxdepth 0 -type f $re 2>/dev/null)
597
598 if [ -z $desc ] || [ ${#desc[@]} -eq 0 ]; then
599 # Check if it is under vnfd/nsd subdirectory
600 # Backward compatibility support
601 re=$(get_expr false "*")
602 desc=$(find $TYPE/* -maxdepth 0 -type f $re 2>/dev/null)
603 if [ -z $desc ] || [ ${#desc[@]} -eq 0 ]; then
604 echo "ERROR: Did not find descriptor file of type $TYPE" \
605 " in $dir" >&2
606 exit 1
607 fi
608 desc_sub_dir=$ty
609 fi
610 fi
611
612 if [ ${#desc[@]} -gt 1 ]; then
613 echo "ERROR: Found multiple files of type $TYPE in $dir: $desc" >&2
614 exit 1
615 fi
616
617 descriptor=${desc[0]}
618
619 # Check if there are files not supported
620 files=$(find * -maxdepth 0 -type f ! -name $descriptor 2>/dev/null)
621
622 for f in ${files[@]}; do
623 if [ $(contains "${ALLOWED_FILES[@]}" $f) == "n" ]; then
624 echo "WARN: Unsupported file $f found"
625 fi
626 done
627
628 if [ $VERBOSE == true ]; then
629 echo "INFO: Found descriptor package: ${desc_sub_dir} ${descriptor}"
630 fi
631
632 if [ $DRY_RUN == false ]; then
633 add_chksum ${descriptor}
634 fi
635
636 # Check the folders are supported ones
637 dirs=$( find * -maxdepth 0 -type d )
638
639 for d in ${dirs[@]}; do
640 if [ $(contains "${folders[@]}" $d) == "y" ]; then
641 if [ $DRY_RUN == false ]; then
642 find $d/* -type f 2>/dev/null|
643 while read file; do
644 add_chksum $file
645 done
646 fi
647 elif [ -z $desc_sub_dir ] || [ $d != $desc_sub_dir ]; then
648 echo "WARN: $d is not part of standard folders " \
649 "for descriptor type $TYPE in $PKG"
650 fi
651 done
652
653 if [ $VERBOSE == true ]; then
654 echo "INFO: Creating archive for $PKG"
655 fi
656
657 cd $BASE_DIR
658 if [ $DRY_RUN == false ]; then
659 tar zcvf "$DEST_DIR/$PKG.tar.gz" "${PKG}" ${RM}
660 if [ $? -ne 0 ]; then
661 rc=$?
662 echo "ERROR: creating archive for $PKG ($rc)" >&2
663 exit $rc
664 fi
665 fi
666 else
667 # Create the folders for the descriptor
668 if [ $VERBOSE == true ]; then
669 echo "INFO: Creating folders for $PKG in $dir"
670 fi
671
672 # Create, default to VNFD if no type is defined
673 if [ -z $TYPE ]; then
674 TYPE=vnfd
675 echo "WARNING: Defaulting to descriptor type $TYPE"
676 fi
677
678 mkdir -p $dir && cd $dir
679 if [ $? -ne 0 ]; then
680 rc=$?
681 echo "ERROR: creating directory $dir ($rc)" >&2
682 exit $rc
683 fi
684
685 if [ $TYPE == 'nsd' ]; then
686 folders=("${NSD_FOLDERS[@]}")
687 else
688 folders=("${VNFD_FOLDERS[@]}")
689 fi
690
691 for d in ${folders[@]}; do
692 mkdir -p $dir/$d
693 if [ $? -ne 0 ]; then
694 rc=$?
695 echo "ERROR: creating directory $dir/$d ($rc)" >&2
696 exit $rc
697 fi
698 if [ $VERBOSE == true ]; then
699 echo "Created folder $d in $dir"
700 fi
701 done
702
703 if [ $VERBOSE == true ]; then
704 echo "INFO: Created folders for in $dir"
705 fi
706
707 # Write a descriptor template file
708 if [ $TYPE == 'vnfd' ]; then
709 write_vnfd_tmpl $dir
710 else
711 write_nsd_tmpl $dir
712 # write_nsd_config_tmpl $dir
713 fi
714
715 fi
716
717 cd $cur_dir