|
| 1 | +# Copyright 2020 Planet Labs, Inc. |
| 2 | +# |
| 3 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +# you may not use this file except in compliance with the License. |
| 5 | +# You may obtain a copy of the License at |
| 6 | +# |
| 7 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +# |
| 9 | +# Unless required by applicable law or agreed to in writing, software |
| 10 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +# See the License for the specific language governing permissions and |
| 13 | +# limitations under the License. |
| 14 | + |
| 15 | +''' |
| 16 | +Test CLI download. This creates an order, waits for it to be ready, then |
| 17 | +downloads it, and confirms all files were downloaded. |
| 18 | +
|
| 19 | +Because download is spotty, this runs download multiple times and ensures that |
| 20 | +each time all files were downloaded. |
| 21 | +''' |
| 22 | +import argparse |
| 23 | +import json |
| 24 | +import logging |
| 25 | +import os |
| 26 | +import subprocess |
| 27 | +import sys |
| 28 | +import tempfile |
| 29 | +import time |
| 30 | + |
| 31 | +# from click.testing import CliRunner |
| 32 | +import requests |
| 33 | +from requests.auth import HTTPBasicAuth |
| 34 | + |
| 35 | + |
| 36 | +# logging.basicConfig(filename='example.log', level=logging.DEBUG) |
| 37 | +# logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) |
| 38 | + |
| 39 | +logging.basicConfig( |
| 40 | + stream=sys.stderr, level=logging.DEBUG, |
| 41 | + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' |
| 42 | +) |
| 43 | + |
| 44 | +logger = logging.getLogger(__name__) |
| 45 | +# logging.getLogger('planet.api.dispatch').setLevel(logging.WARNING) |
| 46 | +# logging.getLogger('urllib3.connectionpool').setLevel(logging.WARNING) |
| 47 | +# API Key stored as an env variable |
| 48 | +PLANET_API_KEY = os.getenv('PL_API_KEY') |
| 49 | + |
| 50 | +ORDERS_URL = 'https://api.planet.com/compute/ops/orders/v2' |
| 51 | + |
| 52 | +# equivalent to: |
| 53 | +# planet orders create --item-type SkySatScene --bundle analytic \ |
| 54 | +# --id 20200505_193841_ssc4d1_0018 --name 20200505_193841_ssc4d1_0018 |
| 55 | +ORDER_REQUEST = { |
| 56 | + "name": "20200505_193841_ssc4d1_0018", |
| 57 | + "products": [ |
| 58 | + { |
| 59 | + "item_ids": [ |
| 60 | + "20200505_193841_ssc4d1_0018" |
| 61 | + ], |
| 62 | + "item_type": "SkySatScene", |
| 63 | + "product_bundle": "analytic" |
| 64 | + } |
| 65 | + ], |
| 66 | + "state": "success", |
| 67 | + "delivery": { |
| 68 | + "archive_filename": "{{name}}_{{order_id}}.zip", |
| 69 | + "archive_type": "zip", |
| 70 | + "single_archive": True |
| 71 | + }, |
| 72 | + "tools": [ |
| 73 | + { |
| 74 | + "reproject": { |
| 75 | + "kernel": "cubic", |
| 76 | + "projection": "EPSG:4326" |
| 77 | + } |
| 78 | + } |
| 79 | + ] |
| 80 | +} |
| 81 | + |
| 82 | + |
| 83 | +def submit_order(request, auth): |
| 84 | + auth = HTTPBasicAuth(PLANET_API_KEY, '') |
| 85 | + |
| 86 | + # set content type to json |
| 87 | + headers = {'content-type': 'application/json'} |
| 88 | + |
| 89 | + response = requests.post(ORDERS_URL, |
| 90 | + data=json.dumps(request), |
| 91 | + auth=auth, |
| 92 | + headers=headers) |
| 93 | + order_id = response.json()['id'] |
| 94 | + return order_id |
| 95 | + |
| 96 | + |
| 97 | +def poll_for_success(order_url, auth, num_loops=50): |
| 98 | + count = 0 |
| 99 | + while(count < num_loops): |
| 100 | + count += 1 |
| 101 | + r = requests.get(order_url, auth=auth) |
| 102 | + response = r.json() |
| 103 | + state = response['state'] |
| 104 | + logger.info(state) |
| 105 | + end_states = ['success', 'failed', 'partial'] |
| 106 | + if state in end_states: |
| 107 | + break |
| 108 | + time.sleep(10) |
| 109 | + if state != 'success': |
| 110 | + raise Exception('order did not succeed') |
| 111 | + |
| 112 | + |
| 113 | +def test_download_order(order_id, num_runs): |
| 114 | + # # these are the files inside the zip |
| 115 | + # expected_files = [ |
| 116 | + # '20200505_193841_ssc4d1_0018_analytic_reproject.tif', |
| 117 | + # '20200505_193841_ssc4d1_0018_analytic_udm_reproject.tif', |
| 118 | + # '20200505_193841_ssc4d1_0018_metadata.json', |
| 119 | + # 'manifest.json' |
| 120 | + # ] |
| 121 | + |
| 122 | + expected_files = [ |
| 123 | + '20200505_193841_ssc4d1_0018_53d1209a-af58-40ce-974f-3570f4e20326.zip', |
| 124 | + 'manifest.json' |
| 125 | + ] |
| 126 | + |
| 127 | + messages = [] |
| 128 | + for i in range(num_runs): |
| 129 | + logging.debug('TEST {}'.format(i)) |
| 130 | + files = download_order_cli(order_id) |
| 131 | + if not len(files) == len(expected_files): |
| 132 | + messages.append('TEST {}'.format(i)) |
| 133 | + messages.append('{} != {}'.format(len(files), len(expected_files))) |
| 134 | + for f in expected_files: |
| 135 | + if f not in files: |
| 136 | + messages.append('{} not found'.format(f)) |
| 137 | + |
| 138 | + if len(messages): |
| 139 | + for m in messages: |
| 140 | + logger.info(m) |
| 141 | + else: |
| 142 | + logger.info('Success!') |
| 143 | + |
| 144 | + |
| 145 | +def download_order_cli(order_id): |
| 146 | + with tempfile.TemporaryDirectory() as tmpdirname: |
| 147 | + cmd = ['planet', '-vv', 'orders', 'download', '--dest', tmpdirname, |
| 148 | + order_id] |
| 149 | + |
| 150 | + logging.debug(cmd) |
| 151 | + _run_command_line(cmd) |
| 152 | + |
| 153 | + files = os.listdir(tmpdirname) |
| 154 | + logger.debug(files) |
| 155 | + return files |
| 156 | + |
| 157 | + |
| 158 | +def _run_command_line(cmds, stdout=None, stderr=None): |
| 159 | + try: |
| 160 | + cmds = [str(x) for x in cmds] |
| 161 | + logging.debug(' '.join(cmds)) |
| 162 | + subprocess.check_call(cmds, stdout=stdout, stderr=stderr) |
| 163 | + except OSError: |
| 164 | + raise OSError('{} not found.'.format(cmds[0])) |
| 165 | + |
| 166 | + |
| 167 | +def get_parser(): |
| 168 | + aparser = argparse.ArgumentParser( |
| 169 | + description='Submit and download an order') |
| 170 | + aparser.add_argument('-o', '--oid', |
| 171 | + help='order id') |
| 172 | + aparser.add_argument('-r', '--runs', type=int, default=5, |
| 173 | + help='number of runs') |
| 174 | + return aparser |
| 175 | + |
| 176 | + |
| 177 | +if __name__ == '__main__': |
| 178 | + args = get_parser().parse_args(sys.argv[1:]) |
| 179 | + logger.debug(args) |
| 180 | + |
| 181 | + auth = HTTPBasicAuth(PLANET_API_KEY, '') |
| 182 | + |
| 183 | + if args.oid: |
| 184 | + order_id = args.oid |
| 185 | + else: |
| 186 | + logging.debug('submitting order') |
| 187 | + order_id = submit_order(ORDER_REQUEST, auth) |
| 188 | + |
| 189 | + order_url = ORDERS_URL + '/' + order_id |
| 190 | + poll_for_success(order_url, auth) |
| 191 | + |
| 192 | + test_download_order(order_id, args.runs) |
| 193 | + logger.info('order id: {}'.format(order_id)) |
0 commit comments