Skip to content

Commit a4f0310

Browse files
author
Phil Varner
authored
Merge pull request #536 from stac-utils/pv/fix-sns-publish
fix async sns post-ingest publishing
2 parents 2997c0d + 94ffda2 commit a4f0310

File tree

5 files changed

+87
-31
lines changed

5 files changed

+87
-31
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased] - TBD
9+
10+
### Fixed
11+
12+
- Post-ingest SNS topic was not being published to when deployed as a Lambda.
13+
814
## [2.0.0] - 2023-06-26
915

1016
### Removed

README.md

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- [Migration](#migration)
99
- [0.x or 1.x -\> 2.x](#0x-or-1x---2x)
1010
- [Fine-grained Access Control](#fine-grained-access-control)
11+
- [Enabling Post-ingest SNS publishing](#enabling-post-ingest-sns-publishing)
1112
- [0.4.x -\> 0.5.x](#04x---05x)
1213
- [Elasticsearch to OpenSearch Migration](#elasticsearch-to-opensearch-migration)
1314
- [Preferred Elasticsearch to OpenSearch Migration Process](#preferred-elasticsearch-to-opensearch-migration-process)
@@ -135,6 +136,49 @@ As of 2.0.0, only OpenSearch is supported and only using fine-grained access con
135136
It is recommended to follow the migration path to upgrade to fine-grained access control
136137
first and then upgrade to stac-server 2.x.
137138

139+
#### Enabling Post-ingest SNS publishing
140+
141+
stac-server now has the ability to publish all ingested entities (Items and Collections)
142+
to an SNS topic. Follow these steps to add this to an existing deployment. These
143+
configurations are also in the serverless.example.yml file, so reference that if it is
144+
unclear exactly where to add this in your config.
145+
146+
The following changes should be added to the serverless.yml file.
147+
148+
Explicitly set the provider/environment setting for STAC_API_URL so the ingested entities
149+
published to the topic will have their link hrefs set correctly. If this is not set,
150+
the entities will still be published, with with incorrect link hrefs.
151+
152+
```text
153+
STAC_API_URL: "https://some-stac-server.com"
154+
```
155+
156+
Add the SNS topic resource:
157+
158+
```text
159+
postIngestTopic:
160+
Type: AWS::SNS::Topic
161+
Properties:
162+
TopicName: ${self:service}-${self:provider.stage}-post-ingest
163+
```
164+
165+
For the `ingest` Lambda resource definition, configure the ARN to publish to by adding:
166+
167+
```text
168+
environment:
169+
POST_INGEST_TOPIC_ARN: !Ref postIngestTopic
170+
```
171+
172+
Add IAM permissions with the statement:
173+
174+
```text
175+
- Effect: Allow
176+
Action:
177+
- sns:Publish
178+
Resource:
179+
Fn::GetAtt: [postIngestTopic, TopicArn]
180+
```
181+
138182
### 0.4.x -> 0.5.x
139183

140184
#### Elasticsearch to OpenSearch Migration
@@ -521,11 +565,9 @@ aws lambda invoke \
521565
/dev/stdout
522566
```
523567

524-
Stac-server is now ready to ingest data!
525-
526568
#### OpenSearch fine-grained access control
527569

528-
As of version 2.0.0, stac-server on"ly supports fine-grained access control to
570+
As of version 2.0.0, stac-server only supports fine-grained access control to
529571
OpenSearch, and no longer supports "AWS Connection" mode.
530572

531573
**Warning**: Unfortunately, fine-grained access control cannot be enabled on an
@@ -634,8 +676,8 @@ so that stac-server can access them.
634676
The preferred mechanism for populating the OpenSearch credentials to stac-server is to
635677
create a secret in AWS Secret Manager that contains the username and password. The
636678
recommended name for this Secret corresponds
637-
to the stac-server deployment as `{stage}/{service}/opensearch`, e.g.,
638-
`dev/my-stac-server/opensearch`.
679+
to the stac-server deployment as `${service}-${stage}-opensearch-user-creds`, e.g.,
680+
`my-stac-server-dev-opensearch-user-creds`.
639681

640682
The Secret type should be "Other type of secret" and
641683
have two keys, `username` and `password`, with the appropriate
@@ -645,14 +687,14 @@ Add the `OPENSEARCH_CREDENTIALS_SECRET_ID` variable to the serverless.yml sectio
645687
`environment`:
646688

647689
```yaml
648-
OPENSEARCH_CREDENTIALS_SECRET_ID: ${self:provider.stage}/${self:service}/opensearch
690+
OPENSEARCH_CREDENTIALS_SECRET_ID: ${self:service}-${self:provider.stage}-opensearch-user-creds
649691
```
650692

651693
Add to the IAM Role Statements:
652694

653695
```yaml
654-
- Effect: "Allow"
655-
Resource: "arn:aws:secretsmanager:${aws:region}:${aws:accountId}:secret:${self:provider.stage}/${self:service}/opensearch-*"
696+
- Effect: Allow
697+
Resource: arn:aws:secretsmanager:${aws:region}:${aws:accountId}:secret:${self:provider.environment.OPENSEARCH_CREDENTIALS_SECRET_ID}-*
656698
Action: "secretsmanager:GetSecretValue"
657699
```
658700

@@ -674,6 +716,8 @@ OPENSEARCH_PASSWORD: xxxxxxxxxxx
674716
Setting these as environment variables can also be useful when running stac-server
675717
locally.
676718

719+
Stac-server is now ready to ingest data!
720+
677721
### Proxying Stac-server through CloudFront
678722

679723
The API Gateway URL associated with the deployed stac-server instance may not be the URL that you ultimately wish to expose to your API users. AWS CloudFront can be used to proxy to a more human readable URL. In order to accomplish this:

serverless.example.yml

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,25 @@ provider:
2929
iam:
3030
role:
3131
statements:
32-
- Effect: "Allow"
32+
- Effect: Allow
3333
Resource: "arn:aws:es:${aws:region}:${aws:accountId}:domain/*"
3434
Action: "es:*"
35-
- Effect: "Allow"
35+
- Effect: Allow
3636
Action:
3737
- sqs:GetQueueUrl
3838
- sqs:SendMessage
3939
- sqs:ReceiveMessage
4040
- sqs:DeleteMessage
4141
Resource:
4242
Fn::GetAtt: [ingestQueue, Arn]
43+
- Effect: Allow
44+
Action:
45+
- sns:Publish
46+
Resource:
47+
Fn::GetAtt: [postIngestTopic, Arn]
4348
- Effect: Allow
4449
Action: s3:GetObject
45-
Resource: 'arn:aws:s3:::usgs-landsat/*'
50+
Resource: "arn:aws:s3:::usgs-landsat/*"
4651
- Effect: Allow
4752
Resource: arn:aws:secretsmanager:${aws:region}:${aws:accountId}:secret:${self:provider.environment.OPENSEARCH_CREDENTIALS_SECRET_ID}-*
4853
Action: secretsmanager:GetSecretValue
@@ -107,14 +112,14 @@ resources:
107112
Description: A STAC API running on stac-server
108113
Resources:
109114
ingestTopic:
110-
Type: "AWS::SNS::Topic"
115+
Type: AWS::SNS::Topic
111116
Properties:
112117
TopicName: ${self:service}-${self:provider.stage}-ingest
113118
postIngestTopic:
114-
# After a collection or item is ingested, the status of the ingest (success
115-
# or failure) along with details of the collection or item are sent to this
116-
# SNS topic. To take future action on items after they are ingested
117-
# suscribe an endpoint to this topic
119+
# After a collection or item is ingested, the status of the ingest (success
120+
# or failure) along with details of the collection or item are sent to this
121+
# SNS topic. To take future action on items after they are ingested
122+
# suscribe an endpoint to this topic
118123
Type: AWS::SNS::Topic
119124
Properties:
120125
TopicName: ${self:service}-${self:provider.stage}-post-ingest
@@ -156,7 +161,7 @@ resources:
156161
TopicArn: !Ref ingestTopic
157162
OpenSearchInstance:
158163
Type: AWS::OpenSearchService::Domain
159-
DeletionPolicy : Retain
164+
DeletionPolicy: Retain
160165
UpdateReplacePolicy: Retain
161166
UpdatePolicy:
162167
EnableVersionUpgrade: true
@@ -187,13 +192,13 @@ resources:
187192
MasterUserOptions:
188193
MasterUserName: admin
189194
MasterUserPassword: ${env:OPENSEARCH_MASTER_USER_PASSWORD}
190-
AccessPolicies:
191-
Version: "2012-10-17"
192-
Statement:
193-
- Effect: "Allow"
194-
Principal: { "AWS": "*" }
195-
Action: "es:ESHttp*"
196-
Resource: "arn:aws:es:${aws:region}:${aws:accountId}:domain/${self:service}-${self:provider.stage}/*"
195+
AccessPolicies:
196+
Version: "2012-10-17"
197+
Statement:
198+
- Effect: "Allow"
199+
Principal: { "AWS": "*" }
200+
Action: "es:ESHttp*"
201+
Resource: "arn:aws:es:${aws:region}:${aws:accountId}:domain/${self:service}-${self:provider.stage}/*"
197202
Outputs:
198203
OpenSearchEndpoint:
199204
Value:

src/lambdas/ingest/index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const handler = async (event, _context) => {
5353

5454
if (event.create_indices) {
5555
await createIndex('collections')
56+
return
5657
}
5758

5859
const stacItems = isSqsEvent(event)
@@ -67,9 +68,9 @@ export const handler = async (event, _context) => {
6768

6869
if (postIngestTopicArn) {
6970
logger.debug('Publishing to post-ingest topic: %s', postIngestTopicArn)
70-
publishResultsToSns(results, postIngestTopicArn)
71+
await publishResultsToSns(results, postIngestTopicArn)
7172
} else {
72-
logger.debug('Skkipping post-ingest notification since no topic is configured')
73+
logger.debug('Skipping post-ingest notification since no topic is configured')
7374
}
7475
} catch (error) {
7576
logger.error(error)

src/lib/ingest.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ export async function convertIngestObjectToDbObject(
2828
index = data.collection
2929
} else {
3030
throw new InvalidIngestError(
31-
`Expeccted data.type to be "Collection" or "Feature" not ${data.type}`
31+
`Expected data.type to be "Collection" or "Feature" not ${data.type}`
3232
)
3333
}
3434

3535
// remove any hierarchy links in a non-mutating way
3636
if (!data.links) {
37-
throw new InvalidIngestError('Expected a "links" proporty on the stac object')
37+
throw new InvalidIngestError('Expected a "links" property on the stac object')
3838
}
3939
const links = data.links.filter(
4040
(/** @type {{ rel: string; }} */ link) => !hierarchyLinks.includes(link.rel)
@@ -187,11 +187,11 @@ function updateLinksWithinRecord(record) {
187187
return record
188188
}
189189

190-
export function publishResultsToSns(results, topicArn) {
191-
results.forEach(async (result) => {
190+
export async function publishResultsToSns(results, topicArn) {
191+
await Promise.allSettled(results.map(async (result) => {
192192
if (result.record && !result.error) {
193193
updateLinksWithinRecord(result.record)
194194
}
195195
await publishRecordToSns(topicArn, result.record, result.error)
196-
})
196+
}))
197197
}

0 commit comments

Comments
 (0)