diff options
Diffstat (limited to 'docs/how-to/migration-scripts')
4 files changed, 244 insertions, 2 deletions
diff --git a/docs/how-to/migration-scripts/30-extract-parse-failures.sh b/docs/how-to/migration-scripts/30-extract-parse-failures.sh index bc2049a..410fcbc 100755 --- a/docs/how-to/migration-scripts/30-extract-parse-failures.sh +++ b/docs/how-to/migration-scripts/30-extract-parse-failures.sh | |||
| @@ -65,6 +65,14 @@ | |||
| 65 | 65 | ||
| 66 | set -euo pipefail | 66 | set -euo pipefail |
| 67 | 67 | ||
| 68 | # Get script directory for sourcing helpers | ||
| 69 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| 70 | |||
| 71 | # Source the service validation helper | ||
| 72 | if [[ -f "$SCRIPT_DIR/validate-service.sh" ]]; then | ||
| 73 | source "$SCRIPT_DIR/validate-service.sh" | ||
| 74 | fi | ||
| 75 | |||
| 68 | # Colors for output (disabled if not a terminal) | 76 | # Colors for output (disabled if not a terminal) |
| 69 | if [[ -t 1 ]]; then | 77 | if [[ -t 1 ]]; then |
| 70 | RED='\033[0;31m' | 78 | RED='\033[0;31m' |
| @@ -188,11 +196,35 @@ main() { | |||
| 188 | esac | 196 | esac |
| 189 | done | 197 | done |
| 190 | 198 | ||
| 191 | # Validate service name | 199 | # Validate service name format |
| 192 | if [[ ! "$service" =~ \.service$ ]]; then | 200 | if [[ ! "$service" =~ \.service$ ]]; then |
| 193 | service="${service}.service" | 201 | service="${service}.service" |
| 194 | fi | 202 | fi |
| 195 | 203 | ||
| 204 | # Validate service is appropriate for structured logging | ||
| 205 | # This prevents the common mistake of using ngit-relay instead of ngit-grasp | ||
| 206 | if type validate_service_for_structured_logging &>/dev/null; then | ||
| 207 | # Use non-interactive mode if not a terminal, skip log check (we'll do our own) | ||
| 208 | local interactive="true" | ||
| 209 | [[ ! -t 0 ]] && interactive="false" | ||
| 210 | |||
| 211 | if ! validate_service_for_structured_logging "$service" "false" "$interactive"; then | ||
| 212 | log_error "Service validation failed. Use an ngit-grasp service for structured logging." | ||
| 213 | exit 1 | ||
| 214 | fi | ||
| 215 | else | ||
| 216 | # Fallback validation if helper not available | ||
| 217 | if [[ "$service" == *"ngit-relay"* ]]; then | ||
| 218 | log_error "Service name appears to be ngit-relay: $service" | ||
| 219 | log_error "Structured logging ([PARSE_FAIL]) only exists in ngit-grasp services." | ||
| 220 | log_error "Please use the ngit-grasp archive service instead." | ||
| 221 | log_error "" | ||
| 222 | log_error "To find the correct service:" | ||
| 223 | log_error " systemctl list-units 'ngit-grasp*' --all" | ||
| 224 | exit 1 | ||
| 225 | fi | ||
| 226 | fi | ||
| 227 | |||
| 196 | log_info "Extracting parse failures from systemd logs" | 228 | log_info "Extracting parse failures from systemd logs" |
| 197 | log_info "Service: $service" | 229 | log_info "Service: $service" |
| 198 | log_info "Output: $output_dir" | 230 | log_info "Output: $output_dir" |
diff --git a/docs/how-to/migration-scripts/31-extract-purgatory-expiry.sh b/docs/how-to/migration-scripts/31-extract-purgatory-expiry.sh index 8cadad9..a20780e 100755 --- a/docs/how-to/migration-scripts/31-extract-purgatory-expiry.sh +++ b/docs/how-to/migration-scripts/31-extract-purgatory-expiry.sh | |||
| @@ -76,6 +76,14 @@ | |||
| 76 | 76 | ||
| 77 | set -euo pipefail | 77 | set -euo pipefail |
| 78 | 78 | ||
| 79 | # Get script directory for sourcing helpers | ||
| 80 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| 81 | |||
| 82 | # Source the service validation helper | ||
| 83 | if [[ -f "$SCRIPT_DIR/validate-service.sh" ]]; then | ||
| 84 | source "$SCRIPT_DIR/validate-service.sh" | ||
| 85 | fi | ||
| 86 | |||
| 79 | # Colors for output (disabled if not a terminal) | 87 | # Colors for output (disabled if not a terminal) |
| 80 | if [[ -t 1 ]]; then | 88 | if [[ -t 1 ]]; then |
| 81 | RED='\033[0;31m' | 89 | RED='\033[0;31m' |
| @@ -195,11 +203,35 @@ main() { | |||
| 195 | esac | 203 | esac |
| 196 | done | 204 | done |
| 197 | 205 | ||
| 198 | # Validate service name | 206 | # Validate service name format |
| 199 | if [[ ! "$service" =~ \.service$ ]]; then | 207 | if [[ ! "$service" =~ \.service$ ]]; then |
| 200 | service="${service}.service" | 208 | service="${service}.service" |
| 201 | fi | 209 | fi |
| 202 | 210 | ||
| 211 | # Validate service is appropriate for structured logging | ||
| 212 | # This prevents the common mistake of using ngit-relay instead of ngit-grasp | ||
| 213 | if type validate_service_for_structured_logging &>/dev/null; then | ||
| 214 | # Use non-interactive mode if not a terminal, skip log check (we'll do our own) | ||
| 215 | local interactive="true" | ||
| 216 | [[ ! -t 0 ]] && interactive="false" | ||
| 217 | |||
| 218 | if ! validate_service_for_structured_logging "$service" "false" "$interactive"; then | ||
| 219 | log_error "Service validation failed. Use an ngit-grasp service for structured logging." | ||
| 220 | exit 1 | ||
| 221 | fi | ||
| 222 | else | ||
| 223 | # Fallback validation if helper not available | ||
| 224 | if [[ "$service" == *"ngit-relay"* ]]; then | ||
| 225 | log_error "Service name appears to be ngit-relay: $service" | ||
| 226 | log_error "Structured logging ([PURGATORY_EXPIRED]) only exists in ngit-grasp services." | ||
| 227 | log_error "Please use the ngit-grasp archive service instead." | ||
| 228 | log_error "" | ||
| 229 | log_error "To find the correct service:" | ||
| 230 | log_error " systemctl list-units 'ngit-grasp*' --all" | ||
| 231 | exit 1 | ||
| 232 | fi | ||
| 233 | fi | ||
| 234 | |||
| 203 | log_info "Extracting purgatory expiry events from systemd logs" | 235 | log_info "Extracting purgatory expiry events from systemd logs" |
| 204 | log_info "Service: $service" | 236 | log_info "Service: $service" |
| 205 | log_info "Output: $output_dir" | 237 | log_info "Output: $output_dir" |
diff --git a/docs/how-to/migration-scripts/run-migration-analysis.sh b/docs/how-to/migration-scripts/run-migration-analysis.sh index 65d9d17..b2ca142 100755 --- a/docs/how-to/migration-scripts/run-migration-analysis.sh +++ b/docs/how-to/migration-scripts/run-migration-analysis.sh | |||
| @@ -548,6 +548,34 @@ run_phase_4() { | |||
| 548 | return 0 | 548 | return 0 |
| 549 | fi | 549 | fi |
| 550 | 550 | ||
| 551 | # Validate service name before running Phase 4 | ||
| 552 | # Structured logging only exists in ngit-grasp, not ngit-relay | ||
| 553 | if [[ "$SERVICE_NAME" == *"ngit-relay"* ]]; then | ||
| 554 | log_error "SERVICE_NAME appears to be ngit-relay: $SERVICE_NAME" | ||
| 555 | log_error "" | ||
| 556 | log_error "Phase 4 requires an ngit-grasp service with structured logging." | ||
| 557 | log_error "Structured logging ([PARSE_FAIL], [PURGATORY_EXPIRED]) only exists" | ||
| 558 | log_error "in ngit-grasp services, NOT in ngit-relay services." | ||
| 559 | log_error "" | ||
| 560 | log_error "Please update --service to use the ngit-grasp archive service." | ||
| 561 | log_error "" | ||
| 562 | log_error "To find the correct service name:" | ||
| 563 | log_error " systemctl list-units 'ngit-grasp*' --all" | ||
| 564 | log_error "" | ||
| 565 | log_error "Common ngit-grasp service names:" | ||
| 566 | log_error " - ngit-grasp.service" | ||
| 567 | log_error " - ngit-grasp-relay-ngit-dev.service (NixOS multi-instance)" | ||
| 568 | log_error " - ngit-grasp-archive.service" | ||
| 569 | return 1 | ||
| 570 | fi | ||
| 571 | |||
| 572 | # Warn if service name doesn't look like ngit-grasp | ||
| 573 | if [[ "$SERVICE_NAME" != *"ngit-grasp"* && "$SERVICE_NAME" != *"grasp"* ]]; then | ||
| 574 | log_warn "SERVICE_NAME doesn't contain 'ngit-grasp': $SERVICE_NAME" | ||
| 575 | log_warn "Structured logging only exists in ngit-grasp services." | ||
| 576 | log_warn "If this is not an ngit-grasp service, Phase 4 will find no logs." | ||
| 577 | fi | ||
| 578 | |||
| 551 | local cmds=() | 579 | local cmds=() |
| 552 | 580 | ||
| 553 | cmds+=("'$SCRIPT_DIR/30-extract-parse-failures.sh' '$SERVICE_NAME' '$OUTPUT_DIR/logs'") | 581 | cmds+=("'$SCRIPT_DIR/30-extract-parse-failures.sh' '$SERVICE_NAME' '$OUTPUT_DIR/logs'") |
diff --git a/docs/how-to/migration-scripts/validate-service.sh b/docs/how-to/migration-scripts/validate-service.sh new file mode 100755 index 0000000..2525a3f --- /dev/null +++ b/docs/how-to/migration-scripts/validate-service.sh | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | # | ||
| 3 | # validate-service.sh - Validate service name for structured logging | ||
| 4 | # | ||
| 5 | # This helper script validates that a service name is appropriate for | ||
| 6 | # Phase 4 log extraction. Structured logging ([PARSE_FAIL], [PURGATORY_EXPIRED]) | ||
| 7 | # only exists in ngit-grasp services, NOT in ngit-relay services. | ||
| 8 | # | ||
| 9 | # USAGE: | ||
| 10 | # Source this script and call the validation function: | ||
| 11 | # | ||
| 12 | # source validate-service.sh | ||
| 13 | # validate_service_for_structured_logging "$SERVICE_NAME" || exit 1 | ||
| 14 | # | ||
| 15 | # BACKGROUND: | ||
| 16 | # Phase 4 of the migration analysis extracts structured log entries from | ||
| 17 | # journald. These log entries only exist in ngit-grasp services. If you | ||
| 18 | # accidentally specify an ngit-relay service, Phase 4 will find no logs | ||
| 19 | # and produce empty results. | ||
| 20 | # | ||
| 21 | # This validation prevents that common mistake by: | ||
| 22 | # 1. Checking if the service name contains "ngit-relay" (error) | ||
| 23 | # 2. Warning if the service name doesn't contain "ngit-grasp" | ||
| 24 | # 3. Optionally checking if structured logs actually exist | ||
| 25 | # | ||
| 26 | # SEE ALSO: | ||
| 27 | # docs/how-to/migrate-to-ngit-grasp.md - Full migration guide | ||
| 28 | # 30-extract-parse-failures.sh - Uses this validation | ||
| 29 | # 31-extract-purgatory-expiry.sh - Uses this validation | ||
| 30 | # | ||
| 31 | |||
| 32 | # Colors for output (disabled if not a terminal) | ||
| 33 | if [[ -t 1 ]]; then | ||
| 34 | _VS_RED='\033[0;31m' | ||
| 35 | _VS_YELLOW='\033[0;33m' | ||
| 36 | _VS_NC='\033[0m' | ||
| 37 | else | ||
| 38 | _VS_RED='' | ||
| 39 | _VS_YELLOW='' | ||
| 40 | _VS_NC='' | ||
| 41 | fi | ||
| 42 | |||
| 43 | # Validates that the service name is appropriate for structured logging | ||
| 44 | # | ||
| 45 | # Arguments: | ||
| 46 | # $1 - service_name: The systemd service name to validate | ||
| 47 | # $2 - check_logs: Whether to check if logs actually exist (default: "true") | ||
| 48 | # $3 - interactive: Whether to prompt for confirmation (default: "true") | ||
| 49 | # | ||
| 50 | # Returns: | ||
| 51 | # 0 - Service is valid for structured logging | ||
| 52 | # 1 - Service is invalid or user declined to continue | ||
| 53 | # | ||
| 54 | # Example: | ||
| 55 | # validate_service_for_structured_logging "ngit-grasp.service" || exit 1 | ||
| 56 | # validate_service_for_structured_logging "ngit-grasp.service" "false" # Skip log check | ||
| 57 | # validate_service_for_structured_logging "ngit-grasp.service" "true" "false" # Non-interactive | ||
| 58 | # | ||
| 59 | validate_service_for_structured_logging() { | ||
| 60 | local service_name="$1" | ||
| 61 | local check_logs="${2:-true}" | ||
| 62 | local interactive="${3:-true}" | ||
| 63 | |||
| 64 | # Check if service name looks like ngit-relay (ERROR - wrong service type) | ||
| 65 | if [[ "$service_name" == *"ngit-relay"* ]]; then | ||
| 66 | echo -e "${_VS_RED}ERROR: Service name appears to be ngit-relay: $service_name${_VS_NC}" >&2 | ||
| 67 | echo "" >&2 | ||
| 68 | echo "Structured logging ([PARSE_FAIL], [PURGATORY_EXPIRED]) only exists in" >&2 | ||
| 69 | echo "ngit-grasp services, NOT in ngit-relay services." >&2 | ||
| 70 | echo "" >&2 | ||
| 71 | echo "Please use the ngit-grasp archive service instead." >&2 | ||
| 72 | echo "" >&2 | ||
| 73 | echo "To find the correct service name:" >&2 | ||
| 74 | echo " systemctl list-units 'ngit-grasp*' --all" >&2 | ||
| 75 | echo "" >&2 | ||
| 76 | echo "Common ngit-grasp service names:" >&2 | ||
| 77 | echo " - ngit-grasp.service" >&2 | ||
| 78 | echo " - ngit-grasp-relay-ngit-dev.service (NixOS multi-instance)" >&2 | ||
| 79 | echo " - ngit-grasp-archive.service" >&2 | ||
| 80 | return 1 | ||
| 81 | fi | ||
| 82 | |||
| 83 | # Check if service name looks like ngit-grasp (WARNING if not) | ||
| 84 | if [[ "$service_name" != *"ngit-grasp"* && "$service_name" != *"grasp"* ]]; then | ||
| 85 | echo -e "${_VS_YELLOW}WARNING: Service name doesn't contain 'ngit-grasp': $service_name${_VS_NC}" >&2 | ||
| 86 | echo "" >&2 | ||
| 87 | echo "Structured logging ([PARSE_FAIL], [PURGATORY_EXPIRED]) only exists in" >&2 | ||
| 88 | echo "ngit-grasp services." >&2 | ||
| 89 | echo "" >&2 | ||
| 90 | |||
| 91 | if [[ "$interactive" == "true" ]]; then | ||
| 92 | read -p "Continue anyway? (y/N) " -n 1 -r | ||
| 93 | echo | ||
| 94 | if [[ ! $REPLY =~ ^[Yy]$ ]]; then | ||
| 95 | return 1 | ||
| 96 | fi | ||
| 97 | else | ||
| 98 | echo "Non-interactive mode: proceeding despite warning" >&2 | ||
| 99 | fi | ||
| 100 | fi | ||
| 101 | |||
| 102 | # Optionally check if structured logs actually exist | ||
| 103 | if [[ "$check_logs" == "true" ]]; then | ||
| 104 | # Check if journalctl is available | ||
| 105 | if ! command -v journalctl &> /dev/null; then | ||
| 106 | echo -e "${_VS_YELLOW}WARNING: journalctl not available, cannot verify logs exist${_VS_NC}" >&2 | ||
| 107 | return 0 | ||
| 108 | fi | ||
| 109 | |||
| 110 | # Check for structured log entries | ||
| 111 | local has_parse_fail has_purgatory | ||
| 112 | has_parse_fail=$(journalctl -u "$service_name" --since "7 days ago" 2>/dev/null | grep -c '\[PARSE_FAIL\]' || echo "0") | ||
| 113 | has_purgatory=$(journalctl -u "$service_name" --since "7 days ago" 2>/dev/null | grep -c '\[PURGATORY_EXPIRED\]' || echo "0") | ||
| 114 | |||
| 115 | # Strip any non-numeric characters (grep -c can have trailing whitespace) | ||
| 116 | has_parse_fail="${has_parse_fail//[^0-9]/}" | ||
| 117 | has_purgatory="${has_purgatory//[^0-9]/}" | ||
| 118 | has_parse_fail="${has_parse_fail:-0}" | ||
| 119 | has_purgatory="${has_purgatory:-0}" | ||
| 120 | |||
| 121 | if [[ "$has_parse_fail" -eq 0 && "$has_purgatory" -eq 0 ]]; then | ||
| 122 | echo -e "${_VS_YELLOW}WARNING: No structured logs found in $service_name (last 7 days)${_VS_NC}" >&2 | ||
| 123 | echo "" >&2 | ||
| 124 | echo "This may indicate:" >&2 | ||
| 125 | echo " 1. Wrong service (should be ngit-grasp archive service, not ngit-relay)" >&2 | ||
| 126 | echo " 2. Structured logging not yet deployed to this ngit-grasp instance" >&2 | ||
| 127 | echo " 3. No parse failures or purgatory expiry events in the time window" >&2 | ||
| 128 | echo "" >&2 | ||
| 129 | echo "To verify you have the right service:" >&2 | ||
| 130 | echo " systemctl list-units 'ngit-grasp*' --all" >&2 | ||
| 131 | echo " journalctl -u <service> | grep -E '\\[PARSE_FAIL\\]|\\[PURGATORY_EXPIRED\\]' | head -5" >&2 | ||
| 132 | echo "" >&2 | ||
| 133 | |||
| 134 | if [[ "$interactive" == "true" ]]; then | ||
| 135 | read -p "Continue anyway? (y/N) " -n 1 -r | ||
| 136 | echo | ||
| 137 | if [[ ! $REPLY =~ ^[Yy]$ ]]; then | ||
| 138 | return 1 | ||
| 139 | fi | ||
| 140 | else | ||
| 141 | echo "Non-interactive mode: proceeding despite warning" >&2 | ||
| 142 | fi | ||
| 143 | fi | ||
| 144 | fi | ||
| 145 | |||
| 146 | return 0 | ||
| 147 | } | ||
| 148 | |||
| 149 | # Export the function so it can be used after sourcing | ||
| 150 | export -f validate_service_for_structured_logging | ||