Skip to content

Commit 1fe8abe

Browse files
committed
merged
2 parents b8d7fc8 + 8a2a519 commit 1fe8abe

16 files changed

+169
-39
lines changed

.dockerignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
./build
2+
./dist
3+
./epl.egg-info
4+
./index
5+
./venv
6+
*.tar.gz
7+
**/__pycache__

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
21
.idea
32
venv
43
index
54
*.tar.gz
6-
__pycache__/
5+
**/__pycache__
76
dist
87
epl.egg-info
98
.ipynb_checkpoints/
109
build/
10+
naip_visual_db-*

Dockerfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM python:slim
2+
3+
WORKDIR /opt/src/naip-stac-grpc
4+
COPY ./ ./
5+
6+
RUN pip install -r requirements.txt
7+
8+
RUN python -mgrpc_tools.protoc -I=./protos --python_out=./ \
9+
./protos/epl/protobuf/geometry_operators.proto ./protos/epl/protobuf/stac.proto \
10+
./protos/epl/protobuf/stac_item_result.proto
11+
RUN python -mgrpc_tools.protoc -I=./protos --grpc_python_out=./ \
12+
./protos/epl/grpc/naip_stac.proto
13+
14+
RUN python setup.py install
15+
16+
CMD python service.py

NAIP_TEST.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@
303303
"Session = rasterio.Env(\n",
304304
" AWS_REQUEST_PAYER='requester',\n",
305305
" GDAL_DISABLE_READDIR_ON_OPEN='YES',\n",
306-
" AWS_PROFILE='${HOME}/.aws/credentials')\n",
306+
" AWS_PROFILE='${HOME}/.aws/naip-download.csv')\n",
307307
"\n",
308308
"assets = metadata_result.assets\n",
309309
"for asset_key in assets:\n",

README.md

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,56 @@
11
# STAC + NAIP + gRPC Metadata Service
22
This is a first version of a [gRPC](https://grpc.io/) service and [protobuf](https://developers.google.com/protocol-buffers/) definition for serving [NAIP](https://registry.opendata.aws/naip/) metadata that tries to be [STAC](https://github.com/radiantearth/stac-spec) compliant.
33

4+
## TLDR
5+
Requirements:
6+
* `aws` [cli tool](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)
7+
* AWS s3 requester pays authorization in ~/.aws/credentials (`aws configure` to setup)
8+
* `ogr2ogr` with postgres extensions
9+
* docker + docker-compose
10+
* [virtualenv](https://virtualenv.pypa.io/en/latest/installation/)
11+
12+
#### Commands
13+
There are two different ways to test the gRPC service. One is with a postgis docker container and the other is with a docker-compose db+service. Both require this initial set of commands.
14+
15+
Initial commands will download a gig or more of shapefiles to your local machine and prepare a database:
16+
```bash
17+
git clone git@github.com:geo-grpc/naip-stac-grpc.git
18+
cd naip-stac-grpc
19+
virtualenv venv
20+
source venv/bin/activate
21+
./download_shapefiles.sh
22+
./naip_import_aws.sh
23+
```
24+
25+
Test version 1; test with the local docker database:
26+
```bash
27+
pip3 install -r requirements.txt
28+
python3 setup.py install
29+
python3 service.py
30+
python3 test_client.py
31+
```
32+
33+
Test version 2; test with docker-compose initialized with a pg_dump file:
34+
```bash
35+
# dump postgres table to file
36+
docker exec naip-metadata-postgis pg_dump -U user -Fc \
37+
-t naip_visual testdb > ./naip_visual_db-$(date +%Y-%m-%d)
38+
docker stop naip-metadata-postgis
39+
docker-compose up --build -d
40+
# wait for postgres db to initialize. you could omit the `-d` and
41+
# watch for the initialization completion and execute the rest of
42+
# the command from another window
43+
sleep 15
44+
docker exec -i naip-stac-grpc_db_1 pg_restore -C --clean --no-acl --no-owner \
45+
-U user -d testdb < ./naip_visual_db-$(date +%Y-%m-%d)
46+
pip3 install -r requirements.txt
47+
python3 test_client.py
48+
```
49+
50+
51+
52+
53+
454
## STAC, Protocol Buffers, and gPRC
555

656
#### Protobuf Defintions
@@ -26,7 +76,7 @@ This stac experiment imports a geometry proto definition used in another gRPC pr
2676
#### Requirements
2777
install requirements:
2878
```bash
29-
pip3 install -r requirements
79+
pip3 install -r requirements.txt
3080
```
3181

3282
#### Protoc Compile Step (Optional)
@@ -57,7 +107,7 @@ GDAL + ogr2ogr + postgresql:
57107
brew install gdal2 --with-postgresql
58108
```
59109

60-
To collect all the data data from the AWS NAIP shapefiles you'll need to execute the included bash script, `naip_import_aws.sh`.
110+
To collect all the data data from the AWS NAIP shapefiles (a gig or more) you'll need to execute the included bash script, `naip_import_aws.sh`.
61111

62112
## Testing
63113

docker-compose.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
version: '3'
2+
services:
3+
naip-stac-grpc:
4+
container_name: naip-stac-grpc-service-c
5+
image: us.gcr.io/echoparklabs/naip-stac-grpc
6+
build:
7+
context: .
8+
dockerfile: Dockerfile
9+
depends_on:
10+
- db
11+
networks:
12+
- naip
13+
ports:
14+
- "50051:50051"
15+
environment:
16+
- POSTGRES_HOST=db
17+
- POSTGRES_PORT=5432
18+
19+
db:
20+
container_name: naip-stac-grpc-db-c
21+
image: mdillon/postgis
22+
ports:
23+
- "5432:5432"
24+
networks:
25+
- naip
26+
environment:
27+
- POSTGRES_PASSWORD=cabbage
28+
- POSTGRES_USER=user
29+
- POSTGRES_DB=testdb
30+
31+
networks:
32+
naip: {}

download_shapefiles.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env bash
2+
3+
STATES=(al ar az ca co ct de fl ga ia id il in ks ky la ma md me mi mn mo ms mt nc nd ne nh nj nm nv ny oh ok or pa ri sc sd tn tx ut va vt wa wi wv wy)
4+
END_YEAR=$(date +'%Y')
5+
FAILING_SHAPEFILES=(naip_3_172_6_fl naip_3_17_2_8_sc naip_3_17_2_2_pa)
6+
7+
for state in "${STATES[@]}"
8+
do
9+
for year in $(seq 2011 $END_YEAR)
10+
do
11+
echo s3 cp s3://naip-visualization/$state/$year/60cm/index/ ./index/ --request-payer --recursive
12+
# if the bucket doesn't exist these copies won't do anything at all
13+
aws s3 cp s3://naip-visualization/$state/$year/60cm/index/ ./index/ --request-payer --recursive
14+
echo s3 cp s3://naip-visualization/$state/$year/100cm/index/ ./index/ --request-payer --recursive
15+
aws s3 cp s3://naip-visualization/$state/$year/100cm/index/ ./index/ --request-payer --recursive
16+
done
17+
done

epl/asset.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,3 @@ def extract_naip_s3_path(metadata_request: stac_pb2.MetadataRequest,
8888
write_asset(s3_path_template, imagery_bands, asset_type, metadata_result.assets)
8989
else:
9090
write_asset(s3_path_template, imagery_bands, stac_pb2.GEOTIFF, metadata_result.assets)
91-
92-
93-
94-
95-

epl/store.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from epl import parse, asset
2424
from datetime import datetime, timezone
2525

26-
from sqlalchemy import Table, Column, Integer, String, MetaData, Date, Float, create_engine
26+
from sqlalchemy import Table, Column, Integer, String, MetaData, Date, Float
2727
from geoalchemy2 import Geometry
2828
from geoalchemy2.elements import WKTElement, WKBElement
2929
from sqlalchemy.sql import select, and_

epl/store_test.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
import unittest
2-
from epl.protobuf import geometry_operators_pb2 as geometry
3-
from epl.protobuf import stac_pb2 as stac
4-
from epl import store, parse
5-
from google.protobuf.timestamp_pb2 import Timestamp
2+
import os
63

74
from datetime import datetime, timezone
85

96
from sqlalchemy import Table, Column, Integer, String, MetaData, Date, Float, create_engine
107
from geoalchemy2 import Geometry
118
from sqlalchemy.sql import select, and_
9+
from google.protobuf.timestamp_pb2 import Timestamp
10+
11+
from epl.protobuf import geometry_operators_pb2 as geometry
12+
from epl.protobuf import stac_pb2 as stac
13+
from epl import store, parse
14+
15+
16+
POSTGRES_HOST = os.getenv('POSTGRES_HOST', 'localhost')
17+
POSTGRES_PORT = os.getenv('POSTGRES_PORT', 5432)
1218

1319
metadata = MetaData()
1420
naip_visual = Table('naip_visual', metadata,
@@ -22,7 +28,8 @@
2228

2329
class TestStore(unittest.TestCase):
2430
def setUp(self):
25-
engine = create_engine('postgresql://user:cabbage@localhost:5432/testdb', echo=True)
31+
engine = create_engine('postgresql://user:cabbage@{0}:{1}/testdb'.format(POSTGRES_HOST, POSTGRES_PORT),
32+
echo=True)
2633
self.postgres_access = store.PostgresStore(db_engine=engine)
2734

2835
def test_simple_date_2(self):
@@ -39,7 +46,8 @@ def test_simple_date_2(self):
3946
offset = 0
4047
current_and = None
4148
if metadata_req:
42-
current_and = and_(naip_visual.c.srcimgdate >= datetime.fromtimestamp(metadata_req.src_img_date.value.seconds, timezone.utc))
49+
current_and = and_(naip_visual.c.srcimgdate >= datetime.fromtimestamp(
50+
metadata_req.src_img_date.value.seconds, timezone.utc))
4351
s = select([naip_visual], current_and).limit(limit).offset(offset)
4452

4553
conn = self.postgres_access.db_engine.connect()

naip_import_aws.sh

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,17 @@ STATES=(al ar az ca co ct de fl ga ia id il in ks ky la ma md me mi mn mo ms mt
33
END_YEAR=$(date +'%Y')
44
FAILING_SHAPEFILES=(naip_3_172_6_fl naip_3_17_2_8_sc naip_3_17_2_2_pa)
55

6-
for state in "${STATES[@]}"
7-
do
8-
for year in $(seq 2011 $END_YEAR)
9-
do
10-
echo s3://naip-visualization/$state/$year/60cm/index/
11-
# if the bucket doesn't exist these copies won't do anything at all
12-
aws s3 cp s3://naip-visualization/$state/$year/60cm/index/ ./index/ --request-payer --recursive
13-
echo s3://naip-visualization/$state/$year/100cm/index/
14-
aws s3 cp s3://naip-visualization/$state/$year/100cm/index/ ./index/ --request-payer --recursive
15-
done
16-
done
17-
186
cd index
197

208
# TODO contact ESRI bucket owner about broken prj files
219
# Failures
2210
# naip_3_13_2_1_al
2311
# GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]
2412
docker rm -f naip-metadata-postgis
25-
docker run -d --env POSTGRES_PASSWORD=cabbage --env POSTGRES_USER=user --env POSTGRES_DB=testdb -p 5432:5432 --name=naip-metadata-postgis mdillon/postgis
13+
docker run -d --env POSTGRES_PASSWORD=cabbage \
14+
--env POSTGRES_USER=user \
15+
--env POSTGRES_DB=testdb \
16+
-p 5432:5432 --name=naip-metadata-postgis mdillon/postgis
2617
echo starting db
2718
sleep 40
2819

@@ -83,8 +74,4 @@ docker exec -it naip-metadata-postgis /bin/bash -c "psql -qtA -d testdb -U user
8374
echo altering dates from varchar to dates
8475
docker exec -it naip-metadata-postgis /bin/bash -c "psql -qtA -d testdb -U user -c \"ALTER TABLE naip_visual ALTER COLUMN verdate TYPE DATE USING to_date(verdate, 'YYYYMMDD'); ALTER TABLE naip_visual ALTER COLUMN srcimgdate TYPE DATE USING to_date(srcimgdate, 'YYYYMMDD');\""
8576

86-
# dump postgres table to file
87-
echo dumping everything to file
88-
docker exec naip-metadata-postgis pg_dump -U user -F t -t naip_visual testdb | gzip > ./naip_visual_db-$(date +%Y-%m-%d).tar.gz
89-
9077
echo finished all tasks!

requirements-jupyter.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
jupyter
2+
rasterio
3+
boto3
4+
matplotlib

requirements-test.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pytest
2+
pytest-flake8

service.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
GRPC_CHAIN = os.getenv('GRPC_CHAIN', None)
3939
GRPC_KEY = os.getenv('GRPC_KEY', None)
4040

41+
POSTGRES_HOST = os.getenv('POSTGRES_HOST', 'localhost')
42+
POSTGRES_PORT = os.getenv('POSTGRES_PORT', 5432)
43+
4144
MAX_MESSAGE_MB = os.getenv('MAX_MESSAGE_MB', 64)
4245
BYTES_PER_MB = 1024 * 1024
4346
# https://github.com/grpc/grpc/issues/7927
@@ -66,7 +69,7 @@ def serve():
6669
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10), options=GRPC_CHANNEL_OPTIONS)
6770

6871
# db connection
69-
engine = create_engine('postgresql://user:cabbage@localhost:5432/testdb', echo=True)
72+
engine = create_engine('postgresql://user:cabbage@{0}:{1}/testdb'.format(POSTGRES_HOST, POSTGRES_PORT), echo=True)
7073

7174
# add metadata service
7275
naip_grpc.add_MetadataOperatorsServicer_to_server(MetadataServicer(engine), server)

setup.cfg

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[tool:pytest]
2+
flake8-max-line-length = 120
3+
4+
# these two can be ignored as they are generated or provided by google.
5+
flake8-ignore =
6+
epl/protobuf/stac_pb2.py ALL
7+
epl/protobuf/stac_item_result_pb2.py ALL
8+
epl/protobuf/geometry_operators_pb2.py ALL
9+
epl/grpc/naip_stac_pb2_grpc.py ALL

test_client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212

1313
MB = 1024 * 1024
1414
GRPC_CHANNEL_OPTIONS = [('grpc.max_message_length', 64 * MB), ('grpc.max_receive_message_length', 64 * MB)]
15-
GRPC_SERVICE_PORT = os.getenv('GRPC_SERVICE_PORT', 50051)
16-
GRPC_SERVICE_HOST = os.getenv('GRPC_SERVICE_HOST', 'localhost')
17-
IMAGERY_SERVICE = "{0}:{1}".format(GRPC_SERVICE_HOST, GRPC_SERVICE_PORT)
15+
NAIP_SERVICE_PORT = os.getenv('NAIP_SERVICE_PORT', 50051)
16+
NAIP_SERVICE_HOST = os.getenv('NAIP_SERVICE_HOST', 'localhost')
17+
IMAGERY_SERVICE = "{0}:{1}".format(NAIP_SERVICE_HOST, NAIP_SERVICE_PORT)
1818
ip_reg = re.compile(r"[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}")
1919

20-
if GRPC_SERVICE_HOST == "localhost" or ip_reg.match(GRPC_SERVICE_HOST):
20+
if NAIP_SERVICE_HOST == "localhost" or ip_reg.match(NAIP_SERVICE_HOST):
2121
channel = grpc.insecure_channel(IMAGERY_SERVICE, options=GRPC_CHANNEL_OPTIONS)
2222
else:
2323
channel_credentials = grpc.ssl_channel_credentials()

0 commit comments

Comments
 (0)