|
|
@ -136,6 +136,13 @@ read-0-err() { |
|
|
|
false |
|
|
|
} |
|
|
|
} |
|
|
|
export -f read-0-err |
|
|
|
|
|
|
|
p-err() { |
|
|
|
"$@" |
|
|
|
echo "$?" |
|
|
|
} |
|
|
|
export -f p-err |
|
|
|
|
|
|
|
|
|
|
|
wyq() { |
|
|
@ -355,7 +362,7 @@ export -f merge_yaml_str |
|
|
|
yaml_get_values() { |
|
|
|
local sep=${1:-$'\n'} value input type first elt |
|
|
|
input=$(cat -) |
|
|
|
if [ -z "$input" ] || [ "$input" == "None" ]; then |
|
|
|
if [ -z "$input" ] || [[ "$input" =~ ^None|null$ ]]; then |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
type=$(e "$input" | shyaml get-type) |
|
|
@ -459,7 +466,7 @@ export -f cached_cmd_on_image |
|
|
|
cmd_on_base_image() { |
|
|
|
local service="$1" base_image |
|
|
|
shift |
|
|
|
base_image=$(service_base_docker_image "$service") || return 1 |
|
|
|
base_image=$(service_ensure_image_ready "$service") || return 1 |
|
|
|
docker run -i --rm --entrypoint /bin/bash "$base_image" -c "$*" |
|
|
|
} |
|
|
|
export -f cmd_on_base_image |
|
|
@ -473,10 +480,7 @@ cached_cmd_on_base_image() { |
|
|
|
quick_cat_stdin < "$cache_file" |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
base_image=$(service_base_docker_image "$service") || return 1 |
|
|
|
if ! docker_has_image "$base_image"; then |
|
|
|
docker pull "$base_image" 1>&2 |
|
|
|
fi |
|
|
|
base_image=$(service_ensure_image_ready "$service") || return 1 |
|
|
|
result=$(cached_cmd_on_image "$base_image" "$@") || return 1 |
|
|
|
echo "$result" | tee "$cache_file" |
|
|
|
} |
|
|
@ -493,7 +497,7 @@ docker_update() { |
|
|
|
shift |
|
|
|
shift |
|
|
|
## this will build it if necessary |
|
|
|
base_image=$(service_base_docker_image "$service") || return 1 |
|
|
|
base_image=$(service_ensure_image_ready "$service") || return 1 |
|
|
|
|
|
|
|
## XXXvlab: there are probably ways to avoid rebuilding that each time |
|
|
|
image_id="$(docker_image_id "$base_image")" || return 1 |
|
|
@ -552,10 +556,7 @@ export -f docker_image_export_dir |
|
|
|
service_base_image_export_dir() { |
|
|
|
local service="$1" src="$2" dst="$3" base_image |
|
|
|
shift |
|
|
|
base_image=$(service_base_docker_image "$service") || return 1 |
|
|
|
if ! docker_has_image "$base_image"; then |
|
|
|
docker pull "$base_image" |
|
|
|
fi |
|
|
|
base_image=$(service_ensure_image_ready "$service") || return 1 |
|
|
|
docker_image_export_dir "$base_image" "$src" "$dst" |
|
|
|
} |
|
|
|
export -f service_base_image_export_dir |
|
|
@ -564,10 +565,7 @@ export -f service_base_image_export_dir |
|
|
|
service_base_image_id() { |
|
|
|
local service="$1" src="$2" dst="$3" base_image |
|
|
|
shift |
|
|
|
base_image=$(service_base_docker_image "$service") || return 1 |
|
|
|
if ! docker_has_image "$base_image"; then |
|
|
|
docker pull "$base_image" |
|
|
|
fi |
|
|
|
base_image=$(service_ensure_image_ready "$service") || return 1 |
|
|
|
docker inspect "$base_image" --format="{{ .Id }}" |
|
|
|
} |
|
|
|
export -f service_base_image_id |
|
|
@ -823,7 +821,8 @@ ensure_db_docker_running () { |
|
|
|
else |
|
|
|
verb "Database is not locked." |
|
|
|
if ! docker_has_image "$DOCKER_BASE_IMAGE"; then |
|
|
|
docker pull "$DOCKER_BASE_IMAGE" |
|
|
|
err "Unexpected missing docker image $DOCKER_BASE_IMAGE." |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
|
|
|
|
_set_server_db_params || return 1 |
|
|
@ -1122,7 +1121,7 @@ get_docker_compose_links() { |
|
|
|
[ "$type" == "run-once" ] && continue |
|
|
|
if [ "$tech_dep" == "reversed" ]; then |
|
|
|
deps+=("$(echo -en "$master_target_service:\n links:\n - $master_service")") |
|
|
|
elif [ "$tech_dep" == "True" ]; then |
|
|
|
elif [[ "$tech_dep" =~ ^(True|true)$ ]]; then |
|
|
|
deps+=("$(echo -en "$master_service:\n links:\n - $master_target_service")") |
|
|
|
fi |
|
|
|
## XXXvlab: an attempt to add depends_on, but this doesn't work well actually |
|
|
@ -1284,12 +1283,12 @@ get_docker_compose () { |
|
|
|
return 1 |
|
|
|
} |
|
|
|
|
|
|
|
base_v2="version: '2.0'" |
|
|
|
base_v2="version: '2.1'" |
|
|
|
merge_yaml_str "$(yaml_key_val_str "services" "$docker_compose_services")" \ |
|
|
|
"$base_v2" > "$cache_file" || return 1 |
|
|
|
|
|
|
|
export _current_docker_compose="$(cat "$cache_file")" |
|
|
|
echo "$_current_docker_compose" |
|
|
|
export _CURRENT_DOCKER_COMPOSE="$cache_file" |
|
|
|
cat "$_CURRENT_DOCKER_COMPOSE" |
|
|
|
debug " ..compilation of base 'docker-compose.yml' done $GRAY(in $((SECONDS - start_compilation))s)$NORMAL" || true |
|
|
|
# debug " ** ${WHITE}docker-compose.yml${NORMAL}:" |
|
|
|
# debug "$_current_docker_compose" |
|
|
@ -1393,12 +1392,15 @@ export -f get_service_charm |
|
|
|
## full docker-compose.yml to be already built. |
|
|
|
get_service_def () { |
|
|
|
local service="$1" def |
|
|
|
if [ -z "$_current_docker_compose" ]; then |
|
|
|
print_syntax_error "$FUNCNAME is meant to be called after"\ |
|
|
|
"\$_current_docker_compose has been calculated." |
|
|
|
if [ -z "$_CURRENT_DOCKER_COMPOSE" ]; then |
|
|
|
err "${FUNCNAME[0]} is meant to be called after"\ |
|
|
|
"\$_CURRENT_DOCKER_COMPOSE has been calculated." |
|
|
|
echo " Called by:" >&2 |
|
|
|
printf " - %s\n" "${FUNCNAME[@]:1}" >&2 |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
|
|
|
|
def=$(echo "$_current_docker_compose" | shyaml get-value "services.${service//./\\.}" 2>/dev/null) |
|
|
|
def=$(cat "$_CURRENT_DOCKER_COMPOSE" | shyaml get-value "services.${service//./\\.}" 2>/dev/null) |
|
|
|
if [ -z "$def" ]; then |
|
|
|
err "No definition for service $DARKYELLOW$service$NORMAL in compiled 'docker-compose.yml'." |
|
|
|
return 1 |
|
|
@ -1407,54 +1409,285 @@ get_service_def () { |
|
|
|
} |
|
|
|
export -f get_service_def |
|
|
|
|
|
|
|
get_build_hash() { |
|
|
|
local dir="$1" cache_file="$state_tmpdir/$FUNCNAME.cache.$(H "$1")" hash |
|
|
|
if [ -e "$cache_file" ]; then |
|
|
|
# debug "$FUNCNAME: cache hit ($*)" |
|
|
|
cat "$cache_file" |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
## Check that there's a Dockerfile in this directory |
|
|
|
if [ ! -e "$dir/Dockerfile" ]; then |
|
|
|
err "No 'Dockerfile' found in '$dir'." |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
## use find to md5sum all files in the directory and make a final hash |
|
|
|
hash=$(set -o pipefail; cd "$dir"; env -i find "." -type f -exec md5sum {} \; | |
|
|
|
sort | md5sum | awk '{print $1}') || { |
|
|
|
err "Failed to get hash for '$dir'." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
printf "%s" "$hash" | tee "$cache_file" |
|
|
|
return $? |
|
|
|
} |
|
|
|
export -f get_build_hash |
|
|
|
|
|
|
|
### Query/Get cached image from registry |
|
|
|
## |
|
|
|
## Returns on stdout the name of the image if found, or an empty string if not |
|
|
|
cache:image:registry:get() { |
|
|
|
local charm="$1" hash="$2" service="$3" |
|
|
|
local charm_image_name="cache/charm/$charm" |
|
|
|
local charm_image="$charm_image_name:$hash" |
|
|
|
|
|
|
|
Elt "pulling ${DARKPINK}$charm${NORMAL} image from $COMPOSE_DOCKER_REGISTRY" >&2 |
|
|
|
if out=$(docker pull "$COMPOSE_DOCKER_REGISTRY/$charm_image" 2>&1); then |
|
|
|
docker tag "$COMPOSE_DOCKER_REGISTRY/$charm_image" "$charm_image" || { |
|
|
|
err "Failed set image '$COMPOSE_DOCKER_REGISTRY/$charm_image' as '$charm_image'" \ |
|
|
|
"for ${DARKYELLOW}$service${NORMAL}." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
print_info "found" >&2 |
|
|
|
print_status success >&2 |
|
|
|
Feed >&2 |
|
|
|
printf "%s" "$charm_image" | tee "$cache_file" |
|
|
|
return $? |
|
|
|
fi |
|
|
|
if [[ "$out" != *"manifest unknown"* ]] && [[ "$out" != *"manifest"*"not found"* ]]; then |
|
|
|
print_status failure >&2 |
|
|
|
Feed >&2 |
|
|
|
err "Failed to pull image '$COMPOSE_DOCKER_REGISTRY/$charm_image'" \ |
|
|
|
"for ${DARKYELLOW}$service${NORMAL}:" |
|
|
|
e "$out"$'\n' | prefix " ${GRAY}|${NORMAL} " >&2 |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
print_info "not found" >&2 |
|
|
|
if test "$type_method" = "long"; then |
|
|
|
__status="[${NOOP}ABSENT${NORMAL}]" |
|
|
|
else |
|
|
|
echo -n "${NOOP}" |
|
|
|
shift; shift; |
|
|
|
echo -n "$*${NORMAL}" |
|
|
|
fi >&2 |
|
|
|
Feed >&2 |
|
|
|
} |
|
|
|
export -f cache:image:registry:get |
|
|
|
|
|
|
|
### Store cached image on registry |
|
|
|
## |
|
|
|
## Returns nothing |
|
|
|
cache:image:registry:put() { |
|
|
|
if [ -n "$COMPOSE_DOCKER_REGISTRY" ] && [ -n "$COMPOSE_PUSH_TO_REGISTRY" ]; then |
|
|
|
local charm="$1" hash="$2" service="$3" |
|
|
|
local charm_image_name="cache/charm/$charm" |
|
|
|
local charm_image="$charm_image_name:$hash" |
|
|
|
|
|
|
|
Wrap -d "pushing ${DARKPINK}$charm${NORMAL} image to $COMPOSE_DOCKER_REGISTRY" <<EOF || return 1 |
|
|
|
docker tag "$charm_image" "$COMPOSE_DOCKER_REGISTRY/$charm_image" && |
|
|
|
docker push "$COMPOSE_DOCKER_REGISTRY/$charm_image" |
|
|
|
EOF |
|
|
|
fi >&2 |
|
|
|
} |
|
|
|
export -f cache:image:registry:put |
|
|
|
|
|
|
|
|
|
|
|
### Produce docker cached charm image 'cache/charm/$charm:$hash' |
|
|
|
## |
|
|
|
## Either by fetching it from a registry or by building it from a |
|
|
|
## Dockerfile. |
|
|
|
cache:image:produce() { |
|
|
|
local type="$1" src="$2" charm="$3" hash="$4" service="$5" |
|
|
|
local charm_image_name="cache/charm/$charm" |
|
|
|
local charm_image="$charm_image_name:$hash" |
|
|
|
|
|
|
|
case "$type" in |
|
|
|
fetch) |
|
|
|
local specified_image="$src" |
|
|
|
## will not pull upstream image if already present locally |
|
|
|
if ! docker_has_image "${specified_image}"; then |
|
|
|
if ! out=$(docker pull "${specified_image}" 2>&1); then |
|
|
|
err "Failed to pull image '$specified_image' for ${DARKYELLOW}$service${NORMAL}:" |
|
|
|
echo "$out" | prefix " | " >&2 |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
fi |
|
|
|
|
|
|
|
# specified_image_id=$(docker_image_id "$specified_image") || return 1 |
|
|
|
# charm_image_id= |
|
|
|
# if docker_has_image "${image_dst}"; then |
|
|
|
# charm_image_id=$(docker_image_id "${image_dst}") || return 1 |
|
|
|
# fi |
|
|
|
# if [ "$specified_image_id" != "$charm_image_id" ]; then |
|
|
|
docker tag "$specified_image" "${charm_image}" || return 1 |
|
|
|
# fi |
|
|
|
;; |
|
|
|
build) |
|
|
|
local service_build="$src" |
|
|
|
build_opts=() |
|
|
|
if [ "$COMPOSE_ACTION" == "build" ]; then |
|
|
|
while read-0 arg; do |
|
|
|
case "$arg" in |
|
|
|
-t|--tag) |
|
|
|
## XXXvlab: doesn't seem to be actually a valid option |
|
|
|
if [ -n "$COMPOSE_PUSH_TO_REGISTRY" ]; then |
|
|
|
err "You can't use -t|--tag option when pushing to a registry." |
|
|
|
exit 1 |
|
|
|
fi |
|
|
|
has_named_image=true |
|
|
|
read-0 val ## should always be okay because already checked |
|
|
|
build_opts+=("$arg" "$val") |
|
|
|
;; |
|
|
|
--help|-h) |
|
|
|
docker-compose "$action" --help | |
|
|
|
filter_docker_compose_help_message >&2 |
|
|
|
exit 0 |
|
|
|
;; |
|
|
|
--*|-*) |
|
|
|
if str_pattern_matches "$arg" $DC_MATCH_MULTI; then |
|
|
|
read-0 value |
|
|
|
build_opts+=("$arg" "$value") |
|
|
|
shift |
|
|
|
elif str_pattern_matches "$arg" $DC_MATCH_SINGLE; then |
|
|
|
build_opts+=("$arg") |
|
|
|
else |
|
|
|
err "Unexpected error while parsing a second time the build arguments." |
|
|
|
fi |
|
|
|
;; |
|
|
|
*) |
|
|
|
## Already parsed |
|
|
|
build_opts+=("$arg") |
|
|
|
;; |
|
|
|
esac |
|
|
|
done < <(cla.normalize "${action_opts[@]}") |
|
|
|
fi |
|
|
|
if [ -z "$has_named_image" ]; then |
|
|
|
build_opts+=(-t "${charm_image}") |
|
|
|
fi |
|
|
|
|
|
|
|
Wrap -v -d "Building ${DARKPINK}$charm${NORMAL}:$hash image" -- \ |
|
|
|
docker build "$service_build" -t "${charm_image}" "${build_opts[@]}" >&2 || { |
|
|
|
err "Failed to build image '${charm_image}' for ${DARKYELLOW}$service${NORMAL}." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
if [ -n "$has_named_image" ]; then |
|
|
|
exit 0 |
|
|
|
fi |
|
|
|
;; |
|
|
|
*) |
|
|
|
err "Unknown type '$type'." |
|
|
|
return 1 |
|
|
|
;; |
|
|
|
esac |
|
|
|
} |
|
|
|
export -f cache:image:produce |
|
|
|
|
|
|
|
## Return the base docker image name of a service |
|
|
|
service_base_docker_image() { |
|
|
|
service_ensure_image_ready() { |
|
|
|
local service="$1" cache_file="$state_tmpdir/$FUNCNAME.cache.$1" \ |
|
|
|
master_service service_def service_image service_build service_dockerfile |
|
|
|
master_service service_def service_image service_build service_dockerfile image \ |
|
|
|
specified_image specified_image_id charm_image_name hash \ |
|
|
|
service_quoted |
|
|
|
|
|
|
|
if [ -e "$cache_file" ]; then |
|
|
|
# debug "$FUNCNAME: cache hit ($*)" |
|
|
|
#debug "$FUNCNAME: cache hit ($*)" |
|
|
|
cat "$cache_file" |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
if [ -z "$_CURRENT_DOCKER_COMPOSE" ]; then |
|
|
|
err "${FUNCNAME[0]} is meant to be called after"\ |
|
|
|
"\$_CURRENT_DOCKER_COMPOSE has been calculated." |
|
|
|
echo " Called by:" >&2 |
|
|
|
printf " - %s\n" "${FUNCNAME[@]:1}" >&2 |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
|
|
|
|
master_service="$(get_top_master_service_for_service "$service")" || { |
|
|
|
err "Could not compute master service for service $DARKYELLOW$service$NORMAL." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
service_def="$(get_service_def "$master_service")" || { |
|
|
|
err "Could not get docker-compose service definition for $DARKYELLOW$master_service$NORMAL." |
|
|
|
if [ "$master_service" != "$service" ]; then |
|
|
|
image=$(service_ensure_image_ready "$master_service") || return 1 |
|
|
|
printf "%s" "$image" | tee "$cache_file" |
|
|
|
return $? |
|
|
|
fi |
|
|
|
|
|
|
|
## check if \$_CURRENT_DOCKER_COMPOSE's service def is already correctly setup |
|
|
|
local charm="$(get_service_charm "$service")" || return 1 |
|
|
|
local charm_image_name="cache/charm/$charm" || return 1 |
|
|
|
local service_def="$(get_service_def "$service")" || { |
|
|
|
err "Could not get docker-compose service definition for $DARKYELLOW$service$NORMAL." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
service_image=$(echo "$service_def" | shyaml get-value image 2>/dev/null) |
|
|
|
if [ "$?" != 0 ]; then |
|
|
|
## According to https://stackoverflow.com/questions/32230577 , if there's a build, |
|
|
|
## then the builded image will get name ${project}_${service} |
|
|
|
project=$(get_default_project_name) || return 1 |
|
|
|
image_name="${project}_${service}" |
|
|
|
if ! docker_has_image "$image_name"; then |
|
|
|
service_build=$(echo "$service_def" | shyaml get-value build 2>/dev/null) |
|
|
|
if [ "$?" != 0 ]; then |
|
|
|
err "Service $DARKYELLOW$service$NORMAL has no ${WHITE}image${NORMAL} nor ${WHITE}build${NORMAL} parameter." |
|
|
|
echo "$service_def" >&2 |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
local service_quoted=${service//./\\.} |
|
|
|
|
|
|
|
docker build "$service_build" -t "${project}_${service}" >&2 || { |
|
|
|
err "Failed to build image for ${DARKYELLOW}$service${NORMAL}." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
if specified_image=$(echo "$service_def" | shyaml get-value image 2>/dev/null); then |
|
|
|
if [ "$specified_image" == "$charm_image_name"* ]; then |
|
|
|
## Assume we already did the change |
|
|
|
printf "%s" "$specified_image" | tee "$cache_file" |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
printf "%s" "${project}_${service}" |
|
|
|
if [[ "$specified_image" == "${COMPOSE_DOCKER_REGISTRY}/"* ]]; then |
|
|
|
if [ -n "$DEBUG" ]; then |
|
|
|
Elt "using ${DARKPINK}$charm${NORMAL}'s specified image from $COMPOSE_DOCKER_REGISTRY" >&2 |
|
|
|
print_status noop >&2 |
|
|
|
Feed >&2 |
|
|
|
fi |
|
|
|
## Already on the cache server |
|
|
|
printf "%s" "$specified_image" | tee "$cache_file" |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
src="$specified_image" |
|
|
|
hash=$(echo "$specified_image" | md5sum | cut -f 1 -d " ") || return 1 |
|
|
|
type=fetch |
|
|
|
|
|
|
|
## replace image by charm image |
|
|
|
yq -i ".services.[\"${service_quoted}\"].image = \"${charm_image_name}:${hash}\"" \ |
|
|
|
"$_CURRENT_DOCKER_COMPOSE" || return 1 |
|
|
|
else |
|
|
|
printf "%s" "${service_image}" |
|
|
|
fi | tee "$cache_file" |
|
|
|
if [ "${PIPESTATUS[0]}" != 0 ]; then |
|
|
|
rm "$cache_file" |
|
|
|
return 1 |
|
|
|
|
|
|
|
if ! src=$(echo "$service_def" | shyaml get-value build 2>/dev/null); then |
|
|
|
err "Service $DARKYELLOW$service$NORMAL has no ${WHITE}image${NORMAL} nor ${WHITE}build${NORMAL} parameter." |
|
|
|
echo "$service_def" >&2 |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
|
|
|
|
## According to https://stackoverflow.com/questions/32230577 , if there's a build, |
|
|
|
## then the built image will get name ${project}_${service} |
|
|
|
hash=$(get_build_hash "$src") || return 1 |
|
|
|
type=build |
|
|
|
## delete build key from service_def and add image to charm_image_name |
|
|
|
yq -i "del(.services.[\"${service_quoted}\"].build) | |
|
|
|
.services.[\"${service_quoted}\"].image = \"${charm_image_name}:${hash}\"" \ |
|
|
|
"$_CURRENT_DOCKER_COMPOSE" || return 1 |
|
|
|
|
|
|
|
fi |
|
|
|
if [ "$COMPOSE_ACTION" != "build" ] && docker_has_image "${charm_image_name}:${hash}"; then |
|
|
|
if [ -n "$DEBUG" ]; then |
|
|
|
Elt "using ${DARKPINK}$charm${NORMAL}'s image from local cache" >&2 |
|
|
|
print_status noop >&2 |
|
|
|
Feed >&2 |
|
|
|
fi |
|
|
|
cache:image:registry:put "$charm" "$hash" "$service" || return 1 |
|
|
|
printf "%s" "${charm_image_name}:${hash}" | tee "$cache_file" |
|
|
|
return $? |
|
|
|
fi |
|
|
|
|
|
|
|
## Can we pull it ? Let's check on $COMPOSE_DOCKER_REGISTRY |
|
|
|
if [ "$COMPOSE_ACTION" != "build" ] && [ -n "$COMPOSE_DOCKER_REGISTRY" ]; then |
|
|
|
img=$(cache:image:registry:get "$charm" "$hash" "$service") || { |
|
|
|
err "Failed to get image '$charm_image_name:$hash' from registry for ${DARKYELLOW}$service${NORMAL}." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
[ -n "$img" ] && { |
|
|
|
printf "%s" "$img" | tee "$cache_file" |
|
|
|
return $? |
|
|
|
} |
|
|
|
fi |
|
|
|
cache:image:produce "$type" "$src" "$charm" "$hash" "$service" || return 1 |
|
|
|
cache:image:registry:put "$charm" "$hash" "$service" || return 1 |
|
|
|
printf "%s" "${charm_image_name}:$hash" | tee "$cache_file" |
|
|
|
return $? |
|
|
|
} |
|
|
|
export -f service_base_docker_image |
|
|
|
export -f service_ensure_image_ready |
|
|
|
|
|
|
|
|
|
|
|
get_charm_relation_def () { |
|
|
@ -1609,6 +1842,31 @@ get_ordered_service_dependencies() { |
|
|
|
export -f get_ordered_service_dependencies |
|
|
|
|
|
|
|
|
|
|
|
run_service_acquire_images () { |
|
|
|
local service subservice subservices loaded |
|
|
|
declare -A loaded |
|
|
|
for service in "$@"; do |
|
|
|
subservices=$(get_ordered_service_dependencies "$service") || return 1 |
|
|
|
for subservice in $subservices; do |
|
|
|
if [ "${loaded[$subservice]}" ]; then |
|
|
|
## Prevent double inclusion of same service if this |
|
|
|
## service is deps of two or more of your |
|
|
|
## requirements. |
|
|
|
continue |
|
|
|
fi |
|
|
|
|
|
|
|
type=$(get_service_type "$subservice") || return 1 |
|
|
|
MASTER_BASE_SERVICE_NAME=$(get_top_master_service_for_service "$subservice") || return 1 |
|
|
|
if [ "$type" != "stub" ]; then |
|
|
|
DOCKER_BASE_IMAGE=$(service_ensure_image_ready "$MASTER_BASE_SERVICE_NAME") || return 1 |
|
|
|
fi |
|
|
|
|
|
|
|
loaded[$subservice]=1 |
|
|
|
done |
|
|
|
done |
|
|
|
return 0 |
|
|
|
} |
|
|
|
|
|
|
|
run_service_hook () { |
|
|
|
local action="$1" service subservice subservices loaded |
|
|
|
shift |
|
|
@ -1631,7 +1889,7 @@ run_service_hook () { |
|
|
|
MASTER_BASE_SERVICE_NAME=$(get_top_master_service_for_service "$subservice") || return 1 |
|
|
|
MASTER_BASE_CHARM_NAME=$(get_service_charm "$MASTER_BASE_SERVICE_NAME") || return 1 |
|
|
|
if [ "$type" != "stub" ]; then |
|
|
|
DOCKER_BASE_IMAGE=$(service_base_docker_image "$MASTER_BASE_SERVICE_NAME") || return 1 |
|
|
|
DOCKER_BASE_IMAGE=$(service_ensure_image_ready "$MASTER_BASE_SERVICE_NAME") || return 1 |
|
|
|
fi |
|
|
|
|
|
|
|
Wrap "${wrap_opts[@]}" -d "running $YELLOW$action$NORMAL hook of $DARKYELLOW$subservice$NORMAL in charm $DARKPINK$charm$NORMAL" <<EOF || return 1 |
|
|
@ -1764,7 +2022,7 @@ cfg-get-value () { |
|
|
|
err "The key $WHITE$key$NORMAL was not found in relation's data." |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
echo "$out" | yaml_get_interpret |
|
|
|
printf "%s\n" "$out" | yaml_get_interpret |
|
|
|
} |
|
|
|
export -f cfg-get-value |
|
|
|
|
|
|
@ -1807,8 +2065,7 @@ export -f expand_vars |
|
|
|
yaml_get_interpret() { |
|
|
|
local content tag |
|
|
|
content=$(cat -) |
|
|
|
tag=$(echo "$content" | shyaml -y get-value) || return 1 |
|
|
|
tag="${tag%% *}" |
|
|
|
tag=$(echo "$content" | shyaml get-type) || return 1 |
|
|
|
content=$(echo "$content" | shyaml get-value) || return 1 |
|
|
|
if ! [ "${tag:0:1}" == "!" ]; then |
|
|
|
echo "$content" || return 1 |
|
|
@ -1987,7 +2244,7 @@ _run_service_relation () { |
|
|
|
RELATION_CONFIG="$relation_dir/config_provider" |
|
|
|
type=$(get_service_type "$target_service") || return 1 |
|
|
|
if [ "$type" != "stub" ]; then |
|
|
|
DOCKER_BASE_IMAGE=$(service_base_docker_image "$target_service") || return 1 |
|
|
|
DOCKER_BASE_IMAGE=$(service_ensure_image_ready "$target_service") || return 1 |
|
|
|
fi |
|
|
|
export DOCKER_BASE_IMAGE RELATION_CONFIG RELATION_DATA |
|
|
|
{ |
|
|
@ -2020,7 +2277,7 @@ _run_service_relation () { |
|
|
|
"for $DARKYELLOW$service$NORMAL (charm $DARKPINK$charm$NORMAL)" |
|
|
|
RELATION_CONFIG="$relation_dir/config_providee" |
|
|
|
RELATION_DATA="$(cat "$RELATION_DATA_FILE")" |
|
|
|
DOCKER_BASE_IMAGE=$(service_base_docker_image "$service") || return 1 |
|
|
|
DOCKER_BASE_IMAGE=$(service_ensure_image_ready "$service") || return 1 |
|
|
|
export DOCKER_BASE_IMAGE RELATION_CONFIG RELATION_DATA |
|
|
|
{ |
|
|
|
( |
|
|
@ -2210,6 +2467,37 @@ get_service_relation() { |
|
|
|
export -f get_service_relation |
|
|
|
|
|
|
|
|
|
|
|
## From a service and a relation, get all relations targeting given |
|
|
|
## service with given relation. |
|
|
|
## |
|
|
|
## Returns a NUL separated list of couple of: |
|
|
|
## (base_service, relation_config) |
|
|
|
## |
|
|
|
get_service_incoming_relations() { |
|
|
|
local service="$1" relation="$2" cache_file="$state_tmpdir/$FUNCNAME.cache.$(H "$@" "$ALL_RELATIONS")" \ |
|
|
|
s rn ts rc td |
|
|
|
if [ -e "$cache_file" ]; then |
|
|
|
#debug "$FUNCNAME: SESSION cache hit $1" |
|
|
|
cat "$cache_file" |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
if [ -z "$ALL_RELATIONS" ]; then |
|
|
|
err "Can't access global \$ALL_RELATIONS" |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
|
|
|
|
while read-0 s rn ts rc _td; do |
|
|
|
[[ "$ts" == "$service" ]] || continue |
|
|
|
[[ "$rn" == "$relation" ]] || continue |
|
|
|
relation_data_file=$(get_relation_data_file "$s" "$ts" "$rn" "$rc") || return 1 |
|
|
|
printf "%s\0" "$s" "$(cat "$relation_data_file")" |
|
|
|
done < <(cat "$ALL_RELATIONS") > "$cache_file" |
|
|
|
|
|
|
|
cat "$cache_file" |
|
|
|
} |
|
|
|
export -f get_service_incoming_relations |
|
|
|
|
|
|
|
|
|
|
|
export TRAVERSE_SEPARATOR=: |
|
|
|
## Traverse on first service satisfying relation |
|
|
|
service:traverse() { |
|
|
@ -2403,7 +2691,7 @@ _get_metadata_provides() { |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
|
|
|
|
provides=$(printf "%s" "$metadata" | shyaml get-value -y -q provides "") |
|
|
|
provides=$(printf "%s" "$metadata" | shyaml -q get-value -y provides "") |
|
|
|
[ "$provides" -a "$provides" != "''" ] || { touch "$cache_file"; return 0; } |
|
|
|
|
|
|
|
_get_provides_provides "$provides" | tee "$cache_file" |
|
|
@ -2577,7 +2865,7 @@ get_all_relations () { |
|
|
|
all_services=("$@") |
|
|
|
while [ "${#all_services[@]}" != 0 ]; do |
|
|
|
array_pop all_services service |
|
|
|
while read-0 relation_name ts relation_config tech_dep; do |
|
|
|
while read-0-err E relation_name ts relation_config tech_dep; do |
|
|
|
[ "${without_relations[$service:$relation_name]}" ] && { |
|
|
|
debug "Ignoring compose $DARKYELLOW$service$NORMAL --$DARKBLUE$relation_name$NORMAL--> ${DARKYELLOW}$ts$NORMAL" |
|
|
|
continue |
|
|
@ -2590,7 +2878,11 @@ get_all_relations () { |
|
|
|
array_read-0 services_uses < <(_get_services_uses "$ts") |
|
|
|
all_services+=("$ts") |
|
|
|
services[$ts]=1 |
|
|
|
done < <(get_compose_relations "$service") |
|
|
|
done < <(p-err get_compose_relations "$service") |
|
|
|
if [ "$E" != 0 ]; then |
|
|
|
err "Failed to get relations for $DARKYELLOW$service$NORMAL." |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
done > "${cache_file}.wip" |
|
|
|
|
|
|
|
while true; do |
|
|
@ -2648,7 +2940,7 @@ get_all_relations () { |
|
|
|
|
|
|
|
_out_new_relation_from_defs "$service" "$relation_name" "$ts" \ |
|
|
|
"${providers_def[0]}" "$relation_def" \ |
|
|
|
>> "${cache_file}.wip" |
|
|
|
>> "${cache_file}.wip" || return 1 |
|
|
|
|
|
|
|
## Adding service |
|
|
|
[ "${services[$ts]}" ] && continue |
|
|
@ -2656,16 +2948,14 @@ get_all_relations () { |
|
|
|
services[$ts]=1 |
|
|
|
changed=1 |
|
|
|
continue |
|
|
|
elif [ "${#providers[@]}" -gt 1 ]; then |
|
|
|
fi |
|
|
|
if [ "${#providers[@]}" -gt 1 ]; then |
|
|
|
msg="" |
|
|
|
warn "No auto-pairing ${DARKYELLOW}$service${NORMAL}" \ |
|
|
|
"--${DARKBLUE}$relation_name${NORMAL}--> ($DARKYELLOW""${providers[@]}""$NORMAL)"\ |
|
|
|
"(> 1 provider)." |
|
|
|
continue |
|
|
|
else |
|
|
|
if [ "$auto" == "summon" ]; then |
|
|
|
summon+=("$service" "$relation_name" "$relation_def") |
|
|
|
fi |
|
|
|
elif [ "$auto" == "summon" ]; then ## no provider |
|
|
|
summon+=("$service" "$relation_name" "$relation_def") |
|
|
|
fi |
|
|
|
;; |
|
|
|
null|disable|disabled) |
|
|
@ -2739,7 +3029,7 @@ get_all_relations () { |
|
|
|
|
|
|
|
_out_new_relation_from_defs "$service" "$relation_name" "$ts" \ |
|
|
|
"${providers_def[0]}" "$relation_def" \ |
|
|
|
>> "${cache_file}.wip" |
|
|
|
>> "${cache_file}.wip" || return 1 |
|
|
|
|
|
|
|
## Adding service |
|
|
|
[ "${services[$ts]}" ] && continue |
|
|
@ -2916,7 +3206,7 @@ run_service_relations () { |
|
|
|
RELATION_TARGET_COMPOSE_DEF=$(get_compose_service_def "$target_service") || return 1 |
|
|
|
export RELATION_TARGET_COMPOSE_DEF MASTER_TARGET_{CHARM,SERVICE}_NAME |
|
|
|
|
|
|
|
Wrap "${wrap_opts[@]}" -d "Building $DARKYELLOW$subservice$NORMAL --$DARKBLUE$relation_name$NORMAL--> $DARKYELLOW$target_service$NORMAL" <<EOF || return 1 |
|
|
|
Wrap "${wrap_opts[@]}" -d "building $DARKYELLOW$subservice$NORMAL --$DARKBLUE$relation_name$NORMAL--> $DARKYELLOW$target_service$NORMAL" <<EOF || return 1 |
|
|
|
_run_service_relation "$relation_name" "$subservice" "$target_service" "\$relation_config" |
|
|
|
EOF |
|
|
|
done < <(get_service_relations "$subservice") || return 1 |
|
|
@ -2950,7 +3240,7 @@ _run_service_action_direct() { |
|
|
|
export ACTION_NAME=$action |
|
|
|
export ACTION_SCRIPT_PATH="$action_script_path" |
|
|
|
export CONTAINER_NAME=$(get_top_master_service_for_service "$service") |
|
|
|
export DOCKER_BASE_IMAGE=$(service_base_docker_image "$CONTAINER_NAME") |
|
|
|
export DOCKER_BASE_IMAGE=$(service_ensure_image_ready "$CONTAINER_NAME") |
|
|
|
export SERVICE_DATASTORE="$DATASTORE/$service" |
|
|
|
export SERVICE_CONFIGSTORE="$CONFIGSTORE/$service" |
|
|
|
exname="$exname $ACTION_NAME $SERVICE_NAME" \ |
|
|
@ -2984,7 +3274,7 @@ _run_service_action_relation() { |
|
|
|
export ACTION_NAME=$action |
|
|
|
export ACTION_SCRIPT_PATH="$action_script_path" |
|
|
|
export CONTAINER_NAME=$(get_top_master_service_for_service "$service") |
|
|
|
export DOCKER_BASE_IMAGE=$(service_base_docker_image "$CONTAINER_NAME") |
|
|
|
export DOCKER_BASE_IMAGE=$(service_ensure_image_ready "$CONTAINER_NAME") |
|
|
|
export SERVICE_DATASTORE="$DATASTORE/$service" |
|
|
|
export SERVICE_CONFIGSTORE="$CONFIGSTORE/$service" |
|
|
|
exname="$exname $ACTION_NAME $SERVICE_NAME" \ |
|
|
@ -3018,7 +3308,8 @@ export -f get_relation_data_dir |
|
|
|
|
|
|
|
|
|
|
|
get_relation_data_file() { |
|
|
|
local service="$1" target_service="$2" relation_name="$3" relation_config="$4" |
|
|
|
local service="$1" target_service="$2" relation_name="$3" relation_config="$4" \ |
|
|
|
new new_md5 relation_dir relation_data_file |
|
|
|
|
|
|
|
relation_dir=$(get_relation_data_dir "$service" "$target_service" "$relation_name") || return 1 |
|
|
|
relation_data_file="$relation_dir/data" |
|
|
@ -3034,9 +3325,11 @@ get_relation_data_file() { |
|
|
|
new=true |
|
|
|
fi |
|
|
|
|
|
|
|
if [ "$new" ]; then |
|
|
|
if [ -n "$new" ]; then |
|
|
|
OLDUMASK=$(umask) |
|
|
|
umask 0077 |
|
|
|
e "$relation_config" > "$relation_data_file" |
|
|
|
chmod go-rwx "$relation_data_file" ## protecting this file |
|
|
|
umask "$OLDUMASK" |
|
|
|
e "$relation_config" | md5_compat > "$relation_data_file.md5_ref" |
|
|
|
fi |
|
|
|
echo "$relation_data_file" |
|
|
@ -3171,7 +3464,7 @@ _get_master_service_for_service_cached () { |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
|
|
|
|
if [ "$(echo "$metadata" | shyaml get-value "subordinate" 2>/dev/null)" != "True" ]; then |
|
|
|
if ! [[ "$(echo "$metadata" | shyaml get-value "subordinate" 2>/dev/null)" =~ ^True|true$ ]]; then |
|
|
|
## just return service name |
|
|
|
echo "$service" | tee "$cache_file" |
|
|
|
return 0 |
|
|
@ -3295,7 +3588,7 @@ _get_docker_compose_mixin_from_metadata_cached() { |
|
|
|
mixins+=("$docker_compose") |
|
|
|
fi |
|
|
|
|
|
|
|
if [ "$(echo "$metadata" | shyaml get-value "subordinate" 2>/dev/null)" == "True" ]; then |
|
|
|
if [[ "$(echo "$metadata" | shyaml get-value "subordinate" 2>/dev/null)" =~ ^True|true$ ]]; then |
|
|
|
subordinate=true |
|
|
|
fi |
|
|
|
fi |
|
|
@ -3473,7 +3766,7 @@ switch_to_relation_service() { |
|
|
|
|
|
|
|
export SERVICE_NAME="$ts" |
|
|
|
export SERVICE_DATASTORE="$DATASTORE/$SERVICE_NAME" |
|
|
|
DOCKER_BASE_IMAGE=$(service_base_docker_image "$SERVICE_NAME") |
|
|
|
DOCKER_BASE_IMAGE=$(service_ensure_image_ready "$SERVICE_NAME") |
|
|
|
export DOCKER_BASE_IMAGE |
|
|
|
|
|
|
|
target_charm=$(get_service_charm "$ts") || return 1 |
|
|
@ -3597,7 +3890,14 @@ launch_docker_compose() { |
|
|
|
mkdir -p "$docker_compose_tmpdir/$project" |
|
|
|
docker_compose_dir="$docker_compose_tmpdir/$project" |
|
|
|
|
|
|
|
get_docker_compose $SERVICE_PACK > "$docker_compose_dir/docker-compose.yml" || return 1 |
|
|
|
if [ -z "$_CURRENT_DOCKER_COMPOSE" ]; then |
|
|
|
err "${FUNCNAME[0]} is meant to be called after"\ |
|
|
|
"\$_CURRENT_DOCKER_COMPOSE has been calculated." |
|
|
|
echo " Called by:" >&2 |
|
|
|
printf " - %s\n" "${FUNCNAME[@]:1}" >&2 |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
cat "$_CURRENT_DOCKER_COMPOSE" > "$docker_compose_dir/docker-compose.yml" || return 1 |
|
|
|
if [ -e "$state_tmpdir/to-merge-in-docker-compose.yml" ]; then |
|
|
|
# debug "Merging some config data in docker-compose.yml:" |
|
|
|
# debug "$(cat $state_tmpdir/to-merge-in-docker-compose.yml)" |
|
|
@ -4025,6 +4325,7 @@ display_help() { |
|
|
|
print_help |
|
|
|
echo "${WHITE}Usage${NORMAL}:" |
|
|
|
echo " $usage" |
|
|
|
echo " $usage cache {clean|clear}" |
|
|
|
echo "${WHITE}Options${NORMAL}:" |
|
|
|
echo " -h, --help Print this message and quit" |
|
|
|
echo " (ignoring any other options)" |
|
|
@ -4053,6 +4354,7 @@ display_help() { |
|
|
|
echo " --add-compose-content, -Y YAML" |
|
|
|
echo " Will merge some direct YAML with the current compose" |
|
|
|
echo " -c, --color Force color mode (default is to detect if in tty mode)" |
|
|
|
echo " --push-builds Will push cached docker images to docker cache registry" |
|
|
|
|
|
|
|
get_docker_compose_opts_help | remove_options_in_option_help_msg --version --help --verbose | |
|
|
|
filter_docker_compose_help_message |
|
|
@ -4067,7 +4369,7 @@ _graph_service() { |
|
|
|
metadata=$(charm.metadata "$charm") || return 1 |
|
|
|
subordinate=$(echo "$metadata" | shyaml get-value "subordinate" 2>/dev/null) |
|
|
|
|
|
|
|
if [ "$subordinate" == "True" ]; then |
|
|
|
if [[ "$subordinate" =~ ^True|true$ ]]; then |
|
|
|
requires="$(echo "$metadata" | shyaml get-value "requires" 2>/dev/null)" |
|
|
|
master_charm= |
|
|
|
while read-0 relation_name relation; do |
|
|
@ -4109,8 +4411,8 @@ _graph_node_service() { |
|
|
|
|
|
|
|
cat <<EOF |
|
|
|
"$(_graph_node_service_label ${service})" [ |
|
|
|
style = "filled, $([ "$subordinate" == "True" ] && echo "dashed" || echo "bold")" |
|
|
|
penwidth = $([ "$subordinate" == "True" ] && echo "3" || echo "5") |
|
|
|
style = "filled, $([[ "$subordinate" =~ ^True|true$ ]] && echo "dashed" || echo "bold")" |
|
|
|
penwidth = $([[ "$subordinate" =~ ^True|true$ ]] && echo "3" || echo "5") |
|
|
|
color = $([ "$base" ] && echo "blue" || echo "black") |
|
|
|
fillcolor = "white" |
|
|
|
fontname = "Courier New" |
|
|
@ -4245,11 +4547,11 @@ export -f cached_wget |
|
|
|
|
|
|
|
trap_add "EXIT" clean_cache |
|
|
|
|
|
|
|
|
|
|
|
export COMPOSE_DOCKER_REGISTRY="${COMPOSE_DOCKER_REGISTRY:-docker.0k.io}" |
|
|
|
|
|
|
|
if [ -z "$DISABLE_SYSTEM_CONFIG_FILE" ]; then |
|
|
|
if [ -r /etc/default/charm ]; then |
|
|
|
. /etc/default/charm |
|
|
|
. "/etc/default/charm" |
|
|
|
fi |
|
|
|
|
|
|
|
if [ -r "/etc/default/$exname" ]; then |
|
|
@ -4373,6 +4675,9 @@ while read-0 arg; do |
|
|
|
rebuild_relations_to_service+=("$value") |
|
|
|
shift |
|
|
|
;; |
|
|
|
--push-builds) |
|
|
|
export COMPOSE_PUSH_TO_REGISTRY=1 |
|
|
|
;; |
|
|
|
--debug|-d) |
|
|
|
export DEBUG=true |
|
|
|
export VERBOSE=true |
|
|
@ -4483,6 +4788,38 @@ while read-0 arg; do |
|
|
|
shift |
|
|
|
done < <(cla.normalize "$@") |
|
|
|
|
|
|
|
[ -n "$CACHEDIR" ] || die "No cache directory defined." |
|
|
|
[ -d "$CACHEDIR" ] || die "Cache directory '$CACHEDIR' doesn't exists." |
|
|
|
case "$action" in |
|
|
|
cache) |
|
|
|
case "${remainder_args[0]}" in |
|
|
|
clean) |
|
|
|
clean_cache |
|
|
|
exit 0 |
|
|
|
;; |
|
|
|
clear) |
|
|
|
Wrap "${wrap_opts[@]}" -v -d "clear cache directory" -- rm -rf "$CACHEDIR/"* |
|
|
|
|
|
|
|
## clear all docker caches |
|
|
|
## image name are like '[$COMPOSE_DOCKER_REGISTRY]cache/charm/CHARM_NAME:HASH' |
|
|
|
Wrap "${wrap_opts[@]}" -v -d "clear docker cache" <<EOF |
|
|
|
docker images --format "{{.Repository}}:{{.Tag}}" | |
|
|
|
egrep "^($COMPOSE_DOCKER_REGISTRY/)?cache/charm/[a-zA-Z0-9._-]+:[0-9a-f]{32,32}$" | |
|
|
|
while read -r image; do |
|
|
|
docker rmi "\$image" || true |
|
|
|
done |
|
|
|
EOF |
|
|
|
exit 0 |
|
|
|
;; |
|
|
|
*) |
|
|
|
err "Unknown cache command: ${DARKCYAN}${remainder_args[0]}${NORMAL}" |
|
|
|
exit 1 |
|
|
|
;; |
|
|
|
esac |
|
|
|
;; |
|
|
|
esac |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export compose_contents |
|
|
|
[ "${services_args[*]}" ] && debug " ${DARKWHITE}Services:$NORMAL ${DARKYELLOW}${services_args[*]}$NORMAL" |
|
|
@ -4612,6 +4949,9 @@ get_docker_compose "${services_args[@]}" >/dev/null || { ## precalculate variab |
|
|
|
|
|
|
|
full_init= |
|
|
|
case "$action" in |
|
|
|
build) |
|
|
|
full_init=true ## will actually stop after build |
|
|
|
;; |
|
|
|
up|run) |
|
|
|
full_init=true |
|
|
|
post_hook=true |
|
|
@ -4637,16 +4977,21 @@ case "$action" in |
|
|
|
;; |
|
|
|
esac |
|
|
|
|
|
|
|
|
|
|
|
if [ -n "$full_init" ]; then |
|
|
|
## init in order |
|
|
|
if [[ -z "$no_init" && -z "$no_hooks" ]]; then |
|
|
|
if [[ "$action" == "build" ]] || [[ -z "$no_init" && -z "$no_hooks" ]]; then |
|
|
|
[[ "$action" == "build" ]] || Section "acquire charm's images" |
|
|
|
run_service_acquire_images "${services_args[@]}" || exit 1 |
|
|
|
Feed |
|
|
|
[ "$action" == "build" ] && { |
|
|
|
exit 0 |
|
|
|
} |
|
|
|
|
|
|
|
Section setup host resources |
|
|
|
setup_host_resources "${services_args[@]}" || exit 1 |
|
|
|
## init in order |
|
|
|
Section initialisation |
|
|
|
run_service_hook init "${services_args[@]}" || exit 1 |
|
|
|
fi |
|
|
|
|
|
|
|
## Get relations |
|
|
|
if [[ -z "$no_relations" && -z "$no_hooks" ]]; then |
|
|
|
if [ "${#rebuild_relations_to_service[@]}" != 0 ]; then |
|
|
@ -4673,6 +5018,8 @@ fi | log |
|
|
|
if [ "${PIPESTATUS[0]}" != 0 ]; then |
|
|
|
exit 1 |
|
|
|
fi |
|
|
|
[ "$action" == "build" ] && exit 0 |
|
|
|
|
|
|
|
|
|
|
|
if [ "$action" == "run" ] && [ "${#services_args}" != 0 ]; then |
|
|
|
charm=$(get_service_charm "${services_args[0]}") || exit 1 |
|
|
|