find_volumes2.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import os
  2. import yaml
  3. import csv
  4. from dotenv import load_dotenv
  5. def load_env_vars(env_file):
  6. """Load environment variables from a .env file."""
  7. if os.path.exists(env_file):
  8. load_dotenv(env_file)
  9. def expand_env_vars(value):
  10. """Expand environment variables in a string."""
  11. return os.path.expandvars(value)
  12. def parse_docker_compose(file_path):
  13. """Parse a docker-compose.yml file and extract volume information."""
  14. with open(file_path, 'r') as file:
  15. compose_data = yaml.safe_load(file)
  16. volumes = []
  17. if compose_data and 'services' in compose_data:
  18. for service_name, service_config in compose_data['services'].items():
  19. if 'volumes' in service_config:
  20. for volume in service_config['volumes']:
  21. if isinstance(volume, str):
  22. # Handle string format: "host_path:container_path"
  23. parts = volume.split(':')
  24. if len(parts) == 2:
  25. host_path, container_path = parts
  26. volumes.append((host_path, container_path))
  27. elif len(parts) == 3:
  28. # Handle cases like "host_path:container_path:ro"
  29. host_path, container_path, _ = parts
  30. volumes.append((host_path, container_path))
  31. elif isinstance(volume, dict):
  32. # Handle dictionary format: { 'source': 'host_path', 'target': 'container_path' }
  33. if 'source' in volume and 'target' in volume:
  34. volumes.append((volume['source'], volume['target']))
  35. return volumes
  36. def get_volume_type(host_path):
  37. """Determine if the volume is a bind mount or a named volume."""
  38. if host_path.startswith(('.', '/', '~')) or '${' in host_path:
  39. return "bind"
  40. else:
  41. return "named"
  42. def traverse_directory(root_dir):
  43. """Traverse the directory and find all docker-compose.yml files."""
  44. results = []
  45. for dirpath, _, filenames in os.walk(root_dir):
  46. if 'docker-compose.yml' in filenames:
  47. compose_file = os.path.join(dirpath, 'docker-compose.yml')
  48. env_file = os.path.join(dirpath, '.env')
  49. load_env_vars(env_file)
  50. volumes = parse_docker_compose(compose_file)
  51. for host_path, container_path in volumes:
  52. expanded_host_path = expand_env_vars(host_path)
  53. volume_type = get_volume_type(expanded_host_path)
  54. results.append((dirpath, expanded_host_path, container_path, volume_type))
  55. return results
  56. def write_to_csv(data, output_file):
  57. """Write the volume data to a CSV file."""
  58. headers = ["Directory", "Volume (Host Path)", "Bind Point (Container Path)", "Volume Type"]
  59. with open(output_file, mode='w', newline='') as file:
  60. writer = csv.writer(file)
  61. writer.writerow(headers) # Write the header row
  62. writer.writerows(data) # Write the data rows
  63. def main():
  64. root_directory = input("Enter the root directory to traverse: ")
  65. if not os.path.isdir(root_directory):
  66. print("Invalid directory path.")
  67. return
  68. output_csv = input("Enter the output CSV file path (e.g., output.csv): ")
  69. # Traverse the directory and get volume information
  70. volume_data = traverse_directory(root_directory)
  71. # Write the results to a CSV file
  72. if volume_data:
  73. write_to_csv(volume_data, output_csv)
  74. print(f"Volume data has been written to {output_csv}")
  75. else:
  76. print("No docker-compose.yml files with volumes found.")
  77. if __name__ == "__main__":
  78. main()