-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathnew.sh
396 lines (339 loc) · 14.9 KB
/
new.sh
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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
#!/usr/bin/env bash
# Copyright (c) 2014-2019, Erik Dannenberg <[email protected]>
# All rights reserved.
readonly _KUBLER_HISTORY_NS_TYPE="${KUBLER_DATA_DIR}"/.ask_history_ns_type
readonly _KUBLER_HISTORY_NS_DIR="${KUBLER_DATA_DIR}"/.ask_history_ns_dir
readonly _KUBLER_HISTORY_IMAGE_TAG="${KUBLER_DATA_DIR}"/.ask_history_image_tag
readonly _KUBLER_HISTORY_BUILDER_IMAGE="${KUBLER_DATA_DIR}"/.ask_history_builder_image
readonly _KUBLER_HISTORY_PARENT_IMAGE="${KUBLER_DATA_DIR}"/.ask_history_parent_image
readonly _KUBLER_HISTORY_AUTHOR="${KUBLER_DATA_DIR}"/.ask_history_author
readonly _KUBLER_HISTORY_EMAIL="${KUBLER_DATA_DIR}"/.ask_history_email
readonly _KUBLER_HISTORY_ENGINE="${KUBLER_DATA_DIR}"/.ask_history_engine
readonly _KUBLER_HISTORY_TEST_TEMPLATE="${KUBLER_DATA_DIR}"/.ask_history_test_template
# Adds given var_name and it's replacement to global assoc. array _template_values
#
# Arguments:
# 1: var_name
# 2: replacement
function add_template_filter_var() {
local var_name replacement
var_name="$1"
replacement="$2"
_template_values["${var_name}"]="${replacement}"
}
# Adds given match and replacement to global assoc. array _template_sed_args.
#
# Arguments:
# 1: match
# 2: replacement
function add_template_sed_replace() {
local match replacement
match="$1"
replacement="$2"
_template_sed_args+=('-e' "s|${match}|${replacement}|g")
}
# Replace all keys of global assoc. array _template_values with theirs respective values for each file in given
# target_dir(s)
#
# Arguments:
# n: target_dir
function replace_template_placeholders() {
local target_dirs var_name tmpl_file
IFS=" " read -r -a target_dirs <<< "$@"
for var_name in "${!_template_values[@]}"; do
add_template_sed_replace "\${${var_name}}" "${_template_values[$var_name]}"
done
for tmpl_file in "${target_dirs[@]}"/*; do
[[ -f "${tmpl_file}" ]] && replace_in_file "${tmpl_file}" _template_sed_args[@]
done
}
# Arguments:
# 1: ns_name
function add_namespace() {
local ns_name ns_dir ns_type ns_engine regex kubler_bin_hint real_ns_dir default_conf
ns_name="$1"
[[ "${ns_name}" == 'kubler' ]] && die "\"kubler\" is a reserved namespace, aborting."
ns_dir="${_NAMESPACE_DIR}/${ns_name}"
real_ns_dir="${ns_dir}"
get_absolute_path "${ns_dir}"
# shellcheck disable=SC2154
ns_dir="${__get_absolute_path}"
[[ -e "${ns_dir}" ]] && die "${ns_dir} already exists, aborting."
[[ "${_NAMESPACE_TYPE}" == 'single' ]] && die "${_NAMESPACE_DIR} namespace is of type single, aborting."
local def_author def_mail def_engine
def_author='John Doe'
def_mail='[email protected]'
def_engine='docker'
# use author and engine from kubler.conf/env as defaults if avail.
regex='(.+)\s<(.+)>'
[[ "${AUTHOR}" =~ $regex ]] && def_author="${BASH_REMATCH[1]}" && def_mail="${BASH_REMATCH[2]}"
[[ -n "${BUILD_ENGINE}" ]] && def_engine="${BUILD_ENGINE}"
msg_info_sub
msg_info_sub '<enter> to accept default value'
msg_info_sub
if [[ "${_NAMESPACE_TYPE}" == 'none' ]]; then
msg_info_sub "Working dir type? Choices:"
msg_info_sub " single - You can't add further namespaces to the created working dir, it only holds images"
msg_info_sub " multi - Creates a working dir that can hold multiple namespaces"
ask 'Type' 'single' "${_KUBLER_HISTORY_NS_TYPE}"
# shellcheck disable=SC2154
ns_type="${__ask}"
add_template_filter_var '_tmpl_ns_type' "${ns_type}"
[[ "${ns_type}" != 'single' && "${ns_type}" != 'multi' ]] && die "Unknown type: \"${ns_type}\""
if [[ "${_NAMESPACE_TYPE}" == 'none' && "${ns_type}" == 'multi' ]]; then
msg_info_sub
msg_info_sub "Top level directory name for new namespace '${ns_name}'? The directory is created at ${_NAMESPACE_DIR}/"
ask 'Namespaces Dir' 'kubler-images' "${_KUBLER_HISTORY_NS_DIR}"
ns_dir="${_NAMESPACE_DIR}/${__ask}"
[[ -e "${ns_dir}" ]] && die "Directory ${ns_dir} already exists, aborting. If you intended to create the new namespace at this location use: \\n
${_KUBLER_BIN} --working-dir=${ns_dir} new namespace ${ns_name}"
real_ns_dir="${ns_dir}/${ns_name}"
fi
msg_info_sub
msg_info "Initial image tag, a.k.a. version?"
ask 'Image Tag' "${_TODAY}" "${_KUBLER_HISTORY_IMAGE_TAG}"
add_template_filter_var '_tmpl_image_tag' "${__ask}"
add_template_sed_replace '^IMAGE_TAG' '#IMAGE_TAG'
msg_info_sub
else
msg_info_sub
msg_warn "Namespace Type: ${_NAMESPACE_TYPE}"
fi
msg_warn "New namespace location: ${real_ns_dir}"
msg_info_sub
msg_info 'Who maintains the new namespace?'
ask 'Name' "${def_author}" "${_KUBLER_HISTORY_AUTHOR}"
add_template_filter_var '_tmpl_author' "${__ask}"
ask 'EMail' "${def_mail}" "${_KUBLER_HISTORY_EMAIL}"
add_template_filter_var '_tmpl_author_email' "${__ask}"
msg_info_sub
msg_info 'Default build engine?'
ask 'Engine' "${def_engine}" "${_KUBLER_HISTORY_ENGINE}"
ns_engine="${__ask}"
add_template_filter_var '_tmpl_engine' "${ns_engine}"
[[ ! -f "${_KUBLER_DIR}/engine/${ns_engine}.sh" ]] && die "Unknown engine: ${ns_engine}"
[[ "${_NAMESPACE_TYPE}" == 'none' && "${ns_type}" == 'multi' ]] && mkdir "${ns_dir}"
cp -r "${_KUBLER_DIR}/template/${ns_engine}/namespace" "${real_ns_dir}" || die
kubler_bin_hint="${_KUBLER_BIN}${_KUBLER_BIN_HINT}"
if [[ "${_NAMESPACE_TYPE}" == 'none' ]]; then
if [[ "${ns_type}" == 'multi' ]]; then
mv "${real_ns_dir}/${_KUBLER_CONF}.single" "${real_ns_dir}/${_KUBLER_CONF}"
else
rm "${real_ns_dir}/${_KUBLER_CONF}.single"
fi
# default multi conf file can also be used for new single namespaces..
default_conf='multi'
if [[ -z "${_KUBLER_BIN_HINT}" ]];then
kubler_bin_hint="cd ${ns_dir}\\n $ ${kubler_bin_hint}"
else
kubler_bin_hint="${_KUBLER_BIN} --working-dir ${ns_dir}"
fi
else
# ..else use default single conf file when inside an existing namespace
default_conf='single'
rm "${ns_dir}/${_KUBLER_CONF}.multi"
fi
mkdir "${real_ns_dir}"/"${_IMAGE_PATH}"
mv "${real_ns_dir}/${_KUBLER_CONF}.${default_conf}" "${ns_dir}/${_KUBLER_CONF}"
replace_template_placeholders "${ns_dir}"
[[ "${_NAMESPACE_TYPE}" == 'none' && "${ns_type}" == 'multi' ]] && \
replace_template_placeholders "${real_ns_dir}"
msg_info_sub
msg_ok "Successfully created \"${ns_name}\" namespace at ${ns_dir}"
msg_info_sub
msg_warn "Configuration file: ${real_ns_dir}/${_KUBLER_CONF}"
msg_info_sub
msg_warn "To manage the new namespace with GIT you may want to run:"
msg_info_sub
msg_info_sub "$ git init ${real_ns_dir}"
msg_info_sub
msg_warn "To create images in the new namespace run:"
msg_info_sub
msg_info_sub "$ ${kubler_bin_hint} new image ${ns_name}/<image_name>"
}
# Create empty dir for given image and return the absolute path
#
# Arguments:
# 1: namespace
# 2: image_name
# 3: image_type
# Return value: absolute path of created image dir
function init_image_base_dir() {
__init_image_base_dir=
local namespace image_name image_type image_base_path image_path
namespace="$1"
image_name="$2"
image_type="$3"
image_base_path="${_NAMESPACE_DIR}/"
[[ "${_NAMESPACE_TYPE}" != 'single' ]] && image_base_path+="${namespace}/"
image_base_path+="${image_type}"
# not really required, just for the nicer output as // etc are removed
get_absolute_path "${image_base_path}"
image_base_path="${__get_absolute_path}"
image_path="${image_base_path}/${image_name}"
[ -e "${image_path}" ] && die "${image_path} already exists, aborting!"
[ ! -d "${image_base_path}" ] && mkdir -p "${image_base_path}"
__init_image_base_dir="${image_path}"
}
# Arguments
# 1: namespace
# 2: image_name
function add_image() {
local namespace image_name image_parent image_builder image_path test_type
namespace="$1"
image_name="$2"
msg_info_sub
msg_info_sub '<enter> to accept default value'
msg_info_sub
msg_info_sub 'Extend an existing Kubler managed image? Fully qualified image id (i.e. kubler/busybox) or scratch'
ask 'Parent Image' 'scratch' "${_KUBLER_HISTORY_PARENT_IMAGE}"
image_parent="${__ask}"
image_builder="${DEFAULT_BUILDER}"
if [[ "${image_parent}" == 'scratch' ]]; then
msg_info_sub
msg_info_sub "Which builder should be used? Press <enter> to use the default builder of namespace ${namespace}"
ask 'Builder Id' "${DEFAULT_BUILDER}" "${_KUBLER_HISTORY_BUILDER_IMAGE}"
image_builder="${__ask}"
[[ "${target_id}" != *"/"* ]] && die "${target_id} should have format <namespace>/<builder_name>"
[[ "${image_builder}" != "${DEFAULT_BUILDER}" ]] && add_template_sed_replace '^#BUILDER=' 'BUILDER='
elif [[ "${image_parent}" != *"/"* || "${image_parent}" == *"/" ]]; then
die "\"${image_parent}\" should have format <namespace>/<image_name>"
fi
if [[ "${BUILD_ENGINE}" == 'docker' ]]; then
msg_info_sub
msg_info_sub 'Add test template(s)? Possible choices:'
msg_info_sub " hc - Add a stub for Docker's HEALTH-CHECK, recommended for images that run daemons"
msg_info_sub ' bt - Add a stub for a custom build-test.sh script, a good choice if HEALTH-CHECK is not suitable'
msg_info_sub ' yes - Add stubs for both test types'
msg_info_sub " no - Fck it, we'll do it live!"
ask 'Tests' 'hc' "${_KUBLER_HISTORY_TEST_TEMPLATE}"
test_type="${__ask}"
[[ "${test_type}" != 'hc' && "${test_type}" != 'bt' && "${test_type}" != 'yes' && "${test_type}" != 'no' ]] \
&& die "'${test_type}' is not a valid choice."
if [[ "${test_type}" == 'bt' || "${test_type}" == 'no' ]]; then
add_template_sed_replace '^HEALTHCHECK ' '#HEALTHCHECK '
add_template_sed_replace '^COPY docker-health' '#COPY docker-health'
add_template_sed_replace '^POST_BUILD_HC=' '#POST_BUILD_HC='
fi
fi
init_image_base_dir "${namespace}" "${image_name}" "${_IMAGE_PATH}"
image_path="${__init_image_base_dir}"
cp -r "${_KUBLER_DIR}/template/${BUILD_ENGINE}/image" "${image_path}" || die
add_template_filter_var '_tmpl_image_parent' "${image_parent}"
add_template_filter_var '_tmpl_image_builder' "${image_builder}"
replace_template_placeholders "${image_path}"
local hc_test_file bt_test_file
hc_test_file="${image_path}"/docker-healthcheck.sh
bt_test_file="${image_path}"/build-test.sh
case "${test_type}" in
hc)
rm "${bt_test_file}"
chmod +x "${hc_test_file}"
;;
bt)
rm "${hc_test_file}"
chmod +x "${bt_test_file}"
;;
no)
rm "${hc_test_file}" "${bt_test_file}"
;;
yes)
chmod +x "${hc_test_file}" "${bt_test_file}"
;;
esac
msg_info_sub
msg_ok "Successfully created new image at ${image_path}"
msg_info_sub
}
# Arguments
# 1: namespace
# 2: builder_name
function add_builder() {
local namespace builder_name builder_parent builder_path is_stage3_builder
namespace="$1"
builder_name="$2"
msg_info_sub
msg_info_sub '<enter> to accept default value'
msg_info_sub
msg_info_sub 'Extend existing Kubler builder image? Fully qualified image id (i.e. kubler/bob) or stage3'
ask 'Parent Image' 'stage3' "${_KUBLER_HISTORY_BUILDER_IMAGE}"
builder_parent="${__ask}"
# shellcheck disable=SC2016,SC2034
if [[ "${builder_parent}" == "stage3" ]]; then
builder_parent='\${NAMESPACE}/bob'
add_template_sed_replace '^BUILDER' '#BUILDER'
is_stage3_builder='true'
else
[[ "${builder_parent}" != *"/"* || "${builder_parent}" == *"/" ]] \
&& die "\"${builder_parent}\" should have format <namespace>/<image_name>"
add_template_sed_replace '^STAGE3' '#STAGE3'
fi
init_image_base_dir "${namespace}" "${builder_name}" "${_BUILDER_PATH}"
builder_path="${__init_image_base_dir}"
cp -r "${_KUBLER_DIR}/template/${BUILD_ENGINE}/builder" "${builder_path}" || die
local build_sh_use build_sh_rm
build_sh_use='build_ext.sh'
build_sh_rm='build_stage3.sh'
if [[ "${is_stage3_builder}" == 'true' ]]; then
build_sh_use='build_stage3.sh'
build_sh_rm='build_ext.sh'
fi
[[ -f "${builder_path}"/"${build_sh_use}" ]] && mv "${builder_path}"/"${build_sh_use}" "${builder_path}"/build.sh
[[ -f "${builder_path}"/"${build_sh_rm}" ]] && rm "${builder_path}"/"${build_sh_rm}"
add_template_filter_var '_tmpl_builder' "${builder_parent}"
replace_template_placeholders "${builder_path}"
msg_info_sub
msg_ok "Successfully created new builder at ${builder_path}"
msg_info_sub
if [[ -n "${is_stage3_builder}" ]]; then
msg_warn "Configure the STAGE3_BASE in ${builder_path}/build.conf then run:"
msg_info_sub
msg_info_sub "$ ${_KUBLER_BIN}${_KUBLER_BIN_HINT} update"
msg_info_sub
fi
}
function main() {
local target_id target_namespace target_image_name
declare -A _template_values
_template_sed_args=()
# shellcheck disable=SC2154
target_id="${_arg_name}"
# shellcheck disable=SC2154
[[ "${target_id}" != *"/"* && "${_arg_template_type}" != 'namespace' && -n "${_NAMESPACE_DEFAULT}" ]] \
&& target_id="${_NAMESPACE_DEFAULT}/${_arg_name}"
target_namespace="${target_id%%/*}"
target_image_name="${target_id##*/}"
[[ "${target_id}" =~ [A-Z] ]] \
&& die "Invalid ${_arg_template_type} name '${target_id}', should be lower case only."
if [[ "${_arg_template_type}" != 'namespace' ]]; then
[[ "${target_id}" != *"/"* || "${target_id}" == *"/" ]] \
&& die "\"${target_id}\" should have format <namespace>/<image_name>"
[[ "${_NAMESPACE_TYPE}" == 'none' ]] \
&& die "${_NAMESPACE_DIR} is not a valid Kubler namespace dir"
fi
add_template_filter_var '_tmpl_namespace' "${target_namespace}"
if [[ "${_arg_template_type}" == 'image' || "${_arg_template_type}" == 'builder' ]]; then
get_ns_include_path "${target_namespace}"
[ $? -eq 3 ] && die "No namespace with id \"${target_namespace}\""
# shellcheck disable=SC2154
source_namespace_conf "${__get_ns_include_path}"
add_template_filter_var '_tmpl_image_name' "${target_image_name}"
fi
case "${_arg_template_type}" in
namespace)
add_namespace "${target_id}"
;;
image)
add_image "${target_namespace}" "${target_image_name}"
;;
builder)
add_builder "${target_namespace}" "${target_image_name}"
;;
*)
show_help
die "Unknown type \"${_arg_template_type}\", should be namespace, builder or image.."
exit 1
;;
esac
}
main "$@"