New Feature : Update descriptor package generator to support flavour and other inputs
[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 ARCHIVE=false
62 CREATE_NSD=false
63 VENDOR='OSM'
64 INTF_TYPE='VIRTIO'
65 VCPU=2
66 MEMORY=4096
67 STORAGE=10
68 CLOUD_INIT='#cloud-config '
69 INTERFACES=1
70
71 function usage() {
72 cat <<EOF
73 Usage:
74 $SCRIPTNAME [-t <type>] [-N] [-c] [base-directory] <package-name>
75
76 -h|--help : show this message
77
78 -t|--package-type <nsd|vnfd> : Descriptor package type
79 is NSD or VNFD. Script will try to
80 determine the type if not provided.
81 Default is vnfd for create-folders.
82
83 -d|--destination-dir <destination directory>: Directory to create the
84 archived file.
85 Default is base-directory
86
87 -N|--no-remove-files : Do not remove the package files after creating
88 archive
89
90 Options specifc for create descriptor:
91
92 -c|--create-folder : Create folder with the structure for the
93 package type using the base-dir and package-dir
94 and a descriptor template
95
96 -a|--archive: Create package for the descriptor
97
98 --nsd : Generate NSD descriptor package also.
99
100 --vendor : Vendor name for descriptor. Default OSM
101
102 --interface-type : Interface type [VIRTIO|SR-IOV|PCI-PASSTHROUGH|E1000|OM-MGMT]
103 Default VIRTIO
104
105 VM Flavour options:
106
107 --vcpu : Virtual CPU count. Default 2
108
109 --memory : Memory for VM in MB. Default 4096MB
110
111 --storage : Storage size for VM in GB. Default 10GB
112
113 VDU Parameters:
114
115 --image : Location URI of the image
116
117 --cloud-init-file : Cloud init file
118
119 --cloud-init : Cloud init script. Will be ignored if
120 cloud-init-file is specified
121
122 --interfaces : Number of external interfaces. Default 1.
123
124 End of create descriptor specific options
125
126 -v| --verbose : Generate progress details
127
128 -n| --dry-run : Validate the package dir
129
130 base-dir : Directory where the archive file or folders are created,
131 if destination directory is not specified.
132 Default is current directory
133
134 package-name : The descriptor name (full path if base-dir not specified)
135 EOF
136 }
137
138 CP_TYPE='VPORT'
139 function get_cp_type() {
140 case ${INTF_TYPE} in
141 VIRTIO ) CP_TYPE='VPORT';;
142 SR-IOV ) CP_TYPE='VPORT';;
143 PCI-PASSTHROUGH ) CP_TYPE='VPORT';;
144 OM-MGMT ) CP_TYPE='VPORT';;
145 E1000 ) CP_TYPE='VPORT';;
146 * ) echo "ERROR: Unknown interface type ${INTF_TYPE}"; exit 1;;
147 esac
148 }
149
150 # Get pci number starting from 0x0a
151 get_pci() {
152 printf '%02x' $((10 + $1)) | tr '[:upper:]' '[:lower:]'
153 }
154
155 function write_vnfd_tmpl() {
156 name=$(basename $1)
157 desc_file="${name}.yaml"
158
159 cat >$desc_file <<EOF
160 vnfd:vnfd-catalog:
161 vnfd:
162 - id: ${name}
163 name: ${name}
164 short-name: ${name}
165 description: Generated by OSM pacakage generator
166 vendor: ${VENDOR}
167 version: '1.0'
168
169 # Place the logo as png in icons directory and provide the name here
170 # logo: <update, optional>
171
172 # Management interface
173 mgmt-interface:
174 vdu-id: ${name}-VM
175
176 # Atleast one VDU need to be specified
177 vdu:
178 - id: ${name}-VM
179 name: ${name}-VM
180 description: ${name}-VM
181 count: 1
182
183 # Flavour of the VM to be instantiated for the VDU
184 vm-flavor:
185 vcpu-count: ${VCPU}
186 memory-mb: ${MEMORY}
187 storage-gb: ${STORAGE}
188
189 # Image including the full path
190 image: '${IMAGE}'
191
192 EOF
193
194 # Add the cloud init file or script
195 if [[ -n ${CLOUD_INIT_FILE} ]]; then
196 cif=$(basename ${CLOUD_INIT_FILE})
197 cat >>$desc_file <<EOF
198 # Cloud init file
199 cloud-init-file: '${cif}'
200 EOF
201 else
202 cat >>$desc_file <<EOF
203 # Cloud init to use
204 cloud-init: '${CLOUD_INIT}'
205 EOF
206 fi
207
208 # Add external interfaces
209 cat >>$desc_file <<EOF
210 external-interface:
211 # Specify the external interfaces
212 # There can be multiple interfaces defined
213 EOF
214
215 # Add external interfaces
216 for i in `seq 1 ${INTERFACES}`; do
217 eth=$(($i - 1))
218 pci=$(get_pci $eth)
219 cat >>$desc_file <<EOF
220 - name: eth${eth}
221 virtual-interface:
222 type: ${INTF_TYPE}
223 bandwidth: '0'
224 vpci: 0000:00:${pci}.0
225 vnfd-connection-point-ref: eth${eth}
226 EOF
227 done
228
229 # Add connection points
230 cat >>$desc_file <<EOF
231
232 connection-point:
233 EOF
234
235 for i in `seq 1 ${INTERFACES}`; do
236 eth=$(($i - 1))
237 cat >>$desc_file <<EOF
238 - name: eth${eth}
239 type: ${CP_TYPE}
240 EOF
241 done
242
243 if [ $VERBOSE == true ]; then
244 echo "INFO: Created $desc_file"
245 fi
246 }
247
248 function write_nsd_tmpl() {
249 name=$(basename $1)
250 vnfd=$2
251 desc_file="${name}.yaml"
252
253 cat >$desc_file <<EOF
254 nsd:nsd-catalog:
255 nsd:
256 - id: ${name}
257 name: ${name}
258 short-name: ${name}
259 description: Generated by OSM pacakage generator
260 vendor: ${VENDOR}
261 version: '1.0'
262
263 # Place the logo as png in icons directory and provide the name here
264 # logo: <update, optional>
265
266 # Specify the VNFDs that are part of this NSD
267 constituent-vnfd:
268 # The member-vnf-index needs to be unique, starting from 1
269 # vnfd-id-ref is the id of the VNFD
270 # Multiple constituent VNFDs can be specified
271 - member-vnf-index: 1
272 vnfd-id-ref: ${vnfd}
273
274 EOF
275
276 cat >>$desc_file <<EOF
277 vld:
278 # Networks for the VNFs
279 EOF
280
281 for i in `seq 1 ${INTERFACES}`; do
282 eth=$(($i - 1))
283 cat >>$desc_file <<EOF
284 - id: ${name}_vld${i}
285 name: ${name}_vld${i}
286 type: ELAN
287 provider-network:
288 overlay-type: VLAN
289 physical-network: <update>
290 segmentation_id: <update>
291 vnfd-connection-point-ref:
292 # Specify the constituent VNFs
293 # member-vnf-index-ref - entry from constituent vnf
294 # vnfd-id-ref - VNFD id
295 # vnfd-connection-point-ref - connection point name in the VNFD
296 - nsd:member-vnf-index-ref: 1
297 nsd:vnfd-id-ref: ${vnfd}
298 # Validate the entry below
299 nsd:vnfd-connection-point-ref: eth${eth}
300 EOF
301 done
302
303 if [ $VERBOSE == true ]; then
304 echo "INFO: Created $desc_file"
305 fi
306 }
307
308 function write_nsd_config_tmpl() {
309 name=$(basename $1)
310 cfg_file="ns_config/$name.yaml"
311
312 cat >$cfg_file <<EOF
313
314 EOF
315
316 if [ $VERBOSE == true ]; then
317 echo "INFO: Created $cfg_file"
318 fi
319 }
320
321 cur_dir=`pwd`
322
323 # Check if the array contains a specific value
324 # Taken from
325 # http://stackoverflow.com/questions/3685970/check-if-an-array-contains-a-value
326 function contains() {
327 local n=$#
328 local value=${!n}
329 for ((i=1;i < $#;i++)); do
330 if [ "${!i}" == "${value}" ]; then
331 echo "y"
332 return 0
333 fi
334 done
335 echo "n"
336 return 1
337 }
338
339 function check_type() {
340 type=$1
341 if [ $(contains "${DESC_TYPES[@]}" $type) == "y" ]; then
342 TYPE=$type
343 else
344 echo "ERROR: Unknown descriptor type $type!" >&2
345 exit 1
346 fi
347 }
348
349 function get_expr(){
350 # First argument is to specify if this is a negative match or not
351 # Rest are filename expressions without extension
352
353 local regex=" "
354 local n=$#
355 local neg="${1}"
356 local first="true"
357 for ((i=2;i <= $#;i++)); do
358 for extn in "${DESC_EXTN[@]}"; do
359 if [ $first == true ]; then
360 if [ $neg == true ]; then
361 subexpr='! -name'
362 else
363 subexpr='-name'
364 fi
365 first=false
366 else
367 if [ $neg == true ]; then
368 subexpr=' -a ! -name'
369 else
370 subexpr=' -o -name'
371 fi
372 fi
373
374 regex="$regex $subexpr ${!i}.$extn"
375 done
376 done
377
378 echo "$regex"
379 }
380
381 function generate_package(){
382 type=$1
383 name="${2}_${type}"
384 vnfd="${2}_vnfd" # Required for NSD
385 dest_dir=$3
386
387 dir="${dest_dir}/${name}"
388
389 # Create the folders for the descriptor
390 if [ $VERBOSE == true ]; then
391 echo "INFO: Creating folders for $PKG in $dest_dir"
392 fi
393
394 # Remove any existing directory
395 if [ -d $dir ]; then
396 rm -rf $dir >/dev/null 2>&1
397 fi
398
399 mkdir -p $dir && cd $dir
400 if [ $? -ne 0 ]; then
401 rc=$?
402 echo "ERROR: creating directory $dir ($rc)" >&2
403 exit $rc
404 fi
405
406 if [ $type == 'nsd' ]; then
407 folders=("${NSD_FOLDERS[@]}")
408 else
409 folders=("${VNFD_FOLDERS[@]}")
410 fi
411
412 for d in ${folders[@]}; do
413 mkdir -p $dir/$d
414 if [ $? -ne 0 ]; then
415 rc=$?
416 echo "ERROR: creating directory $dir/$d ($rc)" >&2
417 exit $rc
418 fi
419 if [ $VERBOSE == true ]; then
420 echo "Created folder $d in $dir"
421 fi
422 done
423
424 if [ $VERBOSE == true ]; then
425 echo "INFO: Created folders for in $dir"
426 fi
427
428 # Write a descriptor template file
429 if [ $type == 'vnfd' ]; then
430
431 # Copy cloud init file to correct folder
432 if [[ -n ${CLOUD_INIT_FILE} ]]; then
433 if [[ -e ${CLOUD_INIT_FILE} ]]; then
434 cp ${CLOUD_INIT_FILE} $dir/cloud_init
435 else
436 echo "ERROR: Unable to find cloud-init-file ${CLOUD_INIT_FILE}"
437 exit 1
438 fi
439 fi
440
441 write_vnfd_tmpl $dir
442 else
443 write_nsd_tmpl $dir $vnfd
444 fi
445
446 if [ $ARCHIVE == true ]; then
447 # Create archive of the package
448 cd $dest_dir
449 if [ $VERBOSE == true ]; then
450 tar zcvf ${name}.tar.gz ${name}
451 echo "Created package ${name}.tar.gz in $dest_dir"
452 else
453 tar zcvf ${name}.tar.gz ${name} >/dev/null 2>&1
454 fi
455
456 if [ $? -ne 0 ]; then
457 echo "ERROR: Creating archive for ${name} in $dest_dir" >&2
458 exit 1
459 fi
460
461 echo "$dest_dir/${name}.tar.gz" >&2
462
463 if [ $RM == true ]; then
464 rm -rf ${name}
465 fi
466 fi
467 }
468
469 OPTS=`getopt -o vhnt:d:caN --long verbose,dry-run,help,package-type:,destination-dir,create-folder,no-remove-files,archive,nsd,vendor:,interface-type:,vcpu:,memory:,storage:,image:,cloud-init-file:,cloud-init:,interfaces:,debug -n $SCRIPTNAME -- "$@"`
470
471 if [ $? != 0 ] ; then
472 echo "ERROR: Failed parsing options ($?)." >&2
473 usage
474 exit 1
475 fi
476
477 echo "$OPTS"
478 eval set -- "$OPTS >/dev/null 2>&1"
479
480 while true; do
481 case "$1" in
482 -v | --verbose ) VERBOSE=true; shift ;;
483 -h | --help ) usage; exit 0; shift ;;
484 -n | --dry-run ) DRY_RUN=true; shift ;;
485 -t | --package-type ) check_type "$2"; shift; shift ;;
486 -d | --destination-dir ) DEST_DIR=$2; shift; shift;;
487 -c | --create-folder ) CREATE=true; shift;;
488 -N | --no-remove-files ) RM=''; shift;;
489 -a | --archive ) ARCHIVE=true; shift;;
490 --nsd ) CREATE_NSD=true; shift;;
491 --vendor ) VENDOR=$2; shift; shift;;
492 --interface-type ) INTF_TYPE=$2; shift; shift;;
493 --vcpu ) VCPU=$2; shift; shift;;
494 --memory ) MEMORY=$2; shift; shift;;
495 --storage ) STORAGE=$2; shift; shift;;
496 --image ) IMAGE=$2; shift; shift;;
497 --cloud-init ) CLOUD_INIT=$2; shift; shift;;
498 --cloud-init-file ) CLOUD_INIT_FILE=$2; shift; shift;;
499 --interfaces ) INTERFACES=$2; shift; shift;;
500 --debug ) DEBUG=true; shift;;
501 -- ) shift; break ;;
502 * ) break ;;
503 esac
504 done
505
506 if [ $DEBUG == true ]; then
507 echo "INFO: Debugging ON"
508 set -x
509 fi
510
511 if [ $VERBOSE == true ]; then
512 echo "INFO: Descriptor type: $TYPE"
513 fi
514
515 # Dry run is to validate existing descriptor folders
516 if [ $DRY_RUN == true ] && [ $CREATE == true ]; then
517 echo "ERROR: Option dry-run with create-folders not supported!" >&2
518 exit 1
519 fi
520
521 if [ $# -gt 1 ]; then
522 BASE_DIR=$1
523 PKG=$(basename $2)
524 else
525 BASE_DIR=$(dirname $1)
526 PKG=$(basename $1)
527 fi
528
529 if [ $VERBOSE == true ]; then
530 echo "INFO: Using base dir: $BASE_DIR"
531 fi
532
533 if [ $VERBOSE == true ]; then
534 echo "INFO: Using package: $PKG"
535 fi
536
537 if [[ -z "$PKG" ]]; then
538 echo "ERROR: Need to specify the package name" >&2
539 usage >&2
540 exit 1
541 fi
542
543 cd $BASE_DIR
544 if [ $? -ne 0 ]; then
545 if [ $CREATE == true ]; then
546 mkdir -p $BASE_DIR
547 if [ $? -ne 0 ]; then
548 echo "ERROR: Unable to create base directory $BASE_DIR" >&2
549 exit 1
550 fi
551 cd $BASE_DIR
552 else
553 echo "ERROR: Unable to change to base directory $BASE_DIR!" >&2
554 exit 1
555 fi
556 fi
557
558 # Get full base dir path
559 BASE_DIR=`pwd`
560 cd $cur_dir
561
562 if [[ -z $DEST_DIR ]]; then
563 DEST_DIR=$BASE_DIR # Default to base directory
564 fi
565
566 mkdir -p $DEST_DIR
567
568 cd $DEST_DIR
569 if [ $? -ne 0 ]; then
570 echo "ERROR: Not able to access destination directory $DEST_DIR!" >&2
571 exit 1
572 fi
573
574 # Get the full destination dir path
575 DEST_DIR=`pwd`
576 cd $cur_dir
577
578 dir=${BASE_DIR}/${PKG}
579
580 function add_chksum() {
581 if [ $VERBOSE == true ]; then
582 echo "INFO: Add file $1 to $CHKSUM"
583 fi
584
585 md5sum $1 >> $CHKSUM
586 }
587
588 if [ $CREATE == false ]; then
589 if [ ! -d $dir ]; then
590 echo "INFO: Package folder $dir not found!" >&2
591 exit 1
592 fi
593
594 cd $dir
595 if [ $? -ne 0 ]; then
596 rc=$?
597 echo "ERROR: changing directory to $dir ($rc)" >&2
598 exit $rc
599 fi
600
601 # Remove checksum file, if present
602 rm -f $CHKSUM
603
604 # Check if the descriptor file is present
605 if [[ -z $TYPE ]]; then
606 # Desc type not specified, look for the desc file and guess the type
607 # Required for backward compatibility
608 for ty in ${DESC_TYPES[@]}; do
609 re=$(get_expr false "$ty" "*_$ty" "*_${ty}_*")
610 desc=$(find * -maxdepth 0 -type f $re 2>/dev/null)
611
612 if [[ -z $desc ]] || [ ${#desc[@]} -eq 0 ]; then
613 # Check the vnfd|nsd folder
614 if [ ! -d $ty ]; then
615 continue
616 fi
617 re=$(get_expr false "*")
618 desc=$(find $ty/* -maxdepth 0 -type f $re 2>/dev/null)
619 if [[ -z $desc ]] || [ ${#desc[@]} -eq 0 ]; then
620 continue
621 elif [ ${#desc[@]} -gt 1 ]; then
622 echo "ERROR: Found multiple descriptor files: ${desc[@]}" >&2
623 exit 1
624 fi
625 # Descriptor sub directory
626 desc_sub_dir=$ty
627 fi
628
629 TYPE=$ty
630 if [ $TYPE == 'nsd' ]; then
631 folders=("${NSD_FOLDERS[@]}")
632 else
633 folders=("${VNFD_FOLDERS[@]}")
634 fi
635
636 if [ $VERBOSE == true ]; then
637 echo "INFO: Determined descriptor is of type $TYPE"
638 fi
639 break
640 done
641
642 if [[ -z $TYPE ]]; then
643 echo "ERROR: Unable to determine the descriptor type!" >&2
644 exit 1
645 fi
646 else
647 if [ $TYPE == 'nsd' ]; then
648 folders=("${NSD_FOLDERS[@]}")
649 else
650 folders=("${VNFD_FOLDERS[@]}")
651 fi
652
653 # Check for descriptor of type provided on command line
654 re=$(get_expr false "$TYPE" "*_${TYPE}" "*_${TYPE}_*")
655 desc=$(find * -maxdepth 0 -type f $re 2>/dev/null)
656
657 if [[ -z $desc ]] || [ ${#desc[@]} -eq 0 ]; then
658 # Check if it is under vnfd/nsd subdirectory
659 # Backward compatibility support
660 re=$(get_expr false "*")
661 desc=$(find $TYPE/* -maxdepth 0 -type f $re 2>/dev/null)
662 if [[ -z $desc ]] || [ ${#desc[@]} -eq 0 ]; then
663 echo "ERROR: Did not find descriptor file of type $TYPE" \
664 " in $dir" >&2
665 exit 1
666 fi
667 desc_sub_dir=$ty
668 fi
669 fi
670
671 if [ ${#desc[@]} -gt 1 ]; then
672 echo "ERROR: Found multiple files of type $TYPE in $dir: $desc" >&2
673 exit 1
674 fi
675
676 descriptor=${desc[0]}
677
678 # Check if there are files not supported
679 files=$(find * -maxdepth 0 -type f ! -name $descriptor 2>/dev/null)
680
681 for f in ${files[@]}; do
682 if [ $(contains "${ALLOWED_FILES[@]}" $f) == "n" ]; then
683 echo "WARN: Unsupported file $f found"
684 fi
685 done
686
687 if [ $VERBOSE == true ]; then
688 echo "INFO: Found descriptor package: ${desc_sub_dir} ${descriptor}"
689 fi
690
691 if [ $DRY_RUN == false ]; then
692 add_chksum ${descriptor}
693 fi
694
695 # Check the folders are supported ones
696 dirs=$( find * -maxdepth 0 -type d )
697
698 for d in ${dirs[@]}; do
699 if [ $(contains "${folders[@]}" $d) == "y" ]; then
700 if [ $DRY_RUN == false ]; then
701 find $d/* -type f 2>/dev/null|
702 while read file; do
703 add_chksum $file
704 done
705 fi
706 elif [[ -z $desc_sub_dir ]] || [ $d != $desc_sub_dir ]; then
707 echo "WARN: $d is not part of standard folders " \
708 "for descriptor type $TYPE in $PKG"
709 fi
710 done
711
712 if [ $VERBOSE == true ]; then
713 echo "INFO: Creating archive for $PKG"
714 fi
715
716 cd $BASE_DIR
717 if [ $DRY_RUN == false ]; then
718 tar zcvf "$DEST_DIR/$PKG.tar.gz" "${PKG}" ${RM}
719 if [ $? -ne 0 ]; then
720 rc=$?
721 echo "ERROR: creating archive for $PKG ($rc)" >&2
722 exit $rc
723 fi
724 fi
725 else
726 # Create, default to VNFD if no type is defined
727 if [[ -z $TYPE ]]; then
728 TYPE=vnfd
729 if [ $VERBOSE == true ]; then
730 echo "WARNING: Defaulting to descriptor type $TYPE"
731 fi
732 fi
733
734 if [ $TYPE == 'vnfd' ]; then
735 if [[ -z $IMAGE ]]; then
736 echo "ERROR: Image file need to be specified for VNF"
737 exit 1
738 fi
739 generate_package vnfd $PKG $DEST_DIR
740 fi
741
742 if [ $TYPE == 'nsd' -o $CREATE_NSD == true ]; then
743 generate_package nsd $PKG $DEST_DIR
744 fi
745
746 fi
747
748 cd $cur_dir