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