delete(docs) remove infraestructura index duplicates #2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy | |
| on: | |
| push: | |
| branches: | |
| - main | |
| tags: | |
| - 'v*.*.*' | |
| workflow_dispatch: | |
| inputs: | |
| environment: | |
| description: 'Target environment' | |
| required: true | |
| default: 'staging' | |
| type: choice | |
| options: | |
| - staging | |
| - production | |
| skip_tests: | |
| description: 'Skip tests (NOT recommended for production)' | |
| required: false | |
| type: boolean | |
| default: false | |
| jobs: | |
| pre-deployment-checks: | |
| name: Pre-deployment Checks | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Determine target environment | |
| id: env | |
| run: | | |
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | |
| echo "environment=${{ github.event.inputs.environment }}" >> $GITHUB_OUTPUT | |
| elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then | |
| echo "environment=production" >> $GITHUB_OUTPUT | |
| else | |
| echo "environment=staging" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Validate branch/tag | |
| run: | | |
| ENV=${{ steps.env.outputs.environment }} | |
| if [ "$ENV" == "production" ]; then | |
| if [[ ! "${{ github.ref }}" =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "ERROR: Production deployments require a version tag (v*.*.*))" | |
| exit 1 | |
| fi | |
| fi | |
| echo "[PASS] Branch/tag validation passed" | |
| - name: Check for IACT restrictions | |
| run: | | |
| echo "Validating IACT critical restrictions..." | |
| # NO Redis check | |
| if grep -r "redis" api/callcentersite/settings*.py; then | |
| echo "ERROR: Redis detected. Prohibited by RNF-002" | |
| exit 1 | |
| fi | |
| # Session backend check | |
| if ! grep -q "django.contrib.sessions.backends.db" api/callcentersite/settings*.py; then | |
| echo "ERROR: SESSION_ENGINE must be django.contrib.sessions.backends.db" | |
| exit 1 | |
| fi | |
| echo "[PASS] IACT restrictions validated" | |
| - name: Run pre-deployment validations | |
| if: github.event.inputs.skip_tests != 'true' | |
| run: | | |
| if [ -f scripts/validate_critical_restrictions.sh ]; then | |
| bash scripts/validate_critical_restrictions.sh | |
| fi | |
| outputs: | |
| environment: ${{ steps.env.outputs.environment }} | |
| run-tests: | |
| name: Run Full Test Suite | |
| runs-on: ubuntu-latest | |
| needs: pre-deployment-checks | |
| if: github.event.inputs.skip_tests != 'true' | |
| services: | |
| mysql: | |
| image: mysql:8.0 | |
| env: | |
| MYSQL_ROOT_PASSWORD: testpass | |
| MYSQL_DATABASE: test_iact | |
| ports: | |
| - 3306:3306 | |
| options: >- | |
| --health-cmd="mysqladmin ping" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=3 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install dependencies | |
| run: | | |
| pip install -r api/requirements.txt | |
| pip install pytest pytest-django pytest-cov | |
| - name: Run tests with coverage | |
| env: | |
| DB_ENGINE: django.db.backends.mysql | |
| DB_NAME: test_iact | |
| DB_USER: root | |
| DB_PASSWORD: testpass | |
| DB_HOST: 127.0.0.1 | |
| DB_PORT: 3306 | |
| run: | | |
| cd api/callcentersite | |
| python manage.py migrate --run-syncdb | |
| pytest --cov=callcentersite --cov-report=term --cov-fail-under=80 | |
| build-backend: | |
| name: Build Backend | |
| runs-on: ubuntu-latest | |
| needs: [pre-deployment-checks, run-tests] | |
| if: | | |
| always() && | |
| needs.pre-deployment-checks.result == 'success' && | |
| (needs.run-tests.result == 'success' || needs.run-tests.result == 'skipped') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install dependencies | |
| run: | | |
| cd api | |
| pip install -r requirements.txt | |
| - name: Collect static files | |
| run: | | |
| cd api/callcentersite | |
| python manage.py collectstatic --no-input | |
| - name: Create deployment package | |
| run: | | |
| tar -czf backend-deployment.tar.gz api/ | |
| - name: Upload backend artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: backend-deployment | |
| path: backend-deployment.tar.gz | |
| retention-days: 7 | |
| build-frontend: | |
| name: Build Frontend | |
| runs-on: ubuntu-latest | |
| needs: [pre-deployment-checks] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18' | |
| cache: 'npm' | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install dependencies | |
| run: | | |
| cd frontend | |
| npm ci | |
| - name: Build for production | |
| env: | |
| NODE_ENV: production | |
| run: | | |
| cd frontend | |
| npm run build | |
| - name: Create deployment package | |
| run: | | |
| tar -czf frontend-deployment.tar.gz frontend/build/ | |
| - name: Upload frontend artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: frontend-deployment | |
| path: frontend-deployment.tar.gz | |
| retention-days: 7 | |
| deploy-staging: | |
| name: Deploy to Staging | |
| runs-on: ubuntu-latest | |
| needs: [pre-deployment-checks, build-backend, build-frontend] | |
| if: needs.pre-deployment-checks.outputs.environment == 'staging' | |
| environment: | |
| name: staging | |
| url: https://staging.iact.example.com | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download backend artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: backend-deployment | |
| - name: Download frontend artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: frontend-deployment | |
| - name: Deploy to staging server | |
| env: | |
| SSH_PRIVATE_KEY: ${{ secrets.STAGING_SSH_KEY }} | |
| STAGING_HOST: ${{ secrets.STAGING_HOST }} | |
| STAGING_USER: ${{ secrets.STAGING_USER }} | |
| run: | | |
| echo "Deploying to staging environment..." | |
| # Setup SSH | |
| mkdir -p ~/.ssh | |
| echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa | |
| chmod 600 ~/.ssh/id_rsa | |
| ssh-keyscan -H $STAGING_HOST >> ~/.ssh/known_hosts | |
| # Upload deployment packages | |
| scp backend-deployment.tar.gz $STAGING_USER@$STAGING_HOST:/tmp/ | |
| scp frontend-deployment.tar.gz $STAGING_USER@$STAGING_HOST:/tmp/ | |
| # Execute deployment script on remote server | |
| ssh $STAGING_USER@$STAGING_HOST << 'ENDSSH' | |
| set -e | |
| # Backup current deployment | |
| echo "Creating backup..." | |
| sudo cp -r /var/www/iact /var/www/iact_backup_$(date +%Y%m%d_%H%M%S) | |
| # Extract packages | |
| echo "Extracting packages..." | |
| cd /tmp | |
| tar -xzf backend-deployment.tar.gz | |
| tar -xzf frontend-deployment.tar.gz | |
| # Deploy backend | |
| echo "Deploying backend..." | |
| sudo cp -r api/* /var/www/iact/api/ | |
| # Deploy frontend | |
| echo "Deploying frontend..." | |
| sudo cp -r frontend/build/* /var/www/iact/frontend/ | |
| # Run migrations | |
| echo "Running migrations..." | |
| cd /var/www/iact/api/callcentersite | |
| sudo -u www-data python manage.py migrate --no-input | |
| # Restart services | |
| echo "Restarting services..." | |
| sudo systemctl restart gunicorn-iact-staging | |
| sudo systemctl reload nginx | |
| # Health check | |
| echo "Running health check..." | |
| sleep 5 | |
| curl -f http://localhost/api/health || exit 1 | |
| echo "Deployment completed successfully!" | |
| ENDSSH | |
| - name: Verify deployment | |
| run: | | |
| echo "Verifying staging deployment..." | |
| # Wait for service to stabilize | |
| sleep 10 | |
| # Check health endpoint | |
| curl -f https://staging.iact.example.com/api/health || exit 1 | |
| echo "[PASS] Staging deployment verified" | |
| deploy-production: | |
| name: Deploy to Production | |
| runs-on: ubuntu-latest | |
| needs: [pre-deployment-checks, build-backend, build-frontend] | |
| if: needs.pre-deployment-checks.outputs.environment == 'production' | |
| environment: | |
| name: production | |
| url: https://iact.example.com | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download backend artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: backend-deployment | |
| - name: Download frontend artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: frontend-deployment | |
| - name: Create database backup | |
| env: | |
| SSH_PRIVATE_KEY: ${{ secrets.PRODUCTION_SSH_KEY }} | |
| PRODUCTION_HOST: ${{ secrets.PRODUCTION_HOST }} | |
| PRODUCTION_USER: ${{ secrets.PRODUCTION_USER }} | |
| run: | | |
| echo "Creating production database backup..." | |
| mkdir -p ~/.ssh | |
| echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa | |
| chmod 600 ~/.ssh/id_rsa | |
| ssh-keyscan -H $PRODUCTION_HOST >> ~/.ssh/known_hosts | |
| ssh $PRODUCTION_USER@$PRODUCTION_HOST << 'ENDSSH' | |
| mysqldump -u root -p$DB_PASSWORD iact_production > /backup/iact_production_$(date +%Y%m%d_%H%M%S).sql | |
| echo "[PASS] Database backup created" | |
| ENDSSH | |
| - name: Blue-Green Deployment | |
| env: | |
| SSH_PRIVATE_KEY: ${{ secrets.PRODUCTION_SSH_KEY }} | |
| PRODUCTION_HOST: ${{ secrets.PRODUCTION_HOST }} | |
| PRODUCTION_USER: ${{ secrets.PRODUCTION_USER }} | |
| run: | | |
| echo "Executing blue-green deployment to production..." | |
| # Upload deployment packages | |
| scp backend-deployment.tar.gz $PRODUCTION_USER@$PRODUCTION_HOST:/tmp/ | |
| scp frontend-deployment.tar.gz $PRODUCTION_USER@$PRODUCTION_HOST:/tmp/ | |
| # Execute blue-green deployment | |
| ssh $PRODUCTION_USER@$PRODUCTION_HOST << 'ENDSSH' | |
| set -e | |
| # Determine current and new environments | |
| if [ -L /var/www/iact-current ] && [ "$(readlink /var/www/iact-current)" == "/var/www/iact-blue" ]; then | |
| CURRENT="blue" | |
| NEW="green" | |
| else | |
| CURRENT="green" | |
| NEW="blue" | |
| fi | |
| echo "Current: $CURRENT, Deploying to: $NEW" | |
| # Prepare new environment | |
| echo "Preparing $NEW environment..." | |
| sudo mkdir -p /var/www/iact-$NEW | |
| cd /tmp | |
| tar -xzf backend-deployment.tar.gz | |
| tar -xzf frontend-deployment.tar.gz | |
| sudo cp -r api/* /var/www/iact-$NEW/api/ | |
| sudo cp -r frontend/build/* /var/www/iact-$NEW/frontend/ | |
| # Run migrations on new environment | |
| echo "Running migrations..." | |
| cd /var/www/iact-$NEW/api/callcentersite | |
| sudo -u www-data python manage.py migrate --no-input | |
| # Start new environment | |
| echo "Starting $NEW environment..." | |
| sudo systemctl start gunicorn-iact-$NEW | |
| # Health check on new environment | |
| echo "Health check on $NEW environment..." | |
| sleep 10 | |
| curl -f http://localhost:800$([[ "$NEW" == "green" ]] && echo 1 || echo 0)/api/health || exit 1 | |
| # Switch traffic to new environment | |
| echo "Switching traffic to $NEW environment..." | |
| sudo ln -sfn /var/www/iact-$NEW /var/www/iact-current | |
| sudo systemctl reload nginx | |
| # Final health check | |
| sleep 5 | |
| curl -f http://localhost/api/health || exit 1 | |
| # Stop old environment (keep as fallback for 5 minutes) | |
| echo "Keeping $CURRENT as fallback for 5 minutes..." | |
| sleep 300 | |
| sudo systemctl stop gunicorn-iact-$CURRENT | |
| echo "[PASS] Blue-green deployment completed successfully!" | |
| ENDSSH | |
| - name: Verify production deployment | |
| run: | | |
| echo "Verifying production deployment..." | |
| # Wait for service to stabilize | |
| sleep 15 | |
| # Check health endpoint | |
| curl -f https://iact.example.com/api/health || exit 1 | |
| # Check session storage (MySQL) | |
| echo "Verifying session storage..." | |
| curl -f https://iact.example.com/api/session-check || exit 1 | |
| echo "[PASS] Production deployment verified" | |
| - name: Create GitHub release (if tag push) | |
| if: startsWith(github.ref, 'refs/tags/') | |
| uses: actions/create-release@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: ${{ github.ref }} | |
| release_name: Release ${{ github.ref }} | |
| draft: false | |
| prerelease: false | |
| post-deployment-monitoring: | |
| name: Post-deployment Monitoring | |
| runs-on: ubuntu-latest | |
| needs: [deploy-staging, deploy-production] | |
| if: always() && (needs.deploy-staging.result == 'success' || needs.deploy-production.result == 'success') | |
| steps: | |
| - name: Monitor for 5 minutes | |
| run: | | |
| ENV=${{ needs.pre-deployment-checks.outputs.environment }} | |
| URL=$([[ "$ENV" == "production" ]] && echo "https://iact.example.com" || echo "https://staging.iact.example.com") | |
| echo "Monitoring $ENV for 5 minutes..." | |
| for i in {1..30}; do | |
| echo "Check $i/30..." | |
| # Health check | |
| if ! curl -f $URL/api/health; then | |
| echo "[FAIL] Health check failed!" | |
| exit 1 | |
| fi | |
| # Check error rate | |
| # (This would typically query a monitoring service) | |
| sleep 10 | |
| done | |
| echo "[PASS] Monitoring completed. No issues detected." | |
| - name: Notify team | |
| if: always() | |
| run: | | |
| STATUS=${{ job.status }} | |
| ENV=${{ needs.pre-deployment-checks.outputs.environment }} | |
| echo "Deployment to $ENV: $STATUS" | |
| # Here you would send notification via Slack, Teams, or InternalMessage |