Skip to content

Commit 19f458a

Browse files
Create devcontainer virtual environment during prebuild
1 parent 48d3232 commit 19f458a

File tree

4 files changed

+166
-23
lines changed

4 files changed

+166
-23
lines changed

.devcontainer/devcontainer.json

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,19 @@
3838
"ms-vscode.vscode-json"
3939
],
4040
"settings": {
41-
"python.defaultInterpreterPath": "/usr/local/bin/python",
41+
"python.defaultInterpreterPath": "/opt/venv/bin/python",
4242
"python.linting.enabled": true,
4343
"python.linting.pylintEnabled": true,
44-
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
45-
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
46-
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
47-
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
48-
"python.linting.flake8Path": "/usr/local/py-utils/bin/flake8",
49-
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
50-
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
51-
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
52-
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint",
53-
"python.testing.pytestPath": "/usr/local/py-utils/bin/pytest",
44+
"python.formatting.autopep8Path": "/opt/venv/bin/autopep8",
45+
"python.formatting.blackPath": "/opt/venv/bin/black",
46+
"python.formatting.yapfPath": "/opt/venv/bin/yapf",
47+
"python.linting.banditPath": "/opt/venv/bin/bandit",
48+
"python.linting.flake8Path": "/opt/venv/bin/flake8",
49+
"python.linting.mypyPath": "/opt/venv/bin/mypy",
50+
"python.linting.pycodestylePath": "/opt/venv/bin/pycodestyle",
51+
"python.linting.pydocstylePath": "/opt/venv/bin/pydocestyle",
52+
"python.linting.pylintPath": "/opt/venv/bin/pylint",
53+
"python.testing.pytestPath": "/opt/venv/bin/pytest",
5454
"jupyter.askForKernelRestart": false,
5555
"jupyter.interactiveWindow.textEditor.executeSelection": true,
5656
"files.associations": {
@@ -60,9 +60,11 @@
6060
}
6161
},
6262
"containerEnv": {
63-
"PYTHONPATH": "/workspaces/Apim-Samples/shared/python:/workspaces/Apim-Samples"
63+
"PYTHONPATH": "/workspaces/Apim-Samples/shared/python:/workspaces/Apim-Samples",
64+
"VIRTUAL_ENV": "/opt/venv",
65+
"PATH": "/opt/venv/bin:${containerEnv:PATH}"
6466
},
65-
"onCreateCommand": "bash .devcontainer/setup-prebuild.sh",
67+
"postCreateCommand": "bash .devcontainer/setup-prebuild.sh",
6668
"postStartCommand": "bash .devcontainer/post-start.sh",
6769
"forwardPorts": [
6870
8000,

.devcontainer/post-start.sh

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ fi
4242
# ------------------------------
4343

4444
echo "✅ Verifying Python environment..."
45+
source /opt/venv/bin/activate
4546
python --version
4647

4748
echo ""
@@ -72,20 +73,23 @@ echo ""
7273
# NEXT STEPS GUIDANCE
7374
# ------------------------------
7475

76+
echo ""
77+
echo "==================================================================================================="
78+
echo ""
7579
echo "📋 Next steps:"
7680
echo ""
7781
if [ -f ".devcontainer/devcontainer.json" ] && grep -q '"mounts"' .devcontainer/devcontainer.json; then
7882
echo " ✅ Azure CLI config mounting detected - your authentication should be available"
7983
echo ""
80-
echo "1. Verify Azure access and ensure correct tenant/subscription: az account show"
81-
echo "2. If needed, switch tenant: az login --tenant <your-tenant-id-or-domain>"
82-
echo "3. If needed, set subscription: az account set --subscription <your-subscription-id-or-name>"
84+
echo "1. Verify Azure correct tenant/subscription : az account show"
85+
echo "2. If needed, switch tenant : az login --tenant <your-tenant-id-or-domain>"
86+
echo "3. If needed, set subscription : az account set --subscription <your-subscription-id-or-name>"
8387
echo "4. Execute shared/jupyter/verify-az-account.ipynb to verify your Azure setup"
8488
else
8589
echo ""
86-
echo "1. Sign in to your specific Azure tenant: az login --tenant <your-tenant-id-or-domain>"
87-
echo "2. Set your target subscription: az account set --subscription <your-subscription-id-or-name>"
88-
echo "3. Verify your context: az account show"
90+
echo "1. Sign in to your specific Azure tenant : az login --tenant <your-tenant-id-or-domain>"
91+
echo "2. Set your target subscription : az account set --subscription <your-subscription-id-or-name>"
92+
echo "3. Verify your context : az account show"
8993
echo "4. Execute shared/jupyter/verify-az-account.ipynb to verify your Azure setup"
9094
fi
9195
echo "5. Navigate to any infrastructure folder and run the create.ipynb notebook"

.devcontainer/setup-prebuild.sh

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,46 @@ set -e
88

99
echo "🔧 Running prebuild-optimized setup..."
1010

11+
# Ensure we have proper permissions and environment
12+
export DEBIAN_FRONTEND=noninteractive
13+
1114
# ------------------------------
1215
# PYTHON ENVIRONMENT SETUP
1316
# ------------------------------
1417

15-
echo "📦 Installing Python dependencies..."
16-
pip install --upgrade pip
18+
echo "📦 Setting up Python virtual environment..."
19+
# Create virtual environment with proper permissions
20+
sudo mkdir -p /opt/venv
21+
sudo chown vscode:vscode /opt/venv
22+
23+
# Switch to vscode user for virtual environment creation
24+
sudo -u vscode bash << 'VENV_SETUP'
25+
set -e
26+
python -m venv /opt/venv
27+
source /opt/venv/bin/activate
28+
29+
echo "📦 Installing Python dependencies in virtual environment..."
30+
pip install --upgrade pip setuptools wheel
1731
pip install -r requirements.txt
1832
1933
# Ensure pytest and coverage tools are available
2034
pip install pytest pytest-cov coverage
2135
36+
echo "✅ Virtual environment setup complete"
37+
VENV_SETUP
38+
39+
# Activate virtual environment for the rest of the setup
40+
source /opt/venv/bin/activate
41+
42+
# Make virtual environment available system-wide for the vscode user
43+
echo 'source /opt/venv/bin/activate' >> /home/vscode/.bashrc
44+
echo 'source /opt/venv/bin/activate' >> /home/vscode/.zshrc
45+
46+
# Set ownership to vscode user (just to be sure)
47+
sudo chown -R vscode:vscode /opt/venv
48+
2249
echo "🔧 Setting up Python path configuration..."
50+
source /opt/venv/bin/activate
2351
python setup/setup_python_path.py --generate-env
2452

2553
# ------------------------------
@@ -40,6 +68,7 @@ az extension add --name front-door --only-show-errors 2>/dev/null || true
4068
# ------------------------------
4169

4270
echo "📓 Setting up Jupyter environment..."
71+
source /opt/venv/bin/activate
4372
# Install Jupyter kernel (with error handling)
4473
if python -c "import ipykernel" 2>/dev/null; then
4574
python -m ipykernel install --user --name=apim-samples --display-name="APIM Samples Python" || echo "⚠️ Warning: Failed to install Jupyter kernel, but continuing..."
@@ -62,13 +91,13 @@ mkdir -p .vscode
6291
cat > .vscode/settings.json << 'EOF'
6392
{
6493
"python.terminal.activateEnvironment": true,
65-
"python.defaultInterpreterPath": "/usr/local/bin/python",
94+
"python.defaultInterpreterPath": "/opt/venv/bin/python",
6695
"python.analysis.extraPaths": [
6796
"/workspaces/Apim-Samples/shared/python"
6897
],
6998
"jupyter.kernels.filter": [
7099
{
71-
"path": "/usr/local/bin/python",
100+
"path": "/opt/venv/bin/python",
72101
"type": "pythonEnvironment"
73102
}
74103
],
@@ -89,9 +118,23 @@ echo "$(date): Prebuild setup completed" > .devcontainer/.prebuild-complete
89118
echo "🎉 Prebuild setup complete!"
90119

91120
echo "✅ Verifying installation..."
121+
source /opt/venv/bin/activate
92122
echo "Python version: $(python --version)"
93123
echo "Azure CLI version: $(az --version | head -1)"
94124
echo "Pip packages installed:"
95125
pip list | grep -E "(requests|pandas|matplotlib|pytest|azure|jwt|jupyter|ipykernel)" || true
96126

127+
echo ""
128+
echo "🔍 Running comprehensive verification..."
129+
if python .devcontainer/verify-venv.py; then
130+
echo "✅ Virtual environment verification passed!"
131+
else
132+
echo "⚠️ Virtual environment verification had issues - but continuing..."
133+
fi
134+
97135
echo "📋 Prebuild optimization complete!"
136+
echo ""
137+
echo "🎯 Next container start should be significantly faster!"
138+
echo " - Virtual environment: /opt/venv"
139+
echo " - All packages pre-installed"
140+
echo " - Ready for immediate development"

.devcontainer/verify-venv.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Verification script to ensure virtual environment and packages are properly installed.
4+
"""
5+
import sys
6+
import subprocess
7+
import importlib
8+
9+
# ------------------------------
10+
# CONSTANTS
11+
# ------------------------------
12+
13+
REQUIRED_PACKAGES = [
14+
'requests',
15+
'setuptools',
16+
'pandas',
17+
'matplotlib',
18+
'jwt',
19+
'pytest',
20+
'azure.storage.blob',
21+
'azure.identity',
22+
'jupyter',
23+
'ipykernel',
24+
'notebook'
25+
]
26+
27+
# ------------------------------
28+
# PUBLIC METHODS
29+
# ------------------------------
30+
31+
def check_virtual_environment():
32+
"""Check if we're running in the expected virtual environment."""
33+
expected_venv = '/opt/venv'
34+
current_prefix = sys.prefix
35+
36+
if expected_venv in current_prefix:
37+
print(f"✅ Running in virtual environment: {current_prefix}")
38+
return True
39+
else:
40+
print(f"❌ Not running in expected virtual environment. Current: {current_prefix}")
41+
return False
42+
43+
def check_package_imports():
44+
"""Check if all required packages can be imported."""
45+
failed_imports = []
46+
47+
for package in REQUIRED_PACKAGES:
48+
try:
49+
importlib.import_module(package)
50+
print(f"✅ {package}")
51+
except ImportError:
52+
print(f"❌ {package}")
53+
failed_imports.append(package)
54+
55+
return len(failed_imports) == 0
56+
57+
def check_executables():
58+
"""Check if Python executables are correctly configured."""
59+
try:
60+
python_path = subprocess.check_output(['which', 'python'], text=True).strip()
61+
pip_path = subprocess.check_output(['which', 'pip'], text=True).strip()
62+
63+
print(f"✅ Python executable: {python_path}")
64+
print(f"✅ Pip executable: {pip_path}")
65+
66+
expected_venv = '/opt/venv'
67+
return expected_venv in python_path and expected_venv in pip_path
68+
except subprocess.CalledProcessError:
69+
print("❌ Failed to locate Python or pip executables")
70+
return False
71+
72+
def main():
73+
"""Main verification function."""
74+
print("🔍 Verifying virtual environment setup...\n")
75+
76+
checks = [
77+
("Virtual Environment", check_virtual_environment),
78+
("Package Imports", check_package_imports),
79+
("Executables", check_executables)
80+
]
81+
82+
all_passed = True
83+
84+
for check_name, check_func in checks:
85+
print(f"\n📋 {check_name} Check:")
86+
if not check_func():
87+
all_passed = False
88+
89+
print(f"\n{'✅ All checks passed!' if all_passed else '❌ Some checks failed!'}")
90+
91+
return 0 if all_passed else 1
92+
93+
if __name__ == "__main__":
94+
sys.exit(main())

0 commit comments

Comments
 (0)