summaryrefslogtreecommitdiffstats
path: root/build/package.sh
blob: a3c1ded26f2b5276957a67a56ec537afb5a1abaf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#! /usr/bin/env bash

#   COPYRIGHT NOTICE STARTS HERE
#
#   Copyright 2018-2019 © Samsung Electronics Co., Ltd.
#
#   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.
#
#   COPYRIGHT NOTICE ENDS HERE


# Scope of this packaging script is to generate tarfiles for offline installation
# Build of any additional artifacts is out of scope for this script
set -e

crash () {
    local exit_code="$1"
    local cause="$2"
    echo "Packaging script finished prematurely"
    echo "Cause: $2"
    exit "${exit_code}"
}

crash_arguments () {
    echo "Missing some mandatory arguments!"
    usage
    exit 1
}

usage () {
    echo "Usage:"
    echo "   ./$(basename $0) <project_name> <version> <packaging_target_dir> [--conf <file>] [--force]"
    echo ""
    echo "Options:"
    echo "   --force Remove packaging_target_dir if exists prior to script execution"
    echo "   --conf  Custom configuration file path for script"
    echo ""
    echo "Example:"
    echo "   ./$(basename $0) myproject 1.0.1 /tmp/package --conf ~/myproject.conf"
    echo ""
    echo "packaging_target_dir will be created if does not exist. All tars will be produced into it."
}

function create_tar {
    local tar_dir="$1"
    local tar_name="$2"

    cd ${tar_dir}
    touch ${tar_name} # Trick to avoid sporadic "tar: .: file changed as we read it" warning message
    tar --exclude=${tar_name} -cf ../${tar_name} .
    cd - &> /dev/null # Trick to avoid printing new dir on stdout

    # Remove packaged folders
    find ${tar_dir}/* -maxdepth 0 -type d -exec rm -rf '{}' \;
    # Remove packaged files
    find ${tar_dir}/* ! -name ${tar_name} -exec rm '{}' \;
    echo "Tar file created to $(dirname ${tar_dir})/${tar_name}"
}

function create_pkg {
    local pkg_type="$1"
    echo "[Creating ${pkg_type} package]"
    create_tar "${PKG_ROOT}" offline-${PROJECT_NAME}-${PROJECT_VERSION}-${pkg_type}.tar
    rm -rf "${PKG_ROOT}"
}

function add_metadata {
    local metafile="$1"
    echo "Project name: ${PROJECT_NAME}" >> "${metafile}"
    echo "Project version: ${PROJECT_VERSION}" >> "${metafile}"
    echo "Package date: ${TIMESTAMP}" >> "${metafile}"
}

function add_additions {
    local source="$1"
    local target="$2"
    if [ -d "${source}" ]; then
        mkdir -p "${target}/$(basename $source)"
        cp -r "${source}" "${target}"
        echo "Adding directory  ... $(basename $source)"
    else
        if [ -f "${source}" ]; then
             cp "${source}" "${target}"
             echo "Adding file       ... $(basename $source)"
        else
             crash 4 "Invalid source specified for packaging: $1"
        fi
    fi
}

function build_sw_artifacts {
    cd ${LOCAL_PATH}/../ansible/docker
    ./build_ansible_image.sh
    if [ $? -ne 0 ]; then
        crash 5 "Building of ansible runner image failed."
    fi
    cd -
}

function create_sw_package {
    PKG_ROOT="${PACKAGING_TARGET_DIR}/sw"

    # Create directory structure of the sw package
    mkdir -p "${PKG_ROOT}"
    cp -r ${LOCAL_PATH}/../ansible "${PKG_ROOT}"

    # Add application additional files/dirs into package based on package.conf
    for item in "${APP_CONFIGURATION[@]}";do
        # all SW package addons are expected within ./ansible/application folder
        add_additions "${item}" "${PKG_ROOT}/${APPLICATION_FILES_IN_PACKAGE}"
    done

    # Application Helm charts
    # To be consistent with resources and aux dir, create charts dir even if no charts provided.
    mkdir -p ${PKG_ROOT}/${HELM_CHARTS_DIR_IN_PACKAGE}
    if [ ! -z "${HELM_CHARTS_DIR}" ];
    then
        echo "Add application Helm charts"
        # Copy charts available for ansible playbook to use/move them to target server/dir
        cp -r "${HELM_CHARTS_DIR}"/* ${PKG_ROOT}/${HELM_CHARTS_DIR_IN_PACKAGE}
    else
        echo "No Helm charts defined, no application will be automatically installed by this package!"
    fi

    # Add metadata to the package
    add_metadata "${PKG_ROOT}"/package.info

    # Create sw tar package
    create_pkg sw
}

function create_resource_package {
    PKG_ROOT="${PACKAGING_TARGET_DIR}/resources"

    # Create directory structure of the resource package
    mkdir -p "${PKG_ROOT}"

    # Add artifacts into resource package based on package.conf config
    if [ ! -z ${APP_BINARY_RESOURCES_DIR} ]; then
        cp -r ${APP_BINARY_RESOURCES_DIR}/* ${PKG_ROOT}
    fi

    # tar file with nexus_data is expected, we should find and untar it
    # before resource.tar is created
    for i in `ls -1 ${PKG_ROOT} | grep tar`; do
        tar tvf "${PKG_ROOT}/${i}" | grep nexus_data &> /dev/null
        if [ $? -eq 0 ]; then
            echo "Debug: tar file with nexus blobs detected ${PKG_ROOT}/${i}. Start unarchive ..."
            tar xf "${PKG_ROOT}/${i}" -C "${PKG_ROOT}" &> /dev/null
            echo "Debug: unarchive finished. Removing original file"
            rm -f "${PKG_ROOT}/${i}"
        fi
    done

    create_pkg resources
}

function create_aux_package {
    PKG_ROOT="${PACKAGING_TARGET_DIR}/aux"

    # Create directory structure of the aux resource package
    mkdir -p "${PKG_ROOT}"

    # Add artifacts into resource packagee based on package.conf config
    for item in "${APP_AUX_BINARIES[@]}";do
        add_additions "${item}" "${PKG_ROOT}"
    done

    create_pkg aux-resources
}

#
# =================== Main ===================
#

PROJECT_NAME="$1"
PROJECT_VERSION="$2"
PACKAGING_TARGET_DIR="$3"

TIMESTAMP=$(date -u +%Y%m%dT%H%M%S)
SCRIPT_DIR=$(dirname "${0}")
LOCAL_PATH=$(readlink -f "$SCRIPT_DIR")

# Relative location inside the package for application related files.
# Application means Kubernetes application installed by Helm charts on ready cluster (e.g. onap).
APPLICATION_FILES_IN_PACKAGE="ansible/application"

# Relative location inside the package to place Helm charts to be available for
# Ansible process to transfer them into machine (infra node) running Helm repository.
# NOTE: This is quite hardcoded place to put them and agreement with Ansible code
# is done in ansible/group_vars/all.yml with variable "app_helm_charts_install_directory"
# whihc value must match to value of this variable (with exception of slash '/'
# prepended so that ansible docker/chroot process can see the dir).
# This variable can be of course changed in package.conf if really needed if
# corresponding ansible variable "app_helm_charts_install_directory" value
# adjusted accordingly.
HELM_CHARTS_DIR_IN_PACKAGE="${APPLICATION_FILES_IN_PACKAGE}/helm_charts"

if [ $# -eq 0 ]; then
    crash_arguments
fi

CONF_FILE=""
FORCE_REMOVE=0
arg_ind=0
for arg in "$@"; do
  shift
  ((arg_ind+=1))
  if [[ ${arg} =~ ^[-]{1,2}[a-zA-Z-]+$ && ${arg_ind} -lt 4 ]]; then
      echo "Non-positional parameters should follow mandatory arguments!"
      usage
      exit 1
  fi
  case "$arg" in
    -c|--conf)
        CONF_FILE="$1" ;;
    --force)
        FORCE_REMOVE=1 ;;
    *)
        set -- "$@" "$arg"
        if [ "$#" -lt 3 ]; then
	    crash_arguments
        fi ;;
  esac
done

if [ -z ${CONF_FILE} ]; then
    CONF_FILE=${LOCAL_PATH}/package.conf # Fall to default conf file
fi

if [ ! -f ${CONF_FILE} ]; then
    crash 2 "Mandatory config file missing! Provide it with --conf option or ${LOCAL_PATH}/package.conf"
fi

source ${CONF_FILE}
pushd ${LOCAL_PATH}

# checking bash capability of parsing arrays
whotest[0]='test' || (crash 3 "Arrays not supported in this version of bash.")

# Prepare output directory for our packaging
# Check target dir exists and is not empty
if [ -d ${PACKAGING_TARGET_DIR} ] && [ "$(ls -A ${PACKAGING_TARGET_DIR})" ]; then
    if [ ${FORCE_REMOVE} -eq 0 ]; then
        crash 1 "Target directory not empty. Use --force to overwrite it."
    else
        rm -rf ${PACKAGING_TARGET_DIR}
    fi
fi

# Create all tars
build_sw_artifacts
create_sw_package
create_resource_package
create_aux_package

popd