From 5a25724581e3d8c630d64bb0e46865d7a8a227eb Mon Sep 17 00:00:00 2001 From: Valentin Lab Date: Tue, 22 Oct 2024 12:13:06 +0200 Subject: [PATCH] wip2 --- bin/compose-core | 181 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 170 insertions(+), 11 deletions(-) diff --git a/bin/compose-core b/bin/compose-core index 00434a6..bb744c2 100755 --- a/bin/compose-core +++ b/bin/compose-core @@ -104,6 +104,8 @@ else fi export VARDIR CACHEDIR +export SERVICE_STATE_PATH=${SERVICE_STATE_PATH:-/var/lib/compose/state} + md5_compat() { md5sum | cut -c -32; } quick_cat_file() { quick_cat_stdin < "$1"; } @@ -2583,7 +2585,7 @@ get_service_incoming_relations() { cache_file="$state_tmpdir/$FUNCNAME.cache.$(H "$@" "$SUBSET_ALL_RELATIONS_HASH")" \ s rn ts rc td if [ -e "$cache_file" ]; then - #debug "$FUNCNAME: SESSION cache hit $1" + debug "$FUNCNAME: SESSION cache hit $1" cat "$cache_file" return 0 fi @@ -2593,8 +2595,8 @@ get_service_incoming_relations() { relation_data_file=$(get_relation_data_file "$s" "$ts" "$rn" "$rc") || return 1 printf "%s\0" "$s" "$(cat "$relation_data_file")" || return 1 debug "Found relation $rn from $s to $ts" >&2 - done < "$SUBSET_ALL_RELATIONS" > "$cache_file" - + done < "$SUBSET_ALL_RELATIONS" > "$cache_file.wip" + mv "$cache_file"{.wip,} || return 1 cat "$cache_file" } export -f get_service_incoming_relations @@ -5078,8 +5080,22 @@ while read-0 arg; do shift done < <(cla.normalize "$@") + +more_actions=(status) + +if [[ "$action" == *" "* ]]; then + err "Invalid action name containing spaces: ${DARKCYAN}$action${NORMAL}" + exit 1 +fi + +is_more_action= +[[ " ${more_actions[*]} " == *" $action "* ]] && is_more_action=true + + + [ -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 @@ -5139,7 +5155,8 @@ charm.sanity_checks || die "Sanity checks about charm-store failed. Please corre ## Get services in command line. ## -if [ -z "$is_docker_compose_action" -a "$action" ]; then + +if [ -z "$is_docker_compose_action" ] && [ -z "$is_more_action" ] && [ -n "$action" ]; then action_service=${remainder_args[0]} if [ -z "$action_service" ]; then err "No such command or action: ${DARKCYAN}$action${NORMAL}" @@ -5187,6 +5204,12 @@ else services_args=($(compose:yml:root:services)) || return 1 fi ;; + status) + services_args=("${remainder_args[@]}") + if [ "${#services_args[@]}" == 0 ]; then + services_args=($(compose:yml:root:services)) || return 1 + fi + ;; config) services_args=("${action_posargs[@]}") ;; @@ -5196,7 +5219,7 @@ fi export COMPOSE_ACTION="$action" NO_CONSTRAINT_CHECK=True case "$action" in - up) + up|status) NO_CONSTRAINT_CHECK= if [ -n "$DEBUG" ]; then Elt "solve all relations" @@ -5226,6 +5249,66 @@ case "$action" in ;; esac + +case "$action" in + up) + PROJECT_NAME=$(get_default_project_name) || exit 1 + + ## Required by get_ordered_service_dependencies + array_read-0 services_args < <(printf "%s" "$COMPOSE_YML_CONTENT" | shyaml keys-0 2>/dev/null) + NO_CONSTRAINT_CHECK=1 get_all_relations "${services_args[@]}" >/dev/null || exit 1 + + ## Remove all intents (*ing states) + rm -f "$SERVICE_STATE_PATH/$PROJECT_NAME"/*/*ing || true + + ## Notify that we have the intent to bring up all these + ## This will be use in inner or concurrent 'run' to include the + ## services that are supposed to be up. + mkdir -p "$SERVICE_STATE_PATH/$PROJECT_NAME" || exit 1 + services_args_deps=($(get_ordered_service_dependencies "${services_args[@]}")) || exit 1 + for service in "${services_args_deps[@]}"; do + mkdir -p "$SERVICE_STATE_PATH/$PROJECT_NAME"/"$service" || exit 1 + [ -e "$SERVICE_STATE_PATH/$PROJECT_NAME"/"$service"/up ] || { + touch "$SERVICE_STATE_PATH/$PROJECT_NAME"/"$service"/deploying || exit 1 + } + done + ## remove services not included in compose.yml anymore + array_read-0 all_services < <(printf "%s" "$COMPOSE_YML_CONTENT" | shyaml keys-0 2>/dev/null) + all_services_deps=($(get_ordered_service_dependencies "${all_services[@]}")) || exit 1 + for service in "$SERVICE_STATE_PATH/$PROJECT_NAME"/*/up; do + [ -e "$service" ] || continue + state=${service##*/} + service=${service%/$state} + service=${service##*/} + + if [[ " ${all_services_deps[*]} " != *" ${service} "* ]]; then + touch "$SERVICE_STATE_PATH/$PROJECT_NAME"/"${service}"/orphaning || exit 1 + fi + done + ;; + + run) + PROJECT_NAME=$(get_default_project_name) || return 1 + if [ -d "$SERVICE_STATE_PATH/$PROJECT_NAME" ]; then + ## Notify that we have the intent to bring up all these + ## This will be use in inner or concurrent 'run' to include the + ## services that are supposed to be up. + for service in "$SERVICE_STATE_PATH/$PROJECT_NAME"/*/{up,deploying}; do + [ -e "$service" ] || continue + state=${service##*/} + service=${service%/$state} + service=${service##*/} + ## don't add if orphaning + [ -e "$SERVICE_STATE_PATH/$PROJECT_NAME"/"${service}"/orphaning ] && continue + ## add in ${services_args[@]} if not already there + if [[ " ${services_args[*]} " != *" ${service} "* ]]; then + services_args+=("$service") + fi + done + fi + ;; +esac + if [ -n "$is_docker_compose_action_multi_service" ]; then if [ -n "$DEBUG" ]; then Elt "get relation subet" @@ -5241,7 +5324,7 @@ if [ -n "$is_docker_compose_action_multi_service" ]; then fi fi -if [ "$is_docker_compose_action" -a "${#services_args[@]}" -gt 0 ]; then +if [ -n "$is_docker_compose_action" ] && [ "${#services_args[@]}" -gt 0 ]; then services=($(get_master_services "${services_args[@]}")) || exit 1 if [ "$action" == "up" ]; then declare -A seen @@ -5266,10 +5349,13 @@ if [ "$is_docker_compose_action" -a "${#services_args[@]}" -gt 0 ]; then fi -get_docker_compose "${services_args[@]}" >/dev/null || { ## precalculate variable \$_current_docker_compose - err "Fails to compile base 'docker-compose.yml'" - exit 1 -} +# if [ "$action" != "status" ]; then + get_docker_compose "${services_args[@]}" >/dev/null || { ## precalculate variable \$_current_docker_compose + err "Fails to compile base 'docker-compose.yml'" + exit 1 + } +# fi + ## ## Pre-action @@ -5285,7 +5371,7 @@ case "$action" in full_init=true post_hook=true ;; - ""|down|restart|logs|config|ps) + ""|down|restart|logs|config|ps|status) full_init= ;; *) @@ -5350,6 +5436,47 @@ fi [ "$action" == "build" ] && exit 0 +service:state() { + local service="$1" states state + project_name=$(get_default_project_name) || return 1 + states=() + for state in "$SERVICE_STATE_PATH"/"$project_name"/"$service"/*; do + [ -e "$state" ] || continue + state=${state##*/} + states+=("$state") + done + + if [[ " ${states[*]} " == *" deploying "* ]]; then + echo "deploying" + elif [[ " ${states[*]} " == *" up "* ]]; then + echo "up" + else + echo "down" + fi +} + + +if [ "$action" == "status" ]; then + for service in "${services_args[@]}"; do + msgs="" + if has_service_action "$service" "get-version" >/dev/null; then + version_msg=$(run_service_action "$service" "get-version") || exit 1 + if [[ "$version_msg" == *$'\n'* ]]; then + version="${version_msg%%$'\n'*}" + msgs="${version_msg#*$'\n'}" + else + version=${version_msg} + fi + else + version="N/A" + fi + state=$(service:state "$service") + printf "%-20s %8s %10s %s\n" "$service" "$state" "$version" "$msgs" + done + exit 0 +fi + + if [ "$action" == "run" ] && [ "${#services_args}" != 0 ]; then charm=$(get_service_charm "${services_args[0]}") || exit 1 metadata=$(charm.metadata "$charm") || exit 1 @@ -5432,6 +5559,38 @@ if [ "$action" == "run" -a "${#services_args}" != 0 ]; then fi fi +case "$action" in + up) + ## Notify that services in 'deploying' states have been deployed + for service in "$SERVICE_STATE_PATH/$PROJECT_NAME"/*/deploying; do + [ -e "$service" ] || continue + state=${service##*/} + service=${service%/$state} + service=${service##*/} + + mv "$SERVICE_STATE_PATH/$PROJECT_NAME"/"${service}"/{deploying,up} + done + ## Notify that services in 'orphaning' states have been removed + for service in "$SERVICE_STATE_PATH/$PROJECT_NAME"/*/orphaning; do + [ -e "$service" ] || continue + state=${service##*/} + service=${service%/$state} + service=${service##*/} + + rm "$SERVICE_STATE_PATH/$PROJECT_NAME"/"${service}"/orphaning + done + ;; + down) + PROJECT_NAME=$(get_default_project_name) || return 1 + if [ -d "$SERVICE_STATE_PATH/$PROJECT_NAME" ]; then + if ! dir_is_empty "$SERVICE_STATE_PATH/$PROJECT_NAME"; then + rm -f "$SERVICE_STATE_PATH/$PROJECT_NAME"/*/* + fi + rmdir "$SERVICE_STATE_PATH/$PROJECT_NAME"/{*,} + fi + ;; +esac + clean_unused_docker_compose || exit 1 exit "$errlvl" \ No newline at end of file