|
| 1 | +#!/usr/bin/env python3 |
| 2 | +""" |
| 3 | +APIM Samples Dev Container Verification Script |
| 4 | +============================================== |
| 5 | +
|
| 6 | +This script verifies that the dev container is properly configured for |
| 7 | +Azure API Management development work. It checks: |
| 8 | +
|
| 9 | +1. Python virtual environment setup |
| 10 | +2. Required packages installation |
| 11 | +3. Jupyter kernel configuration |
| 12 | +4. VS Code integration |
| 13 | +5. Environment file generation |
| 14 | +6. Azure CLI setup |
| 15 | +
|
| 16 | +Run this script inside the dev container to verify everything is working. |
| 17 | +""" |
| 18 | + |
| 19 | +import os |
| 20 | +import sys |
| 21 | +import subprocess |
| 22 | +import json |
| 23 | +from pathlib import Path |
| 24 | + |
| 25 | +def print_section(title): |
| 26 | + """Print a formatted section header.""" |
| 27 | + print(f"\n{'='*50}") |
| 28 | + print(f"🔍 {title}") |
| 29 | + print('='*50) |
| 30 | + |
| 31 | +def check_mark(condition, success_msg, failure_msg): |
| 32 | + """Print a check mark or X based on condition.""" |
| 33 | + if condition: |
| 34 | + print(f"✅ {success_msg}") |
| 35 | + return True |
| 36 | + else: |
| 37 | + print(f"❌ {failure_msg}") |
| 38 | + return False |
| 39 | + |
| 40 | +def warning_mark(condition, success_msg, warning_msg): |
| 41 | + """Print a check mark or warning based on condition.""" |
| 42 | + if condition: |
| 43 | + print(f"✅ {success_msg}") |
| 44 | + return True |
| 45 | + else: |
| 46 | + print(f"⚠️ {warning_msg}") |
| 47 | + return False |
| 48 | + |
| 49 | +def main(): |
| 50 | + print("🚀 APIM Samples Dev Container Verification") |
| 51 | + print("==========================================") |
| 52 | + |
| 53 | + issues = [] |
| 54 | + |
| 55 | + # 1. Check Python environment |
| 56 | + print_section("Python Virtual Environment") |
| 57 | + |
| 58 | + # Check Python version |
| 59 | + python_version = sys.version_info |
| 60 | + if not check_mark( |
| 61 | + python_version.major == 3 and python_version.minor >= 10, |
| 62 | + f"Python {python_version.major}.{python_version.minor}.{python_version.micro}", |
| 63 | + f"Python version should be 3.10+ (got {python_version.major}.{python_version.minor}.{python_version.micro})" |
| 64 | + ): |
| 65 | + issues.append("Python version") |
| 66 | + |
| 67 | + # Check virtual environment |
| 68 | + venv_path = os.environ.get('VIRTUAL_ENV') |
| 69 | + expected_venv = '/workspaces/Apim-Samples/.venv' |
| 70 | + if not check_mark( |
| 71 | + venv_path and venv_path == expected_venv, |
| 72 | + f"Virtual environment: {venv_path}", |
| 73 | + f"Expected virtual environment at {expected_venv}, got {venv_path}" |
| 74 | + ): |
| 75 | + issues.append("Virtual environment path") |
| 76 | + |
| 77 | + # Check Python executable |
| 78 | + python_exe = sys.executable |
| 79 | + expected_python = '/workspaces/Apim-Samples/.venv/bin/python' |
| 80 | + if not warning_mark( |
| 81 | + expected_python in python_exe, |
| 82 | + f"Python executable: {python_exe}", |
| 83 | + f"Python executable should be in venv: {python_exe}" |
| 84 | + ): |
| 85 | + issues.append("Python executable location") |
| 86 | + |
| 87 | + # 2. Check required packages |
| 88 | + print_section("Required Packages") |
| 89 | + |
| 90 | + required_packages = [ |
| 91 | + 'requests', 'pandas', 'matplotlib', 'jwt', 'azure.identity', |
| 92 | + 'azure.storage.blob', 'pytest', 'jupyter', 'ipykernel' |
| 93 | + ] |
| 94 | + |
| 95 | + missing_packages = [] |
| 96 | + for package in required_packages: |
| 97 | + try: |
| 98 | + __import__(package) |
| 99 | + print(f"✅ {package}") |
| 100 | + except ImportError: |
| 101 | + print(f"❌ {package} (missing)") |
| 102 | + missing_packages.append(package) |
| 103 | + |
| 104 | + if missing_packages: |
| 105 | + issues.append(f"Missing packages: {', '.join(missing_packages)}") |
| 106 | + |
| 107 | + # 3. Check workspace structure |
| 108 | + print_section("Workspace Structure") |
| 109 | + |
| 110 | + workspace_files = [ |
| 111 | + ('/workspaces/Apim-Samples/.venv', 'Virtual environment directory'), |
| 112 | + ('/workspaces/Apim-Samples/.env', 'Environment configuration file'), |
| 113 | + ('/workspaces/Apim-Samples/requirements.txt', 'Requirements file'), |
| 114 | + ('/workspaces/Apim-Samples/shared/python', 'Shared Python modules'), |
| 115 | + ('/workspaces/Apim-Samples/setup/setup_python_path.py', 'Setup script'), |
| 116 | + ] |
| 117 | + |
| 118 | + for file_path, description in workspace_files: |
| 119 | + if not check_mark( |
| 120 | + Path(file_path).exists(), |
| 121 | + f"{description}: {file_path}", |
| 122 | + f"{description} missing: {file_path}" |
| 123 | + ): |
| 124 | + issues.append(f"Missing {description}") |
| 125 | + |
| 126 | + # 4. Check PYTHONPATH |
| 127 | + print_section("Python Path Configuration") |
| 128 | + |
| 129 | + pythonpath = os.environ.get('PYTHONPATH', '') |
| 130 | + expected_paths = ['/workspaces/Apim-Samples/shared/python', '/workspaces/Apim-Samples'] |
| 131 | + |
| 132 | + for path in expected_paths: |
| 133 | + if not warning_mark( |
| 134 | + path in pythonpath, |
| 135 | + f"PYTHONPATH includes: {path}", |
| 136 | + f"PYTHONPATH missing: {path}" |
| 137 | + ): |
| 138 | + issues.append(f"PYTHONPATH configuration") |
| 139 | + |
| 140 | + # 5. Check Jupyter kernel |
| 141 | + print_section("Jupyter Kernel Configuration") |
| 142 | + |
| 143 | + try: |
| 144 | + # List available kernels |
| 145 | + result = subprocess.run(['jupyter', 'kernelspec', 'list', '--json'], |
| 146 | + capture_output=True, text=True, check=True) |
| 147 | + kernels = json.loads(result.stdout) |
| 148 | + |
| 149 | + apim_kernel_found = False |
| 150 | + for kernel_name, kernel_info in kernels.get('kernelspecs', {}).items(): |
| 151 | + if 'apim-samples' in kernel_name.lower(): |
| 152 | + apim_kernel_found = True |
| 153 | + print(f"✅ APIM Samples kernel found: {kernel_name}") |
| 154 | + print(f" Display name: {kernel_info.get('spec', {}).get('display_name', 'N/A')}") |
| 155 | + break |
| 156 | + |
| 157 | + if not apim_kernel_found: |
| 158 | + print("❌ APIM Samples Jupyter kernel not found") |
| 159 | + print(" Available kernels:", list(kernels.get('kernelspecs', {}).keys())) |
| 160 | + issues.append("Jupyter kernel registration") |
| 161 | + |
| 162 | + except (subprocess.CalledProcessError, json.JSONDecodeError, FileNotFoundError) as e: |
| 163 | + print(f"❌ Error checking Jupyter kernels: {e}") |
| 164 | + issues.append("Jupyter kernel check failed") |
| 165 | + |
| 166 | + # 6. Check Azure CLI |
| 167 | + print_section("Azure CLI Configuration") |
| 168 | + |
| 169 | + try: |
| 170 | + result = subprocess.run(['az', '--version'], capture_output=True, text=True, check=True) |
| 171 | + az_version = result.stdout.split('\n')[0] if result.stdout else "Unknown" |
| 172 | + print(f"✅ Azure CLI: {az_version}") |
| 173 | + |
| 174 | + # Check for bicep extension |
| 175 | + result = subprocess.run(['az', 'extension', 'list'], capture_output=True, text=True, check=True) |
| 176 | + extensions = json.loads(result.stdout) |
| 177 | + bicep_installed = any(ext.get('name') == 'bicep' for ext in extensions) |
| 178 | + |
| 179 | + if not warning_mark( |
| 180 | + bicep_installed, |
| 181 | + "Bicep extension installed", |
| 182 | + "Bicep extension not installed (run: az extension add --name bicep)" |
| 183 | + ): |
| 184 | + pass # Not critical |
| 185 | + |
| 186 | + except (subprocess.CalledProcessError, json.JSONDecodeError, FileNotFoundError) as e: |
| 187 | + print(f"❌ Azure CLI error: {e}") |
| 188 | + issues.append("Azure CLI setup") |
| 189 | + |
| 190 | + # 7. Final summary |
| 191 | + print_section("Summary") |
| 192 | + |
| 193 | + if not issues: |
| 194 | + print("🎉 All checks passed! Your dev container is ready for Azure APIM development.") |
| 195 | + print("\nNext steps:") |
| 196 | + print("1. Open a Jupyter notebook and verify the kernel selection") |
| 197 | + print("2. Run 'az login' to authenticate with Azure") |
| 198 | + print("3. Start exploring the APIM samples!") |
| 199 | + return 0 |
| 200 | + else: |
| 201 | + print(f"⚠️ Found {len(issues)} issue(s) that may need attention:") |
| 202 | + for i, issue in enumerate(issues, 1): |
| 203 | + print(f" {i}. {issue}") |
| 204 | + print("\nPlease review the issues above and refer to the dev container documentation.") |
| 205 | + return 1 |
| 206 | + |
| 207 | +if __name__ == '__main__': |
| 208 | + exit(main()) |
0 commit comments