#!/bin/bash
-#
-# Copyright 2016 RIFT.IO Inc
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Author(s): Austin Cormier
-# Creation Date: 2016/05/23
-#
+
+############################################################################
+# Copyright 2016 RIFT.io Inc #
+# #
+# Licensed under the Apache License, Version 2.0 (the "License"); #
+# you may not use this file except in compliance with the License. #
+# You may obtain a copy of the License at #
+# #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+# #
+# Unless required by applicable law or agreed to in writing, software #
+# distributed under the License is distributed on an "AS IS" BASIS, #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+############################################################################
+
#
# This shell script is used to create a descriptor package
# The main functions of this script include:
# - Generate checksums.txt file
# - Generate a tar.gz file
+# This script can be used to create the required folders for
+# a descriptor package and a template descriptor
+
+# Usage: generate_descriptor_pkg.sh <base-directory> <package-directory>
+
+# Descriptor names should be
+# - (nsd|vnfd).(yaml|yml|json|xml)
+# - *_(nsd|vnfd).(yaml|yml|json|xml)
+# - *_(nsd|vnfd)_*.(yaml|yml|json|xml)
+# - (nsd|vnfd)/*.(yaml|yml|json|xml)
+#
+
+SCRIPTNAME=`basename $0`
+
+# From https://osm.etsi.org/wikipub/index.php/Release_0_Data_Model_Details
+# Supported folders for VNFD
+# cloud_init - Rel 4.3, not yet part of OSM
+VNFD_FOLDERS=(images scripts icons charms cloud_init)
+
+# Supported folders for NSD
+# OSM document specifies (ns|vnf)-config folder, while Rel 4.3
+# is using (ns|vnf)_config.
+NSD_FOLDERS=(scripts icons ns_config vnf_config)
+
+# Other files allowed in the descriptor base directory
+ALLOWED_FILES=(README)
+
+DESC_TYPES=(vnfd nsd)
+DESC_EXTN=(yml yaml json xml)
+CHKSUM='checksums.txt'
+
+VERBOSE=false
+DRY_RUN=false
+CREATE=false
+RM="--remove-files"
+DEBUG=false
+
+function usage() {
+ cat <<EOF
+Usage:
+ $SCRIPTNAME [-t <type>] [-N] [-c] [base-directory] <package-dir>
+
+ -h|--help : show this message
+
+ -t|--package-type <nsd|vnfd> : Descriptor package type
+ is NSD or VNFD. Script will try to
+ determine the type if not provided.
+ Default is vnfd for create-folders.
+
+ -d|--destination-dir <destination directory>: Directory to create the
+ archived file.
+
+ -N|--no-remove-files : Do not remove the package files after creating
+ archive
+
+ -c|--create-folder : Create folder with the structure for the
+ package type using the base-dir and package-dir
+ and a descriptor template
+
+ -v| --verbose : Generate logs
+
+ -n| --dry-run : Validate the package dir
+
+ base-dir : Directory where the archive file or folders are created,
+ if destination directory is not specified.
+ Default is current directory
+
+ package-dir : The descriptor name and directory
+EOF
+}
+
+function write_vnfd_tmpl() {
+ name=$(basename $1)
+ desc_file="${name}_vnfd.yaml"
+
+ cat >$desc_file <<EOF
+# Only one VNFD per descriptor package is supported
+# Update the <update> tag with correct values
+# Update or remove <update, optional> tags
+vnfd:vnfd-catalog:
+ vnfd:
+ - id: ${name}
+ name: ${name}
+ short-name: ${name}
+ description: ${name}
+
+ # Place the logo as png in icons directory and provide the name here
+ logo: <update, optional>
+
+ # This is an optional section and can be removed
+ vnf-configuration:
+ config-attributes:
+ config-delay: '0'
+ config-priority: '1'
+
+ # Specify the config method
+ # Remove this section if the VNF does not use a config method
+ juju:
+ charm: <update>
+
+ # config-primitive specifies the config and actions for the VNF/charm
+ # This is an optional section
+ config-primitive:
+ # If there are no config to be set, remove this section
+ - name: config
+ # There can be multiple parameter sections
+ # The name and type should be same as VNF/charm specification
+ parameter:
+ - name: <update>
+ data-type: STRING
+ mandatory: <true|false>
+ default-value: <update>
+
+ # If there are no actions specified at VNF level, remove this section
+ # Multiple action sections can be specified
+ # The name should be the name of the action
+ - name: <update, optional>
+ # There can be multiple parameter sections
+ # The name and type should be same as charm specification
+ parameter:
+ - name: <update, optional>
+ data-type: STRING
+ mandatory: <true|false>
+
+ # Any config or action that need to be executed when VNF comes up
+ # This is an optional section
+ initial-config-primitive:
+ - name: config
+ # Any config to be set when VNF comes up
+ # For charm normally the VNF management IP need to be set
+ # in one of the config parameters
+ # Sepcifying the value a <rw_mgmt_ip> will cause the MANO
+ # to replace this with the management ip of VNF when it is
+ # instantiated
+ parameter:
+ - name: <update>
+ value: <rw_mgmt_ip>
+ seq: '1'
+
+ mgmt-interface:
+ # This should be id of one of the VDUs specified for this VNF
+ vdu-id: ${name}-VM
+ port: <update, optional>
+
+ connection-point:
+ # Specify the connection points from VDU
+ # Can specify multiple connection points here
+ - name: eth0
+ type: VPORT
+ - name: eth1
+ type: VPORT
+
+ # Atleast one VDU need to be specified
+ vdu:
+ - id: ${name}-VM
+ name: ${name}-VM
+ description: ${name}-VM
+
+ # Image including the full path
+ image: <update>
+
+ # Flavour of the VM to be instantiated for the VDU
+ vm-flavor:
+ memory-mb: '4096'
+ storage-gb: '10'
+ vcpu-count: '2'
+
+ external-interface:
+ # Specify the external interfaces
+ # There can be multiple interfaces defined
+ - name: eth0
+ virtual-interface:
+ bandwidth: '0'
+ type: VIRTIO
+ vpci: 0000:00:0a.0
+ vnfd-connection-point-ref: eth0
+ - name: eth1
+ virtual-interface:
+ bandwidth: '0'
+ type: OM-MGMT
+ vpci: 0000:00:0b.0
+ vnfd-connection-point-ref: eth1
+
+ # Mgmt vpci, match with the specification in the
+ # external interface for mgmt
+ mgmt-vpci: 0000:00:0a.0
+
+ # Specify EPA parameters
+ # This section is optional
+ guest-epa:
+ cpu-pinning-policy: DEDICATED
+ cpu-thread-pinning-policy: PREFER
+ mempage-size: LARGE
+ numa-node-policy:
+ mem-policy: STRICT
+ node:
+ - id: '0'
+ paired-threads:
+ num-paired-threads: '1'
+ node-cnt: '1'
+
+EOF
+
+ if [ $VERBOSE == true ]; then
+ echo "INFO: Created $desc_file"
+ fi
+}
+
+function write_nsd_tmpl() {
+ name=$(basename $1)
+ desc_file="${name}_nsd.yaml"
+
+ cat >$desc_file <<EOF
+# Only one NSD per descriptor package is supported
+# Update the <update> tag with correct values
+# Update or remove <update, optional> tags
+nsd:nsd-catalog:
+ nsd:
+ - id: ${name}
+ name: ${name}
+ short-name: ${name}
+ description: ${name}
+
+ # Place the logo as png in icons directory and provide the name here
+ logo: <update, optional>
+
+ # Specify the VNFDs that are part of this NSD
+ constituent-vnfd:
+ # The member-vnf-index needs to be unique, starting from 1
+ # vnfd-id-ref is the id of the VNFD
+ # Multiple constituent VNFDs can be specified
+ - member-vnf-index: <update>
+ vnfd-id-ref: <update>
+
+ vld:
+ # Management network for the VNFs
+ - id: management
+ name: management
+ provider-network:
+ overlay-type: VLAN
+ physical-network: <update>
+ type: ELAN
+ vnfd-connection-point-ref:
+ # Specify all the constituent VNFs
+ # member-vnf-index-ref - entry from constituent vnf
+ # vnfd-id-ref - VNFD id
+ # vnfd-connection-point-ref - connection point name in the VNFD
+ - member-vnf-index-ref: '1'
+ vnfd-connection-point-ref: <update>
+ vnfd-id-ref: <update>
+ - member-vnf-index-ref: '2'
+ vnfd-connection-point-ref: <update>
+ vnfd-id-ref: <update>
+
+ # Addtional netowrk can be specified for data, etc
+ - id: <update>
+ name: <update>
+ type: ELAN
+ provider-network:
+ overlay-type: VLAN
+ physical-network: <update>
+ vnfd-connection-point-ref:
+ - member-vnf-index-ref: <update>
+ vnfd-connection-point-ref: <update>
+ vnfd-id-ref: <update>
+
+ # NS level configuration primitive
+ # This section is optional
+ config-primitive:
+ - name: <update>
+ # List of parameters, optional
+ parameter:
+ - name: <update>
+ data-type: string
+ default-value: <update>
+ mandatory: <true|false>
+
+ # List of parameters grouped by name
+ # optional section
+ parameter-group:
+ - mandatory: <true|false>
+ name: <update>
+ parameter:
+ - name: <update>
+ data-type: integer
+ default-value: <update>
+ hidden: <true|false>
+ mandatory: <true|false>
+
+ # Script based NS level configuration
+ user-defined-script: <update>
+EOF
+
+ if [ $VERBOSE == true ]; then
+ echo "INFO: Created $desc_file"
+ fi
+}
+
+function write_nsd_config_tmpl() {
+ name=$(basename $1)
+ cfg_file="ns_config/$name.yaml"
+
+ cat >$cfg_file <<EOF
+
+EOF
+
+ if [ $VERBOSE == true ]; then
+ echo "INFO: Created $cfg_file"
+ fi
+}
+
+OPTS=`getopt -o vhnt:d:cN --long verbose,dry-run,help,package-type:,destination-dir,create-folder,no-remove-files,debug -n $SCRIPTNAME -- "$@"`
-# Usage: generate_descriptor_pkg.sh <package-directory> <dest_package_dir>
+if [ $? != 0 ] ; then
+ echo "ERROR: Failed parsing options ($?)." >&2
+ usage
+ exit 1
+fi
-mkdir -p $1
-mkdir -p $2
+echo "$OPTS"
+eval set -- "$OPTS"
-dest_dir=$(cd $1 && pwd)
-pkg_dir=$(cd $2 && pwd)
+cur_dir=`pwd`
-echo $(pwd)
-cd ${pkg_dir}
-rm -rf checksums.txt
-find * -type f |
- while read file; do
- md5sum $file >> checksums.txt
+# Check if the array contains a specific value
+# Taken from
+# http://stackoverflow.com/questions/3685970/check-if-an-array-contains-a-value
+function contains() {
+ local n=$#
+ local value=${!n}
+ for ((i=1;i < $#;i++)); do
+ if [ "${!i}" == "${value}" ]; then
+ echo "y"
+ return 0
+ fi
done
-cd ..
-tar -zcvf ${dest_dir}/$(basename $pkg_dir).tar.gz $(basename $pkg_dir)
+ echo "n"
+ return 1
+}
+
+function check_type() {
+ type=$1
+ if [ $(contains "${DESC_TYPES[@]}" $type) == "y" ]; then
+ TYPE=$type
+ else
+ echo "ERROR: Unknown descriptor type $type!" >&2
+ exit 1
+ fi
+}
+
+function get_expr(){
+ # First argument is to specify if this is a negative match or match
+ # Rest are filename expressions without extension
+ #
+
+ local regex=" "
+ local n=$1
+ local neg="${1}"
+ for ((i=2;i <= $#;i++)); do
+ if [ $i -eq 2 ]; then
+ if [ $neg == true ]; then
+ subexpr='! -name'
+ else
+ subexpr='-name'
+ fi
+ else
+ if [ $neg == true ]; then
+ subexpr=' -a ! -name'
+ else
+ subexpr=' -o -name'
+ fi
+ fi
+
+ for extn in ${DESC_EXTN[$@]}; do
+ regex="$regex $subexpr ${!i}.$extn"
+ done
+ done
+
+ if [ $VERBOSE == true ]; then
+ echo "INFO: Generate expression: $expr"
+ fi
+
+ echo "$expr"
+}
+
+function get_expr(){
+ # First argument is to specify if this is a negative match or not
+ # Rest are filename expressions without extension
+
+ local regex=" "
+ local n=$#
+ local neg="${1}"
+ local first="true"
+ for ((i=2;i <= $#;i++)); do
+ for extn in "${DESC_EXTN[@]}"; do
+ if [ $first == true ]; then
+ if [ $neg == true ]; then
+ subexpr='! -name'
+ else
+ subexpr='-name'
+ fi
+ first=false
+ else
+ if [ $neg == true ]; then
+ subexpr=' -a ! -name'
+ else
+ subexpr=' -o -name'
+ fi
+ fi
+
+ regex="$regex $subexpr ${!i}.$extn"
+ done
+ done
+
+ echo "$regex"
+}
+
+while true; do
+ case "$1" in
+ -v | --verbose ) VERBOSE=true; shift ;;
+ -h | --help ) usage; exit 0; shift ;;
+ -n | --dry-run ) DRY_RUN=true; shift ;;
+ -t | --package-type ) check_type "$2"; shift; shift ;;
+ -d | --destination-dir ) DEST_DIR=$2; shift; shift;;
+ -c | --create-folder ) CREATE=true; shift;;
+ -N | --no-remove-files ) RM=''; shift;;
+ --debug ) DEBUG=true; shift;;
+ -- ) shift; break ;;
+ * ) break ;;
+ esac
+done
+
+if [ $DEBUG == true ]; then
+ echo "INFO: Debugging ON"
+ set -x
+fi
+
+if [ $VERBOSE == true ]; then
+ echo "INFO: Descriptor type: $TYPE"
+fi
+
+# Dry run is to validate existing descriptor folders
+if [ $DRY_RUN == true ] && [ $CREATE == true ]; then
+ echo "ERROR: Option dry-run with create-folders not supported!" >&2
+ exit 1
+fi
+
+if [ $# -gt 1 ]; then
+ BASE_DIR=$1
+ PKG=$(basename $2)
+else
+ BASE_DIR=$(dirname $1)
+ PKG=$(basename $1)
+fi
+
+if [ $VERBOSE == true ]; then
+ echo "INFO: Using base dir: $BASE_DIR"
+fi
+
+if [ $VERBOSE == true ]; then
+ echo "INFO: Using package: $PKG"
+fi
+
+if [ -z "$PKG" ]; then
+ echo "ERROR: Need to specify the package-dir" >&2
+ usage >&2
+ exit 1
+fi
+
+cd $BASE_DIR
+if [ $? -ne 0 ]; then
+ echo "ERROR: Unable to change to base directory $BASE_DIR!" >&2
+ exit 1
+fi
+
+# Get full base dir path
+BASE_DIR=`pwd`
+cd $cur_dir
+
+if [ -z $DEST_DIR ]; then
+ DEST_DIR=$BASE_DIR # Default to base directory
+fi
+
+mkdir -p $DEST_DIR
+
+cd $DEST_DIR
+if [ $? -ne 0 ]; then
+ echo "ERROR: Not able to access destination directory $DEST_DIR!" >&2
+ exit 1
+fi
+
+# Get the full destination dir path
+DEST_DIR=`pwd`
+cd $cur_dir
+
+dir=${BASE_DIR}/${PKG}
+
+function add_chksum() {
+ if [ $VERBOSE == true ]; then
+ echo "INFO: Add file $1 to $CHKSUM"
+ fi
+
+ md5sum $1 >> $CHKSUM
+}
+
+if [ $CREATE == false ]; then
+ if [ ! -d $dir ]; then
+ echo "INFO: Package folder $dir not found!" >&2
+ exit 1
+ fi
+
+ cd $dir
+ if [ $? -ne 0 ]; then
+ rc=$?
+ echo "ERROR: changing directory to $dir ($rc)" >&2
+ exit $rc
+ fi
+
+ # Remove checksum file, if present
+ rm -f $CHKSUM
+
+ # Check if the descriptor file is present
+ if [ -z $TYPE ]; then
+ # Desc type not specified, look for the desc file and guess the type
+ # Required for backward compatibility
+ for ty in ${DESC_TYPES[@]}; do
+ re=$(get_expr false "$ty" "*_$ty" "*_${ty}_*")
+ desc=$(find * -maxdepth 0 -type f $re 2>/dev/null)
+
+ if [ -z $desc ] || [ ${#desc[@]} -eq 0 ]; then
+ # Check the vnfd|nsd folder
+ if [ ! -d $ty ]; then
+ continue
+ fi
+ re=$(get_expr false "*")
+ desc=$(find $ty/* -maxdepth 0 -type f $re 2>/dev/null)
+ if [ -z $desc ] || [ ${#desc[@]} -eq 0 ]; then
+ continue
+ elif [ ${#desc[@]} -gt 1 ]; then
+ echo "ERROR: Found multiple descriptor files: ${desc[@]}" >&2
+ exit 1
+ fi
+ # Descriptor sub directory
+ desc_sub_dir=$ty
+ fi
+
+ TYPE=$ty
+ if [ $TYPE == 'nsd' ]; then
+ folders=("${NSD_FOLDERS[@]}")
+ else
+ folders=("${VNFD_FOLDERS[@]}")
+ fi
+
+ if [ $VERBOSE == true ]; then
+ echo "INFO: Determined descriptor is of type $TYPE"
+ fi
+ break
+ done
+
+ if [ -z $TYPE ]; then
+ echo "ERROR: Unable to determine the descriptor type!" >&2
+ exit 1
+ fi
+ else
+ if [ $TYPE == 'nsd' ]; then
+ folders=("${NSD_FOLDERS[@]}")
+ else
+ folders=("${VNFD_FOLDERS[@]}")
+ fi
+
+ # Check for descriptor of type provided on command line
+ re=$(get_expr false "$TYPE" "*_${TYPE}" "*_${TYPE}_*")
+ desc=$(find * -maxdepth 0 -type f $re 2>/dev/null)
+
+ if [ -z $desc ] || [ ${#desc[@]} -eq 0 ]; then
+ # Check if it is under vnfd/nsd subdirectory
+ # Backward compatibility support
+ re=$(get_expr false "*")
+ desc=$(find $TYPE/* -maxdepth 0 -type f $re 2>/dev/null)
+ if [ -z $desc ] || [ ${#desc[@]} -eq 0 ]; then
+ echo "ERROR: Did not find descriptor file of type $TYPE" \
+ " in $dir" >&2
+ exit 1
+ fi
+ desc_sub_dir=$ty
+ fi
+ fi
+
+ if [ ${#desc[@]} -gt 1 ]; then
+ echo "ERROR: Found multiple files of type $TYPE in $dir: $desc" >&2
+ exit 1
+ fi
+
+ descriptor=${desc[0]}
+
+ # Check if there are files not supported
+ files=$(find * -maxdepth 0 -type f ! -name $descriptor 2>/dev/null)
+
+ for f in ${files[@]}; do
+ if [ $(contains "${ALLOWED_FILES[@]}" $f) == "n" ]; then
+ echo "WARN: Unsupported file $f found"
+ fi
+ done
+
+ if [ $VERBOSE == true ]; then
+ echo "INFO: Found descriptor package: ${desc_sub_dir} ${descriptor}"
+ fi
+
+ if [ $DRY_RUN == false ]; then
+ add_chksum ${descriptor}
+ fi
+
+ # Check the folders are supported ones
+ dirs=$( find * -maxdepth 0 -type d )
+
+ for d in ${dirs[@]}; do
+ if [ $(contains "${folders[@]}" $d) == "y" ]; then
+ if [ $DRY_RUN == false ]; then
+ find $d/* -type f 2>/dev/null|
+ while read file; do
+ add_chksum $file
+ done
+ fi
+ elif [ -z $desc_sub_dir ] || [ $d != $desc_sub_dir ]; then
+ echo "WARN: $d is not part of standard folders " \
+ "for descriptor type $TYPE in $PKG"
+ fi
+ done
+
+ if [ $VERBOSE == true ]; then
+ echo "INFO: Creating archive for $PKG"
+ fi
+
+ cd $BASE_DIR
+ if [ $DRY_RUN == false ]; then
+ tar zcvf "$DEST_DIR/$PKG.tar.gz" "${PKG}" ${RM}
+ if [ $? -ne 0 ]; then
+ rc=$?
+ echo "ERROR: creating archive for $PKG ($rc)" >&2
+ exit $rc
+ fi
+ fi
+else
+ # Create the folders for the descriptor
+ if [ $VERBOSE == true ]; then
+ echo "INFO: Creating folders for $PKG in $dir"
+ fi
+
+ # Create, default to VNFD if no type is defined
+ if [ -z $TYPE ]; then
+ TYPE=vnfd
+ echo "WARNING: Defaulting to descriptor type $TYPE"
+ fi
+
+ mkdir -p $dir && cd $dir
+ if [ $? -ne 0 ]; then
+ rc=$?
+ echo "ERROR: creating directory $dir ($rc)" >&2
+ exit $rc
+ fi
+
+ if [ $TYPE == 'nsd' ]; then
+ folders=("${NSD_FOLDERS[@]}")
+ else
+ folders=("${VNFD_FOLDERS[@]}")
+ fi
+
+ for d in ${folders[@]}; do
+ mkdir -p $dir/$d
+ if [ $? -ne 0 ]; then
+ rc=$?
+ echo "ERROR: creating directory $dir/$d ($rc)" >&2
+ exit $rc
+ fi
+ if [ $VERBOSE == true ]; then
+ echo "Created folder $d in $dir"
+ fi
+ done
+
+ if [ $VERBOSE == true ]; then
+ echo "INFO: Created folders for in $dir"
+ fi
+
+ # Write a descriptor template file
+ if [ $TYPE == 'vnfd' ]; then
+ write_vnfd_tmpl $dir
+ else
+ write_nsd_tmpl $dir
+ # write_nsd_config_tmpl $dir
+ fi
+
+fi
+
+cd $cur_dir