diff --git a/snowflake-cortex-qbusiness-plugin/PROJECT_SUMMARY.md b/snowflake-cortex-qbusiness-plugin/PROJECT_SUMMARY.md new file mode 100644 index 00000000..6bb36da7 --- /dev/null +++ b/snowflake-cortex-qbusiness-plugin/PROJECT_SUMMARY.md @@ -0,0 +1,63 @@ +# Project Summary: Snowflake Q Business Plugin + +## 🎯 **What This Project Does** +Creates a custom Amazon Q Business plugin that integrates with Snowflake Cortex Search, allowing users to query Snowflake data using natural language through Q Business. + +## 📁 **Final File Structure** +``` +/Users/arghyaba/demo/genAI/FT/ +├── snowflake-q-business-final.yaml # Main CloudFormation template +├── deploy-snowflake-qbusiness.sh # Deployment script +├── test-deployment.sh # Testing script +├── README.md # Complete documentation +├── aws-credentials.env # AWS credentials (not in git) +├── .gitignore # Git ignore file +└── PROJECT_SUMMARY.md # This summary +``` + +## 🚀 **Quick Deployment** +```bash +# 1. Set credentials +source aws-credentials.env + +# 2. Deploy +./deploy-snowflake-qbusiness.sh \ + "arn:aws:secretsmanager:us-west-2::secret:snowflake/amazon-q-oauth-UKe0dC" \ + "arn:aws:sso:::instance/ssoins-xxxxxxx" + +# 3. Test +./test-deployment.sh +``` + +## ✅ **What's Automated** +- Q Business application creation +- Snowflake plugin configuration with OpenAPI schema +- OAuth authentication setup +- Web experience creation +- Auto-subscriptions for users +- All AWS resource provisioning + +## ⚠️ **What Requires Manual Configuration** +- **LLM Access Settings**: Must be enabled in AWS Console + - "Allow end users to send queries directly to the LLM" + - "Allow Amazon Q to fall back to LLM knowledge" +- **User Management**: Create users in IAM Identity Center and assign subscriptions + +## 🔧 **Key Features** +- **Comprehensive CloudFormation**: All resources defined as code +- **Security**: OAuth 2.0 with Secrets Manager integration +- **Scalability**: Auto-subscriptions and proper IAM roles +- **Testing**: Built-in verification scripts +- **Documentation**: Complete setup and troubleshooting guide + +## 🎉 **Current Status** +- ✅ All older files cleaned up +- ✅ Final template tested and working +- ✅ Deployment scripts functional +- ✅ Documentation complete +- ✅ Ready for production use + +## 📞 **Support** +- Check README.md for detailed instructions +- Use test-deployment.sh for verification +- Review CloudFormation events for troubleshooting diff --git a/snowflake-cortex-qbusiness-plugin/README.md b/snowflake-cortex-qbusiness-plugin/README.md new file mode 100644 index 00000000..80486cea --- /dev/null +++ b/snowflake-cortex-qbusiness-plugin/README.md @@ -0,0 +1,223 @@ +# Snowflake Q Business Custom Plugin + +This project creates a custom Amazon Q Business plugin that integrates directly with Snowflake Cortex Search, enabling users to query unstructured data stored in Snowflake through natural language interactions. + +## Architecture + +``` +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────────┐ +│ Amazon Q │ │ Custom Plugin │ │ Snowflake │ +│ Business │◄──►│ (OpenAPI │◄──►│ Cortex Search │ +│ │ │ Schema + │ │ Service │ +│ │ │ OAuth 2.0) │ │ │ +└─────────────────┘ └──────────────────┘ └─────────────────────┘ +``` + +## Files Overview + +- `snowflake-q-business-final.yaml` - Final CloudFormation template with comprehensive configuration +- `deploy-snowflake-qbusiness.sh` - Deployment script +- `test-deployment.sh` - Testing and verification script +- `aws-credentials.env` - AWS credentials configuration (not in git) + +## Prerequisites + +### AWS Requirements +- AWS Account with Amazon Q Business access +- Valid AWS credentials with permissions for: + - CloudFormation stack creation + - Q Business application management + - Secrets Manager access + - IAM role creation + - IAM Identity Center access + +### Snowflake Requirements +- Snowflake account with Cortex Search enabled +- OAuth security integration configured +- Cortex Search service created +- Existing Secrets Manager secret with OAuth credentials + +## Quick Start + +### Step 1: Set AWS Credentials + +```bash +# Option 1: Use environment file (recommended) +source aws-credentials.env + +# Option 2: Set environment variables directly +export AWS_ACCESS_KEY_ID="your_access_key" +export AWS_SECRET_ACCESS_KEY="your_secret_key" +export AWS_SESSION_TOKEN="your_session_token" # if using temporary credentials +export AWS_DEFAULT_REGION="us-west-2" +``` + +### Step 2: Deploy the Plugin + +```bash +./deploy-snowflake-qbusiness.sh [APPLICATION_NAME] +``` + +Example: +```bash +./deploy-snowflake-qbusiness.sh \ + "arn:aws:secretsmanager:us-west-2::secret:snowflake/amazon-q-oauth-UKe0dC" \ + "arn:aws:sso:::instance/ssoins-xxxxxxxx" \ + "SnowflakeCortexApp" +``` + +### Step 3: Test the Deployment + +```bash +./test-deployment.sh [STACK_NAME] [REGION] +``` + +Example: +```bash +./test-deployment.sh snowflake-qbusiness-plugin us-west-2 +``` + +## Manual Configuration Required + +⚠️ **Important**: Some Q Business features are not available through CloudFormation and must be configured manually: + +### LLM Access Settings (Console Only) + +1. **Go to Q Business Console**: + - Navigate to: https://console.aws.amazon.com/qbusiness/ + - Select your application + +2. **Enable LLM Features**: + - Click "Edit" or go to "Settings" + - Enable "Allow end users to send queries directly to the LLM" + - Enable "Allow Amazon Q to fall back to LLM knowledge" + - Save changes + +### User Access Management + +1. **Create Users in IAM Identity Center**: + - Go to: https://console.aws.amazon.com/singlesignon/ + - Add users with appropriate email addresses + +2. **Assign Q Business Subscriptions**: + - Go to Q Business Console → Your App → Access management → Subscriptions + - Assign Q Business Lite or Pro subscriptions to users + +## CloudFormation Template Features + +The template includes comprehensive configuration: + +### ✅ Automated Configuration +- **Application Setup**: Q Business application with optimal settings +- **Plugin Integration**: Snowflake Cortex Search plugin with OpenAPI schema +- **OAuth Configuration**: Secure authentication with Snowflake +- **Web Experience**: Ready-to-use web interface +- **Auto Subscriptions**: Automatic Q Business Pro subscriptions for new users +- **Feature Enablement**: File uploads, personalization, Q Apps, sample prompts + +### ⚠️ Manual Configuration Required +- **LLM Direct Access**: "Allow end users to send queries directly to the LLM" +- **LLM Knowledge Fallback**: "Allow Amazon Q to fall back to LLM knowledge" +- **User Management**: Creating users and assigning subscriptions + +## Snowflake Configuration + +The plugin uses the following Snowflake configuration (stored in Secrets Manager): + +```json +{ + "account": "xxxxxY-xxxxx", + "warehouse": "AMAZON_Q_WAREHOUSE", + "database": "AMAZON_Q_BUSINESS", + "schema": "CORTEX_SEARCH", + "role": "AMAZON_Q_ROLE", + "client_id": "your_oauth_client_id", + "client_secret": "your_oauth_client_secret", + "refresh_token": "your_refresh_token" +} +``` + +## Testing the Plugin + +After deployment and manual configuration: + +1. **Access the Web Experience**: Use the URL from deployment outputs +2. **Sign In**: Use your IAM Identity Center credentials +3. **Test Queries**: Try questions like: + - "Search for pump maintenance procedures" + - "Find information about troubleshooting" + - "What are the safety guidelines?" + +## Troubleshooting + +### Common Issues + +1. **Login Error: "Please ask your IT Admin to add access to General knowledge"** + - Enable LLM access settings manually in the console (see Manual Configuration section) + +2. **User Not Found** + - Create the user in IAM Identity Center + - Assign Q Business subscription to the user + - Wait up to 24 hours for changes to propagate + +3. **Plugin Not Working** + - Verify Snowflake OAuth credentials in Secrets Manager + - Check that Cortex Search service is active in Snowflake + - Ensure plugin is enabled in Q Business console + +### Debug Commands + +Check stack status: +```bash +aws cloudformation describe-stacks --stack-name snowflake-qbusiness-plugin --region us-west-2 +``` + +View stack events: +```bash +aws cloudformation describe-stack-events --stack-name snowflake-qbusiness-plugin --region us-west-2 +``` + +Get application details: +```bash +aws qbusiness get-application --application-id --region us-west-2 +``` + +## Security Considerations + +- OAuth credentials are stored securely in AWS Secrets Manager +- IAM roles follow least privilege principle +- All communications use HTTPS +- Session tokens have limited validity + +## Cost Considerations + +### AWS Costs +- Q Business application usage (based on user subscriptions) +- Secrets Manager storage (minimal) +- CloudFormation (no additional cost) +- Lambda function executions (minimal) + +### Snowflake Costs +- Warehouse compute time for queries +- Cortex Search operations +- Data storage and transfer + +## Cleanup + +To remove the plugin and associated resources: + +```bash +aws cloudformation delete-stack --stack-name snowflake-qbusiness-plugin --region us-west-2 +``` + +## Support + +For issues or questions: +1. Check the troubleshooting section above +2. Review CloudFormation stack events +3. Verify Snowflake configuration and permissions +4. Check AWS Q Business application status in the console + +## License + +This project is licensed under the Apache License 2.0 - see the code headers for details. diff --git a/snowflake-cortex-qbusiness-plugin/deploy-snowflake-qbusiness.sh b/snowflake-cortex-qbusiness-plugin/deploy-snowflake-qbusiness.sh new file mode 100755 index 00000000..08b13594 --- /dev/null +++ b/snowflake-cortex-qbusiness-plugin/deploy-snowflake-qbusiness.sh @@ -0,0 +1,98 @@ +#!/bin/bash + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE} Snowflake Q Business Plugin Deployment${NC}" +echo -e "${BLUE}========================================${NC}" + +# Check if required parameters are provided +if [ $# -lt 2 ]; then + echo -e "${RED}[ERROR]${NC} Usage: $0 [APPLICATION_NAME]" + echo -e "${YELLOW}[INFO]${NC} Example:" + echo -e "${YELLOW}[INFO]${NC} $0 arn:aws:secretsmanager:us-west-2:123456789012:secret:snowflake/oauth-abc123 arn:aws:sso:::instance/ssoins-1234567890abcdef" + exit 1 +fi + +SECRETS_MANAGER_ARN="$1" +IDC_INSTANCE_ARN="$2" +APPLICATION_NAME="${3:-SnowflakeCortexApp}" +STACK_NAME="snowflake-qbusiness-plugin" +REGION="us-west-2" + +echo -e "${GREEN}[INFO]${NC} Configuration:" +echo -e "${GREEN}[INFO]${NC} Secrets Manager ARN: $SECRETS_MANAGER_ARN" +echo -e "${GREEN}[INFO]${NC} IDC Instance ARN: $IDC_INSTANCE_ARN" +echo -e "${GREEN}[INFO]${NC} Application Name: $APPLICATION_NAME" +echo -e "${GREEN}[INFO]${NC} Stack Name: $STACK_NAME" +echo -e "${GREEN}[INFO]${NC} Region: $REGION" + +# Check if AWS credentials are configured +echo -e "${BLUE}[CHECK]${NC} Verifying AWS credentials..." +if ! aws sts get-caller-identity >/dev/null 2>&1; then + echo -e "${RED}[ERROR]${NC} AWS credentials not configured. Please run 'aws configure' or set environment variables." + exit 1 +fi + +ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) +echo -e "${GREEN}[INFO]${NC} Using AWS Account: $ACCOUNT_ID" + +# Deploy the CloudFormation stack +echo -e "${BLUE}[DEPLOY]${NC} Deploying CloudFormation stack..." + +aws cloudformation deploy \ + --template-file snowflake-q-business-final.yaml \ + --stack-name "$STACK_NAME" \ + --parameter-overrides \ + ExistingSecretsManagerArn="$SECRETS_MANAGER_ARN" \ + ExistingIDCInstanceArn="$IDC_INSTANCE_ARN" \ + ApplicationName="$APPLICATION_NAME" \ + CortexSearchServiceName="PUMP_SEARCH_SERVICE" \ + PluginDisplayName="Snowflake-Cortex-Search" \ + --capabilities CAPABILITY_NAMED_IAM \ + --region "$REGION" + +if [ $? -eq 0 ]; then + echo -e "${GREEN}[SUCCESS]${NC} ✅ Stack deployment completed successfully!" + + # Get stack outputs + echo -e "${BLUE}[INFO]${NC} Retrieving deployment information..." + + WEB_URL=$(aws cloudformation describe-stacks \ + --stack-name "$STACK_NAME" \ + --region "$REGION" \ + --query 'Stacks[0].Outputs[?OutputKey==`QBusinessWebExperienceUrl`].OutputValue' \ + --output text) + + APPLICATION_ID=$(aws cloudformation describe-stacks \ + --stack-name "$STACK_NAME" \ + --region "$REGION" \ + --query 'Stacks[0].Outputs[?OutputKey==`QBusinessApplicationId`].OutputValue' \ + --output text) + + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN} DEPLOYMENT SUCCESSFUL! 🎉${NC}" + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN}[SUCCESS]${NC} Web Experience URL: $WEB_URL" + echo -e "${GREEN}[SUCCESS]${NC} Application ID: $APPLICATION_ID" + echo -e "" + echo -e "${YELLOW}[NEXT STEPS]${NC} Manual Configuration Required:" + echo -e "${YELLOW}[STEP 1]${NC} Go to: https://console.aws.amazon.com/qbusiness/home?region=$REGION#/applications/$APPLICATION_ID" + echo -e "${YELLOW}[STEP 2]${NC} Click 'Edit' and enable 'Allow Amazon Q to fall back to LLM knowledge'" + echo -e "${YELLOW}[STEP 3]${NC} Create users in IAM Identity Center and assign Q Business subscriptions" + echo -e "${YELLOW}[STEP 4]${NC} Test the application at: $WEB_URL" + echo -e "" + echo -e "${BLUE}[INFO]${NC} For detailed outputs, run:" + echo -e "${BLUE}[INFO]${NC} aws cloudformation describe-stacks --stack-name $STACK_NAME --region $REGION --query 'Stacks[0].Outputs'" + +else + echo -e "${RED}[ERROR]${NC} ❌ Stack deployment failed!" + echo -e "${RED}[ERROR]${NC} Check the CloudFormation console for details:" + echo -e "${RED}[ERROR]${NC} https://console.aws.amazon.com/cloudformation/home?region=$REGION#/stacks" + exit 1 +fi diff --git a/snowflake-cortex-qbusiness-plugin/snowflake-q-business-final.yaml b/snowflake-cortex-qbusiness-plugin/snowflake-q-business-final.yaml new file mode 100644 index 00000000..a5878b31 --- /dev/null +++ b/snowflake-cortex-qbusiness-plugin/snowflake-q-business-final.yaml @@ -0,0 +1,424 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Snowflake Q Business Plugin with existing resources and comprehensive configuration' + +Parameters: + ExistingSecretsManagerArn: + Type: String + Description: ARN of the existing Secrets Manager secret containing Snowflake OAuth credentials + + ExistingIDCInstanceArn: + Type: String + Description: ARN of the existing IAM Identity Center instance + + ApplicationName: + Type: String + Description: Name for the Q Business application + Default: SnowflakeCortexApp + + CortexSearchServiceName: + Type: String + Description: Name of the Snowflake Cortex Search service + Default: PUMP_SEARCH_SERVICE + + PluginDisplayName: + Type: String + Description: Display name for the plugin + Default: Snowflake-Cortex-Search + +Resources: + # IAM Role for Q Business Application + QBusinessApplicationRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub '${AWS::StackName}-QBApp' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: qbusiness.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AmazonQBusinessServiceRolePolicy + + # Q Business Application with comprehensive configuration + QBusinessApplication: + Type: AWS::QBusiness::Application + Properties: + DisplayName: !Sub '${ApplicationName}-Application' + Description: Q Business Application for Snowflake Cortex Search with comprehensive LLM configuration + RoleArn: !GetAtt QBusinessApplicationRole.Arn + IdentityCenterInstanceArn: !Ref ExistingIDCInstanceArn + # Enable all available features + AttachmentsConfiguration: + AttachmentsControlMode: ENABLED + PersonalizationConfiguration: + PersonalizationControlMode: ENABLED + QAppsConfiguration: + QAppsControlMode: ENABLED + # Enable automatic subscriptions with Pro tier + AutoSubscriptionConfiguration: + AutoSubscribe: ENABLED + DefaultSubscriptionType: Q_BUSINESS + + # Wait for Q Business Application to be active + WaitForQBusinessApplication: + Type: AWS::CloudFormation::WaitCondition + Properties: + Handle: !Ref WaitHandle + Timeout: '600' + Count: 0 + + WaitHandle: + Type: AWS::CloudFormation::WaitConditionHandle + + # Web Experience + QBusinessWebExperience: + Type: AWS::QBusiness::WebExperience + DependsOn: WaitForQBusinessApplication + Properties: + ApplicationId: !Ref QBusinessApplication + Title: Snowflake Cortex Search + Subtitle: Search your Snowflake data using natural language + SamplePromptsControlMode: ENABLED + + # IAM Role for Q Business Plugin + QBusinessPluginRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub '${AWS::StackName}-QBPlugin' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: qbusiness.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: QBusinessPluginPolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*' + - Effect: Allow + Action: + - secretsmanager:GetSecretValue + Resource: + - !Ref ExistingSecretsManagerArn + - !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${AWS::StackName}-plugin-oauth-secret*' + + # Lambda Function to Read Secret Values + SecretReaderFunction: + Type: AWS::Lambda::Function + Properties: + FunctionName: !Sub '${AWS::StackName}-secret-reader' + Runtime: python3.13 + Handler: index.lambda_handler + Role: !GetAtt QBusinessPluginRole.Arn + Code: + ZipFile: | + import boto3 + import json + import cfnresponse + + def lambda_handler(event, context): + try: + if event['RequestType'] == 'Delete': + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) + return + + secret_arn = event['ResourceProperties']['SecretArn'] + secrets_client = boto3.client('secretsmanager') + + response = secrets_client.get_secret_value(SecretArn=secret_arn) + secret_data = json.loads(response['SecretString']) + + cfnresponse.send(event, context, cfnresponse.SUCCESS, { + 'Account': secret_data.get('account', ''), + 'Warehouse': secret_data.get('warehouse', ''), + 'Database': secret_data.get('database', ''), + 'Schema': secret_data.get('schema', ''), + 'Role': secret_data.get('role', ''), + 'ClientId': secret_data.get('client_id', ''), + 'ClientSecret': secret_data.get('client_secret', ''), + 'RefreshToken': secret_data.get('refresh_token', '') + }) + except Exception as e: + cfnresponse.send(event, context, cfnresponse.FAILED, {}, str(e)) + + # Custom Resource to Read Secret + SecretReader: + Type: AWS::CloudFormation::CustomResource + Properties: + ServiceToken: !GetAtt SecretReaderFunction.Arn + SecretArn: !Ref ExistingSecretsManagerArn + + # Plugin OAuth Secret + PluginOAuthSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub '${AWS::StackName}-plugin-oauth-secret' + Description: OAuth credentials for Snowflake Q Business Plugin + SecretString: !Sub | + { + "client_id": "${SecretReader.ClientId}", + "client_secret": "${SecretReader.ClientSecret}", + "refresh_token": "${SecretReader.RefreshToken}" + } + + # Snowflake Cortex Search Plugin + SnowflakeCortexPlugin: + Type: AWS::QBusiness::Plugin + DependsOn: WaitForQBusinessApplication + Properties: + ApplicationId: !Ref QBusinessApplication + DisplayName: !Ref PluginDisplayName + Type: SERVICE_NOW + AuthConfiguration: + OAuth2ClientCredentialConfiguration: + SecretArn: !Ref PluginOAuthSecret + RoleArn: !GetAtt QBusinessPluginRole.Arn + ServerUrl: !Sub 'https://${SecretReader.Account}.snowflakecomputing.com' + CustomPluginConfiguration: + Description: Snowflake Cortex Search integration for Q Business + ApiSchema: !Sub | + { + "openapi": "3.0.0", + "info": { + "title": "Snowflake Cortex Search API", + "version": "1.0.0", + "description": "API for searching Snowflake data using Cortex Search" + }, + "servers": [ + { + "url": "https://${SecretReader.Account}.snowflakecomputing.com" + } + ], + "paths": { + "/api/v2/statements": { + "post": { + "summary": "Execute Snowflake Cortex Search query", + "description": "Search for information using Snowflake Cortex Search service", + "operationId": "searchCortex", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "statement": { + "type": "string", + "description": "SQL statement to execute Cortex Search" + }, + "warehouse": { + "type": "string", + "default": "${SecretReader.Warehouse}" + }, + "database": { + "type": "string", + "default": "${SecretReader.Database}" + }, + "schema": { + "type": "string", + "default": "${SecretReader.Schema}" + }, + "role": { + "type": "string", + "default": "${SecretReader.Role}" + } + }, + "required": ["statement"] + }, + "example": { + "statement": "SELECT SNOWFLAKE.CORTEX.SEARCH_PREVIEW('${CortexSearchServiceName}', 'pump maintenance') as results;", + "warehouse": "${SecretReader.Warehouse}", + "database": "${SecretReader.Database}", + "schema": "${SecretReader.Schema}", + "role": "${SecretReader.Role}" + } + } + } + }, + "responses": { + "200": { + "description": "Successful search response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "resultSetMetaData": { + "type": "object" + }, + "data": { + "type": "array", + "items": { + "type": "array" + } + }, + "code": { + "type": "string" + }, + "statementStatusUrl": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "sqlState": { + "type": "string" + }, + "statementHandle": { + "type": "string" + }, + "message": { + "type": "string" + }, + "createdOn": { + "type": "integer" + } + } + } + } + } + } + }, + "security": [ + { + "OAuth2": ["session:role:${SecretReader.Role}"] + } + ] + } + } + }, + "components": { + "securitySchemes": { + "OAuth2": { + "type": "oauth2", + "flows": { + "clientCredentials": { + "tokenUrl": "https://${SecretReader.Account}.snowflakecomputing.com/oauth/token-request", + "scopes": { + "session:role:${SecretReader.Role}": "Access to Snowflake with specified role" + } + } + } + } + } + } + } + ApiSchemaType: OPEN_API_3 + +Outputs: + QBusinessApplicationId: + Description: Q Business Application ID + Value: !Ref QBusinessApplication + Export: + Name: !Sub '${AWS::StackName}-ApplicationId' + + QBusinessWebExperienceUrl: + Description: Q Business Web Experience URL + Value: !GetAtt QBusinessWebExperience.DefaultEndpoint + Export: + Name: !Sub '${AWS::StackName}-WebExperienceUrl' + + PluginId: + Description: Snowflake Cortex Search Plugin ID + Value: !Sub '${QBusinessApplication}|${SnowflakeCortexPlugin}' + Export: + Name: !Sub '${AWS::StackName}-PluginId' + + PluginArn: + Description: Snowflake Cortex Search Plugin ARN + Value: !Sub 'arn:aws:qbusiness:${AWS::Region}:${AWS::AccountId}:application/${QBusinessApplication}/plugin/${SnowflakeCortexPlugin}' + Export: + Name: !Sub '${AWS::StackName}-PluginArn' + + OAuthCredentialsArn: + Description: OAuth credentials secret ARN + Value: !Ref PluginOAuthSecret + Export: + Name: !Sub '${AWS::StackName}-OAuthCredentialsArn' + + SnowflakeAccountUrl: + Description: Snowflake account URL + Value: !Sub 'https://${SecretReader.Account}.snowflakecomputing.com' + Export: + Name: !Sub '${AWS::StackName}-SnowflakeAccountUrl' + + LLMConfigurationInstructions: + Description: Manual LLM configuration instructions + Value: !Sub + - | + 🤖 LLM CONFIGURATION REQUIRED (MANUAL STEPS): + + ⚠️ The following settings must be enabled manually in the AWS Console: + + 1. ✅ "Allow end users to send queries directly to the LLM" (You've enabled this) + 2. ⚠️ "Allow Amazon Q to fall back to LLM knowledge" (Enable this for better responses) + + 📍 To enable the fallback setting: + 1. Go to: https://console.aws.amazon.com/qbusiness/home?region=${AWS::Region}#/applications/${ApplicationId} + 2. Click "Edit" or go to "Settings" tab + 3. Look for "Allow Amazon Q to fall back to LLM knowledge" + 4. Enable this setting and save changes + + 💡 Benefits: + - Users can ask general questions even without Snowflake data + - Q Business will use AI knowledge when your data doesn't contain the answer + - Better user experience with comprehensive responses + + 🔧 These settings are console-only and not available via CloudFormation/API yet. + - ApplicationId: !Ref QBusinessApplication + Export: + Name: !Sub '${AWS::StackName}-LLMInstructions' + + DeploymentSummary: + Description: Complete deployment summary with next steps + Value: !Sub + - | + 🎉 DEPLOYMENT COMPLETE! + + 🌐 Web Interface: ${WebUrl} + 🔌 Plugin: ${PluginName} (${PluginId}) + 🔐 OAuth Secret: ${OAuthArn} + + 📋 Next Steps: + 1. Access the Q Business web interface using the URL above + 2. Sign in with your IAM Identity Center user + 3. Enable "Allow Amazon Q to fall back to LLM knowledge" in console (see LLM Configuration output) + 4. Test the Snowflake Cortex Search plugin + 5. Ask questions about pump maintenance and repair + + ✅ CONFIGURED FEATURES: + - ✅ File uploads: Enabled + - ✅ Personalization: Enabled + - ✅ Q Apps: Enabled + - ✅ Auto subscriptions: Enabled (Q Business Pro tier) + - ✅ Sample prompts: Enabled + + 🤖 LLM CONFIGURATION: + - ✅ Direct LLM queries: Enabled (manual configuration) + - ⚠️ LLM knowledge fallback: Requires manual configuration + + 📊 Snowflake Configuration: + - Account: ${Account} + - Database: ${Database} + - Schema: ${Schema} + - Cortex Service: ${CortexService} + - WebUrl: !GetAtt QBusinessWebExperience.DefaultEndpoint + PluginName: !Ref PluginDisplayName + PluginId: !Sub '${QBusinessApplication}|${SnowflakeCortexPlugin}' + OAuthArn: !Ref PluginOAuthSecret + Account: !GetAtt SecretReader.Account + Database: !GetAtt SecretReader.Database + Schema: !GetAtt SecretReader.Schema + CortexService: !Ref CortexSearchServiceName + Export: + Name: !Sub '${AWS::StackName}-DeploymentSummary' diff --git a/snowflake-cortex-qbusiness-plugin/test-deployment.sh b/snowflake-cortex-qbusiness-plugin/test-deployment.sh new file mode 100755 index 00000000..c2db21a4 --- /dev/null +++ b/snowflake-cortex-qbusiness-plugin/test-deployment.sh @@ -0,0 +1,110 @@ +#!/bin/bash + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +STACK_NAME="${1:-snowflake-qbusiness-plugin}" +REGION="${2:-us-west-2}" + +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE} Snowflake Q Business Plugin Test${NC}" +echo -e "${BLUE}========================================${NC}" + +echo -e "${BLUE}[TEST]${NC} Testing deployment for stack: $STACK_NAME" + +# Check if stack exists +echo -e "${BLUE}[CHECK]${NC} Verifying stack status..." +STACK_STATUS=$(aws cloudformation describe-stacks \ + --stack-name "$STACK_NAME" \ + --region "$REGION" \ + --query 'Stacks[0].StackStatus' \ + --output text 2>/dev/null) + +if [ $? -ne 0 ]; then + echo -e "${RED}[ERROR]${NC} Stack '$STACK_NAME' not found!" + exit 1 +fi + +echo -e "${GREEN}[INFO]${NC} Stack Status: $STACK_STATUS" + +if [ "$STACK_STATUS" != "CREATE_COMPLETE" ] && [ "$STACK_STATUS" != "UPDATE_COMPLETE" ]; then + echo -e "${YELLOW}[WARNING]${NC} Stack is not in a complete state: $STACK_STATUS" +fi + +# Get all outputs +echo -e "${BLUE}[INFO]${NC} Retrieving stack outputs..." + +OUTPUTS=$(aws cloudformation describe-stacks \ + --stack-name "$STACK_NAME" \ + --region "$REGION" \ + --query 'Stacks[0].Outputs' \ + --output json) + +if [ $? -eq 0 ]; then + echo -e "${GREEN}[SUCCESS]${NC} Stack outputs retrieved successfully!" + + # Parse key outputs + WEB_URL=$(echo "$OUTPUTS" | jq -r '.[] | select(.OutputKey=="QBusinessWebExperienceUrl") | .OutputValue') + APP_ID=$(echo "$OUTPUTS" | jq -r '.[] | select(.OutputKey=="QBusinessApplicationId") | .OutputValue') + PLUGIN_ID=$(echo "$OUTPUTS" | jq -r '.[] | select(.OutputKey=="PluginId") | .OutputValue') + + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN} DEPLOYMENT TEST RESULTS${NC}" + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN}[✅]${NC} Web Experience URL: $WEB_URL" + echo -e "${GREEN}[✅]${NC} Application ID: $APP_ID" + echo -e "${GREEN}[✅]${NC} Plugin ID: $PLUGIN_ID" + + # Test web URL accessibility + echo -e "${BLUE}[TEST]${NC} Testing web experience accessibility..." + if curl -s --head "$WEB_URL" | head -n 1 | grep -q "200 OK"; then + echo -e "${GREEN}[✅]${NC} Web experience is accessible" + else + echo -e "${YELLOW}[⚠️]${NC} Web experience may not be fully ready yet" + fi + + # Check Q Business application status + echo -e "${BLUE}[TEST]${NC} Checking Q Business application status..." + APP_STATUS=$(aws qbusiness get-application \ + --application-id "$APP_ID" \ + --region "$REGION" \ + --query 'status' \ + --output text 2>/dev/null) + + if [ "$APP_STATUS" = "ACTIVE" ]; then + echo -e "${GREEN}[✅]${NC} Q Business application is ACTIVE" + else + echo -e "${YELLOW}[⚠️]${NC} Q Business application status: $APP_STATUS" + fi + + # Check plugin status + echo -e "${BLUE}[TEST]${NC} Checking plugin status..." + PLUGIN_STATUS=$(aws qbusiness get-plugin \ + --application-id "$APP_ID" \ + --plugin-id "${PLUGIN_ID##*|}" \ + --region "$REGION" \ + --query 'state' \ + --output text 2>/dev/null) + + if [ "$PLUGIN_STATUS" = "ENABLED" ]; then + echo -e "${GREEN}[✅]${NC} Plugin is ENABLED" + else + echo -e "${YELLOW}[⚠️]${NC} Plugin status: $PLUGIN_STATUS" + fi + + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN} NEXT STEPS${NC}" + echo -e "${GREEN}========================================${NC}" + echo -e "${YELLOW}[MANUAL]${NC} Enable LLM fallback in console:" + echo -e "${YELLOW}[MANUAL]${NC} https://console.aws.amazon.com/qbusiness/home?region=$REGION#/applications/$APP_ID" + echo -e "${YELLOW}[MANUAL]${NC} Create users in IAM Identity Center and assign subscriptions" + echo -e "${YELLOW}[MANUAL]${NC} Test the web experience: $WEB_URL" + +else + echo -e "${RED}[ERROR]${NC} Failed to retrieve stack outputs!" + exit 1 +fi