utils_devops 0.1.139__tar.gz → 0.1.140__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {utils_devops-0.1.139 → utils_devops-0.1.140}/PKG-INFO +1 -1
  2. {utils_devops-0.1.139 → utils_devops-0.1.140}/pyproject.toml +1 -1
  3. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/docker_ops.py +52 -60
  4. {utils_devops-0.1.139 → utils_devops-0.1.140}/README.md +0 -0
  5. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/__init__.py +0 -0
  6. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/core/__init__.py +0 -0
  7. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/core/datetimes.py +0 -0
  8. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/core/envs.py +0 -0
  9. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/core/files.py +0 -0
  10. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/core/logs.py +0 -0
  11. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/core/script_helpers.py +0 -0
  12. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/core/strings.py +0 -0
  13. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/core/systems.py +0 -0
  14. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/__init__.py +0 -0
  15. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/aws_ops.py +0 -0
  16. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/git_ops.py +0 -0
  17. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/interaction_ops.py +0 -0
  18. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/metrics_ops.py +0 -0
  19. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/network_ops.py +0 -0
  20. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/nginx_ops.py +0 -0
  21. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/notification_ops.py +0 -0
  22. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/performance_ops.py +0 -0
  23. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/ssh_ops.py +0 -0
  24. {utils_devops-0.1.139 → utils_devops-0.1.140}/src/utils_devops/extras/vault_ops.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: utils_devops
3
- Version: 0.1.139
3
+ Version: 0.1.140
4
4
  Summary: Lightweight DevOps utilities for automation scripts: config editing (YAML/JSON/INI/.env), templating, diffing, and CLI tools
5
5
  License: MIT
6
6
  Keywords: devops,automation,nginx,cli,jinja2,yaml,config,diff,templating,logging,docker,compose,file-ops
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "utils_devops"
3
- version = "0.1.139" # Bumped for new string features + diffing
3
+ version = "0.1.140" # Bumped for new string features + diffing
4
4
  description = "Lightweight DevOps utilities for automation scripts: config editing (YAML/JSON/INI/.env), templating, diffing, and CLI tools"
5
5
  authors = ["Hamed Sheikhan <sh.sheikhan.m@gmail.com>"]
6
6
  license = "MIT"
@@ -767,75 +767,67 @@ def check_service_health(compose_file: str, service: str,
767
767
  logger.error(f"Error checking health for {service}: {e}")
768
768
  return {"healthy": False, "error": str(e)}
769
769
 
770
- def wait_for_healthy(compose_file: str, services: Optional[List[str]] = None,
771
- timeout: int = 300, interval: int = 5, logger: Optional[Logger] = None,env_file: Optional[str] = None) -> bool:
772
- """Wait for services to become healthy - ENHANCED LOGGING VERSION"""
773
- # Use parent function's logger if provided, otherwise get default
774
- logger = logger or DEFAULT_LOGGER
775
-
770
+ import time
771
+ from collections import defaultdict
772
+
773
+ def wait_for_healthy(
774
+ compose_file: str,
775
+ services: List[str],
776
+ timeout: int,
777
+ interval: int,
778
+ logger: logger,
779
+ env_file: Optional[str] = None
780
+ ) -> bool:
781
+ """Wait for services to become healthy with detailed status logging."""
776
782
  start_time = time.time()
777
- services_to_check = services or get_services_from_compose(compose_file , env_file)
783
+ attempt = 1
778
784
 
779
- logger.info(f"🩺 Starting health checks for {len(services_to_check)} services: {services_to_check}")
780
- logger.info(f"⏰ Timeout: {timeout}s, Check interval: {interval}s")
781
-
782
- attempt = 0
783
785
  while time.time() - start_time < timeout:
784
- attempt += 1
785
786
  elapsed = time.time() - start_time
786
- time_remaining = timeout - elapsed
787
-
788
- all_healthy = True
789
- unhealthy_services = []
790
- healthy_services = []
791
-
792
- # Check each service
793
- for service in services_to_check:
794
- health_result = check_service_health(compose_file, service)
795
- is_healthy = health_result.get('healthy', False)
796
-
797
- if is_healthy:
798
- healthy_services.append(service)
787
+ remaining = timeout - elapsed
788
+ logger.info(f"🔍 Health check attempt {attempt} ({elapsed:.1f}s elapsed, {remaining:.1f}s remaining):")
789
+
790
+ # Get detailed health status
791
+ detailed_health = _get_detailed_health_status(compose_file, services, logger)
792
+
793
+ # Group services by overall_status
794
+ status_groups = defaultdict(list)
795
+ for service, status in detailed_health.items():
796
+ overall = status['overall_status']
797
+ if overall == 'healthy':
798
+ status_groups[overall].append(service)
799
799
  else:
800
- all_healthy = False
801
- unhealthy_services.append({
802
- 'service': service,
803
- 'status': health_result.get('status', 'unknown'),
804
- 'error': health_result.get('error', 'No error details')
805
- })
806
-
807
- # Log detailed status for each attempt
808
- logger.info(f"🔍 Health check attempt {attempt} ({elapsed:.1f}s elapsed, {time_remaining:.1f}s remaining):")
809
- logger.info(f" ✅ Healthy ({len(healthy_services)}): {healthy_services}")
810
-
811
- if unhealthy_services:
812
- logger.info(f" Unhealthy ({len(unhealthy_services)}):")
813
- for us in unhealthy_services:
814
- logger.info(f" - {us['service']}: {us['status']} | Error: {us['error']}")
800
+ detail = f"{service}: {status['status']} (health: {status['health']}) | Error: {status['error']}"
801
+ status_groups[overall].append(detail)
802
+
803
+ # Define order and emojis
804
+ statuses = ['healthy', 'starting', 'restarting', 'unhealthy', 'not found']
805
+ emojis = {'healthy': '✅', 'starting': '🚀', 'restarting': '🔄', 'unhealthy': '❌', 'not found': '❓'}
806
+
807
+ # Log groups if they have items
808
+ for status in statuses:
809
+ group = status_groups[status]
810
+ if group:
811
+ emoji = emojis[status]
812
+ logger.info(f" {emoji} {status.capitalize()} ({len(group)}):")
813
+ if status == 'healthy':
814
+ logger.info(f" {sorted(group)}")
815
+ else:
816
+ for detail in sorted(group):
817
+ logger.info(f" - {detail}")
815
818
 
816
- if all_healthy:
817
- total_time = time.time() - start_time
818
- logger.info(f"🎉 ALL SERVICES HEALTHY! Completed in {total_time:.1f}s after {attempt} attempts")
819
+ # Check if all healthy
820
+ if len(status_groups['healthy']) == len(services):
821
+ logger.info(f"🎉 ALL SERVICES HEALTHY! Completed in {elapsed:.1f}s after {attempt} attempts")
819
822
  return True
820
823
 
821
- # Wait before next check
822
- if time_remaining > interval:
823
- logger.info(f"⏳ Waiting {interval}s before next health check...")
824
- dt_ops.time.sleep(interval)
825
- else:
826
- # Don't sleep if we're about to timeout
827
- break
828
-
829
- # Timeout reached
830
- elapsed = time.time() - start_time
831
- logger.error(f"⏰ HEALTH CHECK TIMEOUT after {elapsed:.1f}s and {attempt} attempts!")
832
- logger.error(f"💔 Final status - Healthy: {len(healthy_services)}, Unhealthy: {len(unhealthy_services)}")
833
-
834
- if unhealthy_services:
835
- logger.error("📋 Unhealthy services details:")
836
- for us in unhealthy_services:
837
- logger.error(f" - {us['service']}: {us['status']} | {us['error']}")
824
+ # Wait for next attempt
825
+ logger.info(f"⏳ Waiting {interval}s before next health check...")
826
+ time.sleep(interval)
827
+ attempt += 1
838
828
 
829
+ # Timeout
830
+ logger.error(f"❌ Health check timeout after {time.time() - start_time:.1f}s")
839
831
  return False
840
832
 
841
833
  def health_check_docker_compose(compose_file: str) -> bool:
File without changes