Skip to content

Commit c91328b

Browse files
committed
use us-west-2 everywhere
1 parent 7c00804 commit c91328b

71 files changed

Lines changed: 9800 additions & 737 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cloudformation/functions/sample-data-seeder/deploy.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
set -e
66

7-
REGION="${1:-us-east-1}"
7+
REGION="${1:-us-west-2}"
88
STACK_NAME="${2:-sample-data-seeder}"
99
LAYER_ARN="${3}"
1010
S3_BUCKET="${4}"
@@ -22,7 +22,7 @@ if [ -z "$LAYER_ARN" ]; then
2222
echo "Usage: ./deploy.sh [region] [stack-name] [layer-arn] [s3-bucket]"
2323
echo ""
2424
echo "Example:"
25-
echo "./deploy.sh us-east-1 sample-data-seeder arn:aws:lambda:us-east-1:123456789012:layer:uk-data-generator:1 my-deployment-bucket"
25+
echo "./deploy.sh us-west-2 sample-data-seeder arn:aws:lambda:us-west-2:123456789012:layer:uk-data-generator:1 my-deployment-bucket"
2626
exit 1
2727
fi
2828

@@ -32,7 +32,7 @@ if [ -z "$S3_BUCKET" ]; then
3232
echo "Usage: ./deploy.sh [region] [stack-name] [layer-arn] [s3-bucket]"
3333
echo ""
3434
echo "Example:"
35-
echo "./deploy.sh us-east-1 sample-data-seeder arn:aws:lambda:us-east-1:123456789012:layer:uk-data-generator:1 my-deployment-bucket"
35+
echo "./deploy.sh us-west-2 sample-data-seeder arn:aws:lambda:us-west-2:123456789012:layer:uk-data-generator:1 my-deployment-bucket"
3636
exit 1
3737
fi
3838

cloudformation/layers/uk-data-generator/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ zip -r uk-data-generator.zip python/
8080
aws cloudformation deploy \
8181
--template-file layer.yaml \
8282
--stack-name uk-data-generator-layer \
83-
--region us-east-1
83+
--region us-west-2
8484
```
8585

8686
## API Reference

cloudformation/layers/uk-data-generator/deploy.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
set -e
66

7-
REGION="${1:-us-east-1}"
7+
REGION="${1:-us-west-2}"
88
STACK_NAME="${2:-uk-data-generator-layer}"
99
LAYER_NAME="uk-data-generator"
1010

cloudformation/scenarios/council-chatbot/template.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ Resources:
133133
from datetime import datetime
134134
135135
# Initialize Bedrock client
136-
bedrock = boto3.client('bedrock-runtime', region_name='us-east-1')
136+
bedrock = boto3.client('bedrock-runtime', region_name='us-west-2')
137137
138138
# Council assistant system prompt
139139
SYSTEM_PROMPT = """You are a helpful UK local council service assistant for a sample council.
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Description: |
3+
NDX:Try - QuickSight Account Subscription
4+
Creates QuickSight account subscription if not already subscribed.
5+
Must be deployed before quicksight-dashboard main template.
6+
7+
Parameters:
8+
NotificationEmail:
9+
Type: String
10+
Default: 'noreply@example.com'
11+
Description: Email for QuickSight notifications
12+
13+
Resources:
14+
QuickSightSubscriptionRole:
15+
Type: AWS::IAM::Role
16+
Properties:
17+
RoleName: !Sub 'ndx-quicksight-subscription-${AWS::Region}'
18+
AssumeRolePolicyDocument:
19+
Version: '2012-10-17'
20+
Statement:
21+
- Effect: Allow
22+
Principal:
23+
Service: lambda.amazonaws.com
24+
Action: sts:AssumeRole
25+
ManagedPolicyArns:
26+
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
27+
Policies:
28+
- PolicyName: QuickSightSubscriptionPolicy
29+
PolicyDocument:
30+
Version: '2012-10-17'
31+
Statement:
32+
- Effect: Allow
33+
Action:
34+
- quicksight:CreateAccountSubscription
35+
- quicksight:DescribeAccountSubscription
36+
- quicksight:DeleteAccountSubscription
37+
- quicksight:ListUsers
38+
- quicksight:RegisterUser
39+
- quicksight:DescribeUser
40+
- ds:DescribeDirectories
41+
- ds:AuthorizeApplication
42+
- ds:UnauthorizeApplication
43+
- ds:CheckAlias
44+
- ds:CreateAlias
45+
- ds:CreateIdentityPoolDirectory
46+
- ds:DeleteDirectory
47+
- iam:CreateServiceLinkedRole
48+
Resource: '*'
49+
Tags:
50+
- Key: Project
51+
Value: ndx-try
52+
- Key: Scenario
53+
Value: quicksight-subscription
54+
55+
QuickSightSubscriptionFunction:
56+
Type: AWS::Lambda::Function
57+
Properties:
58+
FunctionName: !Sub 'ndx-quicksight-subscription-${AWS::Region}'
59+
Description: Creates QuickSight account subscription if not exists
60+
Runtime: python3.12
61+
Handler: index.handler
62+
Role: !GetAtt QuickSightSubscriptionRole.Arn
63+
Timeout: 300
64+
MemorySize: 256
65+
Environment:
66+
Variables:
67+
ACCOUNT_ID: !Ref AWS::AccountId
68+
REGION: !Ref AWS::Region
69+
NOTIFICATION_EMAIL: !Ref NotificationEmail
70+
Code:
71+
ZipFile: |
72+
import json
73+
import boto3
74+
import urllib3
75+
import os
76+
import time
77+
78+
http = urllib3.PoolManager()
79+
80+
def send_cfn_response(event, context, status, data=None, physical_id=None, reason=None):
81+
response_body = {
82+
'Status': status,
83+
'Reason': reason or f'See CloudWatch Log Stream: {context.log_stream_name}',
84+
'PhysicalResourceId': physical_id or context.log_stream_name,
85+
'StackId': event['StackId'],
86+
'RequestId': event['RequestId'],
87+
'LogicalResourceId': event['LogicalResourceId'],
88+
'Data': data or {}
89+
}
90+
json_response = json.dumps(response_body).encode('utf-8')
91+
headers = {'Content-Type': 'application/json', 'Content-Length': str(len(json_response))}
92+
try:
93+
http.request('PUT', event['ResponseURL'], body=json_response, headers=headers)
94+
except Exception as e:
95+
print(f"Failed to send response: {str(e)}")
96+
97+
def handler(event, context):
98+
print(f"Event: {json.dumps(event)}")
99+
100+
account_id = os.environ['ACCOUNT_ID']
101+
region = os.environ['REGION']
102+
notification_email = os.environ['NOTIFICATION_EMAIL']
103+
request_type = event.get('RequestType')
104+
105+
quicksight = boto3.client('quicksight', region_name=region)
106+
107+
try:
108+
if request_type == 'Delete':
109+
send_cfn_response(event, context, 'SUCCESS',
110+
physical_id=f'quicksight-subscription-{account_id}',
111+
reason='QuickSight subscription retained')
112+
return
113+
114+
def get_active_user():
115+
"""Find an active QuickSight user for CloudFormation permissions"""
116+
try:
117+
users = quicksight.list_users(AwsAccountId=account_id, Namespace='default')
118+
# First try to find an active user (preferring simple names without /)
119+
active_users = [u for u in users.get('UserList', []) if u.get('Active', False)]
120+
for user in active_users:
121+
uname = user.get('UserName', '')
122+
if '/' not in uname:
123+
print(f"Found active user without slash: {uname}")
124+
return uname
125+
# If no simple active user, use any active user
126+
if active_users:
127+
uname = active_users[0].get('UserName', '')
128+
print(f"Using active user: {uname}")
129+
return uname
130+
# No active users - return any user
131+
if users.get('UserList'):
132+
uname = users['UserList'][0].get('UserName', '')
133+
print(f"No active users, using: {uname}")
134+
return uname
135+
except Exception as e:
136+
print(f"Could not list users: {e}")
137+
return 'admin'
138+
139+
# Check if already subscribed
140+
try:
141+
response = quicksight.describe_account_subscription(AwsAccountId=account_id)
142+
account_info = response.get('AccountInfo', {})
143+
print(f"QuickSight already subscribed: {account_info}")
144+
145+
# Get an active user for CloudFormation permissions
146+
username = get_active_user()
147+
148+
send_cfn_response(event, context, 'SUCCESS',
149+
data={'AccountName': account_info.get('AccountName', ''), 'Username': username, 'AlreadySubscribed': 'true'},
150+
physical_id=f'quicksight-subscription-{account_id}',
151+
reason='QuickSight already subscribed')
152+
return
153+
154+
except quicksight.exceptions.ResourceNotFoundException:
155+
print("QuickSight not subscribed, creating subscription...")
156+
except Exception as e:
157+
if 'ResourceNotFoundException' in str(type(e).__name__) or 'not found' in str(e).lower():
158+
print("QuickSight not subscribed, creating subscription...")
159+
else:
160+
raise
161+
162+
print("Creating QuickSight account subscription...")
163+
response = quicksight.create_account_subscription(
164+
AwsAccountId=account_id,
165+
AccountName=f'ndx-try-{account_id}',
166+
NotificationEmail=notification_email,
167+
Edition='ENTERPRISE',
168+
AuthenticationMethod='IAM_AND_QUICKSIGHT'
169+
)
170+
print(f"Subscription response: {response}")
171+
172+
# Wait for subscription to be ready
173+
for i in range(30):
174+
time.sleep(10)
175+
try:
176+
desc = quicksight.describe_account_subscription(AwsAccountId=account_id)
177+
status = desc.get('AccountInfo', {}).get('AccountSubscriptionStatus', '')
178+
print(f"Subscription status: {status}")
179+
if status == 'ACCOUNT_CREATED':
180+
break
181+
except Exception as e:
182+
print(f"Waiting for subscription... {e}")
183+
184+
# Get an active user for CloudFormation permissions
185+
username = get_active_user()
186+
187+
send_cfn_response(event, context, 'SUCCESS',
188+
data={'AccountName': f'ndx-try-{account_id}', 'Username': username, 'AlreadySubscribed': 'false'},
189+
physical_id=f'quicksight-subscription-{account_id}',
190+
reason='QuickSight subscription created')
191+
192+
except Exception as e:
193+
print(f"Error: {str(e)}")
194+
send_cfn_response(event, context, 'FAILED', reason=str(e))
195+
Tags:
196+
- Key: Project
197+
Value: ndx-try
198+
- Key: Scenario
199+
Value: quicksight-subscription
200+
201+
QuickSightSubscriptionLogGroup:
202+
Type: AWS::Logs::LogGroup
203+
Properties:
204+
LogGroupName: !Sub '/aws/lambda/${QuickSightSubscriptionFunction}'
205+
RetentionInDays: 7
206+
Tags:
207+
- Key: Project
208+
Value: ndx-try
209+
- Key: Scenario
210+
Value: quicksight-subscription
211+
212+
QuickSightSubscription:
213+
Type: AWS::CloudFormation::CustomResource
214+
DependsOn:
215+
- QuickSightSubscriptionLogGroup
216+
Properties:
217+
ServiceToken: !GetAtt QuickSightSubscriptionFunction.Arn
218+
ServiceTimeout: 300
219+
Timestamp: !Sub '${AWS::StackName}-subscription-v3'
220+
221+
Outputs:
222+
QuickSightUsername:
223+
Description: QuickSight username for resource permissions
224+
Value: !GetAtt QuickSightSubscription.Username
225+
Export:
226+
Name: !Sub '${AWS::StackName}-QuickSightUsername'
227+
228+
QuickSightAccountName:
229+
Description: QuickSight account name
230+
Value: !GetAtt QuickSightSubscription.AccountName
231+
Export:
232+
Name: !Sub '${AWS::StackName}-QuickSightAccountName'
233+
234+
AlreadySubscribed:
235+
Description: Whether QuickSight was already subscribed
236+
Value: !GetAtt QuickSightSubscription.AlreadySubscribed
237+
Export:
238+
Name: !Sub '${AWS::StackName}-AlreadySubscribed'

0 commit comments

Comments
 (0)