diff --git a/.github/scripts/deploy-instance.sh b/.github/scripts/deploy-instance.sh index b1f9885..85e0aa2 100644 --- a/.github/scripts/deploy-instance.sh +++ b/.github/scripts/deploy-instance.sh @@ -8,16 +8,13 @@ if ! kubectl get namespace/ci-{{INSTANCE}}-ns-pm4 >/dev/null 2>&1; then echo "New instance. Creating Namespace" kubectl create namespace ci-{{INSTANCE}}-ns-pm4 echo "Creating DB" - # Generate random password - echo "Generating MySQL Password" - export MYSQL_PASSWORD=$(openssl rand -base64 12 | tr -dc 'a-zA-Z0-9' | head -c 16) + # Use admin password from secrets echo "Update instance yamls" - echo "Current Directory" - pwd - ls -lah - - sed -i "s/{{MYSQL_PASSWORD}}/$MYSQL_PASSWORD/" .github/templates/db.yaml + export RDS_ADMIN_PASSWORD=$RDS_ADMIN_PASSWORD + export RDS_ADMIN_USERNAME=$RDS_ADMIN_USERNAME + sed -i "s/{{MYSQL_USERNAME}}/$RDS_ADMIN_USERNAME/" .github/templates/db.yaml + sed -i "s/{{MYSQL_PASSWORD}}/$RDS_ADMIN_PASSWORD/" .github/templates/db.yaml echo "Creating DB :: pm4_ci-{{INSTANCE}}" cat .github/templates/db.yaml kubectl apply -f .github/templates/db.yaml --v=4 @@ -36,11 +33,14 @@ if ! kubectl get namespace/ci-{{INSTANCE}}-ns-pm4 >/dev/null 2>&1; then echo "Removing Job" kubectl delete job mysql-setup-job-ci-{{INSTANCE}} echo "Deploying Instance :: ci-{{INSTANCE}}" - sed -i "s/{{MYSQL_PASSWORD}}/$MYSQL_PASSWORD/g" .github/templates/instance.yaml + sed -i "s/{{MYSQL_PASSWORD}}/$RDS_ADMIN_PASSWORD/" .github/templates/instance.yaml + sed -i "s/{{MYSQL_USER}}/$RDS_ADMIN_USERNAME/" .github/templates/instance.yaml cat .github/templates/instance.yaml - + # Evaluate the command and store the result + APP_VERSION=$(echo "$CI_PROJECT-$CI_PACKAGE_BRANCH" | sed "s;/;-;g" | sed "s/refs-heads-//g") + helm install --timeout 75m -f .github/templates/instance.yaml ci-{{INSTANCE}} processmaker/enterprise \ - --set deploy.pmai.openaiApiKey=${OPEN_AI_API_KEY} \ + --set deploy.pmai.openaiApiKey=${OPENAI_API_KEY} \ --set analytics.awsAccessKey=${ANALYTICS_AWS_ACCESS_KEY} \ --set analytics.awsSecretKey=${ANALYTICS_AWS_SECRET_KEY} \ --set dockerRegistry.password=${REGISTRY_PASSWORD} \ @@ -48,6 +48,7 @@ if ! kubectl get namespace/ci-{{INSTANCE}}-ns-pm4 >/dev/null 2>&1; then --set dockerRegistry.username=${REGISTRY_USERNAME} \ --set twilio.sid=${TWILIO_SID} \ --set twilio.token=${TWILIO_TOKEN} \ + --set appVersion=${APP_VERSION} \ --version ${versionHelm} else echo "Instance exists. Running upgrade and bouncing pods" @@ -60,6 +61,10 @@ else kubectl delete pod $webPod $schedulerPod $queuePod -n ci-{{INSTANCE}}-ns-pm4 fi -export INSTANCE_URL=https://ci-{{INSTANCE}}$DOM_EKS +if [ "$MULTITENANCY" = "true" ]; then + export INSTANCE_URL="https://tenant-1.ci-{{INSTANCE}}$DOM_EKS" +else + export INSTANCE_URL="https://ci-{{INSTANCE}}$DOM_EKS" +fi echo "INSTANCE_URL=${INSTANCE_URL}" >> "$GITHUB_ENV" ./pm4-k8s-distribution/images/pm4-tools/pm wait-for-instance-ready diff --git a/.github/templates/db.yaml b/.github/templates/db.yaml index dcccc0f..5316feb 100644 --- a/.github/templates/db.yaml +++ b/.github/templates/db.yaml @@ -16,18 +16,14 @@ spec: # Create databases CREATE DATABASE IF NOT EXISTS \`pm4_ci-{{INSTANCE}}\`; CREATE DATABASE IF NOT EXISTS \`pm4_ci-{{INSTANCE}}_ai\`; - # Create users - CREATE USER IF NOT EXISTS 'user_ci-{{INSTANCE}}'@'%' IDENTIFIED BY '{{MYSQL_PASSWORD}}'; - CREATE USER IF NOT EXISTS 'user_ci-{{INSTANCE}}_ai'@'%' IDENTIFIED BY '{{MYSQL_PASSWORD}}'; - # Grant permissions - GRANT ALL PRIVILEGES ON \`pm4_ci-{{INSTANCE}}\`.* TO 'user_ci-{{INSTANCE}}'@'%'; - GRANT ALL PRIVILEGES ON \`pm4_ci-{{INSTANCE}}_ai\`.* TO 'user_ci-{{INSTANCE}}_ai'@'%'; + # Grant permissions to admin user (no need to create instance-specific users for multitenancy) + GRANT ALL PRIVILEGES ON \`pm4_ci-{{INSTANCE}}\`.* TO '{{MYSQL_USERNAME}}'@'%'; + GRANT ALL PRIVILEGES ON \`pm4_ci-{{INSTANCE}}_ai\`.* TO '{{MYSQL_USERNAME}}'@'%'; FLUSH PRIVILEGES; # Output the created resources SELECT CONCAT('Created database: pm4_', 'ci-{{INSTANCE}}') AS setup_info; SELECT CONCAT('Created database: pm4_', 'ci-{{INSTANCE}}', '_ai') AS setup_info; - SELECT CONCAT('Created user: user_', 'ci-{{INSTANCE}}', '@%') AS setup_info; - SELECT CONCAT('Created user: user_', 'ci-{{INSTANCE}}', '_ai@%') AS setup_info; + SELECT CONCAT('Using admin user: ', '{{MYSQL_USERNAME}}', '@%') AS setup_info; SELECT CONCAT('Password: ', '{{MYSQL_PASSWORD}}') AS setup_info; EOF env: diff --git a/.github/templates/instance.yaml b/.github/templates/instance.yaml index 4890f45..57f2f1c 100644 --- a/.github/templates/instance.yaml +++ b/.github/templates/instance.yaml @@ -1,7 +1,7 @@ appVersion: {{IMAGE_TAG}} eksCluster: pm4-eng appConfig: - https: false + https: true subdomain: .engk8s.processmaker.net customSecurityPolicy: true customSecurityPolicyUrl: 'https://adobexdplatform.com https://*.quicksight.aws.amazon.com https://www.canva.com https://excalidraw.com https://www.figma.com https://flocus.com https://www.framer.com https://giphy.com https://lookerstudio.google.com https://maps.google.com https://docs.google.com https://www.loom.com https://miro.com https://mixpanel.com https://pitch.com https://prezi.com https://www.sketch.com https://www.slideshare.net https://supademo.com https://www.tableau.com https://forms.app https://vimeo.com https://www.youtube.com' @@ -14,7 +14,7 @@ deploy: deployDb: false dbHost: pm4-eng-stm-rds-cluster.cluster-ckz0mnb6cuna.us-east-1.rds.amazonaws.com dbName: pm4_ci-{{INSTANCE}}_ai - dbUsername: user_ci-{{INSTANCE}}_ai + dbUsername: {{MYSQL_USER}} dbPassword: {{MYSQL_PASSWORD}} volumes: storageClassName: 'efs-sc' @@ -30,7 +30,7 @@ database: deploy: false host: pm4-eng-stm-rds-cluster.cluster-ckz0mnb6cuna.us-east-1.rds.amazonaws.com name: pm4_ci-{{INSTANCE}} - username: user_ci-{{INSTANCE}} + username: {{MYSQL_USER}} password: {{MYSQL_PASSWORD}} analytics: awsRegion: us-east-1 @@ -55,6 +55,8 @@ cdata: slack: 4643444B5541535544424141454E545041325246353431324354303100000000000000000000000050524F434553534D00004635523734413735455A32360000 gmail: 4431444B5541535544424141454E545041325246353431324354303100000000000000000000000050524F434553534D00005356434441465847303144570000 api: 4641444B5541535544424141454E545041325246353431324354303100000000000000000000000050524F434553534D00004750533442365456343939530000 +multitenancy: + enable: {{MULTITENANCY}} microservices: scriptExecutor: enable: true diff --git a/.github/workflows/deploy-pm4.yml b/.github/workflows/deploy-pm4.yml index 4324209..9e569f0 100644 --- a/.github/workflows/deploy-pm4.yml +++ b/.github/workflows/deploy-pm4.yml @@ -25,6 +25,7 @@ env: DOM_EKS: ${{ secrets.DOM_EKS }} GITHUB_TOKEN: ${{ secrets.GIT_TOKEN }} BUILD_BASE: ${{ (contains(github.event.pull_request.body, 'ci:build-base') || github.event_name == 'schedule') && '1' || '0' }} + MULTITENANCY: ${{ (contains(github.event.pull_request.body, 'ci:multitenancy')) && 'true' || 'false' }} BASE_IMAGE: ${{ secrets.REGISTRY_HOST }}/processmaker/processmaker:base CUSTOMER_LICENSES_PAT: ${{ secrets.CUSTOMER_LICENSES_PAT }} # K8S_BRANCH: ${{ contains(github.event.pull_request.body, 'ci:next') && 'next' || 'release-2024-fall' }} @@ -50,9 +51,9 @@ jobs: - name: Set image name run: | - RESOLVED_IMAGE_TAG=${{ env.IMAGE_TAG }} echo "IMAGE=${{ secrets.REGISTRY_HOST }}/processmaker/enterprise:$RESOLVED_IMAGE_TAG" >> $GITHUB_ENV - name: Generate image EKS + if: ${{ !contains(github.event.pull_request.body, 'ci:skip-build') }} run: | cd pm4-k8s-distribution/images export CI_RELEASE_BRANCH=$RELEASE_BRANCH @@ -80,6 +81,7 @@ jobs: username: ${{ secrets.REGISTRY_USERNAME }} password: ${{ secrets.REGISTRY_PASSWORD }} - name: Push Enterprise Image to Harbor + if: ${{ !contains(github.event.pull_request.body, 'ci:skip-build') }} run: | docker tag processmaker/enterprise:${{env.IMAGE_TAG}} ${{ secrets.REGISTRY_HOST }}/processmaker/enterprise:${{env.IMAGE_TAG}} docker push ${{ secrets.REGISTRY_HOST }}/processmaker/enterprise:${{env.IMAGE_TAG}} @@ -94,6 +96,7 @@ jobs: uses: actions/checkout@v4 with: repository: processmaker/.github + ref: multitenancy - name: Common uses: ./.github/actions/common @@ -123,6 +126,7 @@ jobs: - name: Authenticate with Amazon EKS run: aws eks update-kubeconfig --region us-east-1 --name pm4-eng + - name: Deploy instance EKS env: IMAGE_TAG: ${{ env.IMAGE_TAG }} @@ -130,7 +134,8 @@ jobs: HELM_REPO: ${{ secrets.HELM_REPO }} HELM_USERNAME: ${{ secrets.HELM_USERNAME }} HELM_PASSWORD: ${{ secrets.HELM_PASSWORD }} - OPEN_AI_API_KEY: ${{ secrets.OPEN_AI_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + OPEN_AI_SECRET: ${{ secrets.OPENAI_API_KEY }} ANALYTICS_AWS_ACCESS_KEY: ${{ secrets.ANALYTICS_AWS_ACCESS_KEY }} ANALYTICS_AWS_SECRET_KEY: ${{ secrets.ANALYTICS_AWS_SECRET_KEY }} REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} @@ -143,18 +148,37 @@ jobs: KEYCLOAK_CLIENT_SECRET: ${{ secrets.KEYCLOAK_CLIENT_SECRET }} KEYCLOAK_PASSWORD: ${{ secrets.KEYCLOAK_PASSWORD }} CUSTOMER_LICENSES_PAT: ${{ secrets.CUSTOMER_LICENSES_PAT }} + RDS_ADMIN_USERNAME: ${{ secrets.RDS_ADMIN_USERNAME }} + RDS_ADMIN_PASSWORD: ${{ secrets.RDS_ADMIN_PASSWORD }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} run: | instance=$(echo -n ${{env.IMAGE_TAG}} | md5sum | head -c 10) - sed -i 's/{{INSTANCE}}/'"$instance"'/g' .github/scripts/deploy-instance.sh - sed -i 's/{{INSTANCE}}/'"$instance"'/g' .github/templates/instance.yaml - sed -i 's/{{INSTANCE}}/'"$instance"'/g' .github/templates/db.yaml - sed -i 's/{{IMAGE_TAG}}/'"${{env.IMAGE_TAG}}"'/g' .github/templates/instance.yaml - sed -i 's/{{KEYCLOAK_CLIENT_SECRET}}/'"${{env.KEYCLOAK_CLIENT_SECRET}}"'/g' .github/templates/instance.yaml - sed -i 's/{{KEYCLOAK_PASSWORD}}/'"${{env.KEYCLOAK_PASSWORD}}"'/g' .github/templates/instance.yaml - sed -i 's/{{CUSTOMER_LICENSES_PAT}}/'"${{env.CUSTOMER_LICENSES_PAT}}"'/g' .github/templates/instance.yaml + echo "INSTANCE: $instance" + echo "IMAGE_TAG: $IMAGE_TAG" + sed -i "s#{{INSTANCE}}#$instance#g" .github/scripts/deploy-instance.sh + sed -i "s#{{INSTANCE}}#$instance#g" .github/templates/instance.yaml + sed -i "s#{{INSTANCE}}#$instance#g" .github/templates/db.yaml + sed -i "s#{{IMAGE_TAG}}#$IMAGE_TAG#g" .github/templates/instance.yaml + sed -i "s#{{KEYCLOAK_CLIENT_SECRET}}#$KEYCLOAK_CLIENT_SECRET#g" .github/templates/instance.yaml + sed -i "s#{{KEYCLOAK_PASSWORD}}#$KEYCLOAK_PASSWORD#g" .github/templates/instance.yaml + sed -i "s#{{CUSTOMER_LICENSES_PAT}}#$CUSTOMER_LICENSES_PAT#g" .github/templates/instance.yaml + sed -i "s#{{MYSQL_USER}}#$RDS_ADMIN_USERNAME#g" .github/templates/instance.yaml + sed -i "s#{{MYSQL_PASSWORD}}#$RDS_ADMIN_PASSWORD#g" .github/templates/instance.yaml + sed -i "s#{{MULTITENANCY}}#$MULTITENANCY#g" .github/templates/instance.yaml + sed -i "s#{{MYSQL_USERNAME}}#$RDS_ADMIN_USERNAME#g" .github/templates/db.yaml + sed -i "s#{{MYSQL_PASSWORD}}#$RDS_ADMIN_PASSWORD#g" .github/templates/db.yaml + echo "=== Checking instance.yaml after replacements ===" + cat .github/templates/instance.yaml + echo "=== Checking db.yaml after replacements ===" + cat .github/templates/db.yaml chmod +x .github/scripts/deploy-instance.sh bash .github/scripts/deploy-instance.sh - export INSTANCE_URL="https://ci-$instance.engk8s.processmaker.net" + if [ "$MULTITENANCY" = "true" ]; then + export INSTANCE_URL="https://tenant-1.ci-$instance.engk8s.processmaker.net" + else + export INSTANCE_URL="https://ci-$instance.engk8s.processmaker.net" + fi echo "Instance URL: $INSTANCE_URL" bash .github/scripts/gh_comment.sh "$CI_PROJECT" "$pull_req_id" @@ -251,12 +275,20 @@ jobs: helm delete ci-$INSTANCE kubectl delete namespace ci-$INSTANCE-ns-pm4 #Drop database - deploy_db="\`pm4_ci-$INSTANCE\`" - deploy_ai="\`pm4_ci-$INSTANCE_ai\`" - mysql -u${{ secrets.USER_MYSQL_ENG }} -p${{ secrets.PASS_MYSQL_ENG }} -e "DROP DATABASE $deploy_db" -h ${{ secrets.RDS_ENG }} - mysql -u${{ secrets.USER_MYSQL_ENG }} -p${{ secrets.PASS_MYSQL_ENG }} -e "DROP DATABASE $deploy_ai" -h ${{ secrets.RDS_ENG }} - mysql -u${{ secrets.USER_MYSQL_ENG }} -p${{ secrets.PASS_MYSQL_ENG }} -e "DROP USER 'user_ci-$INSTANCE'@'%'" -h ${{ secrets.RDS_ENG }} - mysql -u${{ secrets.USER_MYSQL_ENG }} -p${{ secrets.PASS_MYSQL_ENG }} -e "DROP USER 'user_ci-$INSTANCE_ai'@'%'" -h ${{ secrets.RDS_ENG }} + deploy_db="pm4_ci-${INSTANCE}%" + deploy_ai="\`pm4_ci-$INSTANCE_ai\`" + + # check that that string length of $deploy_db is 12 or more as a safety check. If its less than 12, exit now + if [ ${#deploy_db} -lt 12 ]; then + exit 1 + fi + + # Drop the main database including any tenant databases + mysql -u${{ secrets.USER_MYSQL_ENG }} -p${{ secrets.PASS_MYSQL_ENG }} -h ${{ secrets.RDS_ENG }} -N -e "SHOW DATABASES LIKE '${deploy_db}'" | xargs -I{} mysql -u${{ secrets.USER_MYSQL_ENG }} -p${{ secrets.PASS_MYSQL_ENG }} -h ${{ secrets.RDS_ENG }} -e "DROP DATABASE IF EXISTS \`{}\`;" + + mysql -u${{ secrets.USER_MYSQL_ENG }} -p${{ secrets.PASS_MYSQL_ENG }} -e "DROP DATABASE IF EXISTS $deploy_ai" -h ${{ secrets.RDS_ENG }} + mysql -u${{ secrets.USER_MYSQL_ENG }} -p${{ secrets.PASS_MYSQL_ENG }} -e "DROP USER IF EXISTS 'user_ci-$INSTANCE'@'%'" -h ${{ secrets.RDS_ENG }} + mysql -u${{ secrets.USER_MYSQL_ENG }} -p${{ secrets.PASS_MYSQL_ENG }} -e "DROP USER IF EXISTS 'user_ci-$INSTANCE_ai'@'%'" -h ${{ secrets.RDS_ENG }} #Drop image Harbor curl -X DELETE -u ${{ secrets.REGISTRY_USERNAME }}:${{ secrets.REGISTRY_PASSWORD }} "https://${{ secrets.REGISTRY_HOST }}/api/v2.0/projects/processmaker/repositories/enterprise/artifacts/${{env.IMAGE_TAG}}" echo "The instance [https://ci-$INSTANCE.engk8s.processmaker.net] was deleted!!"