eodag 3.10.1__py3-none-any.whl → 4.0.0a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eodag/__init__.py +6 -1
- eodag/api/collection.py +353 -0
- eodag/api/core.py +606 -641
- eodag/api/product/__init__.py +3 -3
- eodag/api/product/_product.py +74 -56
- eodag/api/product/drivers/__init__.py +4 -46
- eodag/api/product/drivers/base.py +0 -28
- eodag/api/product/metadata_mapping.py +178 -216
- eodag/api/search_result.py +156 -15
- eodag/cli.py +83 -403
- eodag/config.py +81 -51
- eodag/plugins/apis/base.py +2 -2
- eodag/plugins/apis/ecmwf.py +36 -25
- eodag/plugins/apis/usgs.py +55 -40
- eodag/plugins/authentication/base.py +1 -3
- eodag/plugins/crunch/filter_date.py +3 -3
- eodag/plugins/crunch/filter_latest_intersect.py +2 -2
- eodag/plugins/crunch/filter_latest_tpl_name.py +1 -1
- eodag/plugins/download/aws.py +46 -42
- eodag/plugins/download/base.py +13 -14
- eodag/plugins/download/http.py +65 -65
- eodag/plugins/manager.py +28 -29
- eodag/plugins/search/__init__.py +6 -4
- eodag/plugins/search/base.py +131 -80
- eodag/plugins/search/build_search_result.py +245 -173
- eodag/plugins/search/cop_marine.py +87 -56
- eodag/plugins/search/csw.py +47 -37
- eodag/plugins/search/qssearch.py +653 -429
- eodag/plugins/search/stac_list_assets.py +1 -1
- eodag/plugins/search/static_stac_search.py +43 -44
- eodag/resources/{product_types.yml → collections.yml} +2594 -2453
- eodag/resources/ext_collections.json +1 -1
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/providers.yml +2706 -2733
- eodag/resources/stac_provider.yml +50 -92
- eodag/resources/user_conf_template.yml +9 -0
- eodag/types/__init__.py +2 -0
- eodag/types/queryables.py +70 -91
- eodag/types/search_args.py +1 -1
- eodag/utils/__init__.py +97 -21
- eodag/utils/dates.py +0 -12
- eodag/utils/exceptions.py +6 -6
- eodag/utils/free_text_search.py +3 -3
- eodag/utils/repr.py +2 -0
- {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/METADATA +13 -99
- eodag-4.0.0a2.dist-info/RECORD +93 -0
- {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/entry_points.txt +0 -4
- eodag/plugins/authentication/oauth.py +0 -60
- eodag/plugins/download/creodias_s3.py +0 -71
- eodag/plugins/download/s3rest.py +0 -351
- eodag/plugins/search/data_request_search.py +0 -565
- eodag/resources/stac.yml +0 -294
- eodag/resources/stac_api.yml +0 -2105
- eodag/rest/__init__.py +0 -24
- eodag/rest/cache.py +0 -70
- eodag/rest/config.py +0 -67
- eodag/rest/constants.py +0 -26
- eodag/rest/core.py +0 -764
- eodag/rest/errors.py +0 -210
- eodag/rest/server.py +0 -604
- eodag/rest/server.wsgi +0 -6
- eodag/rest/stac.py +0 -1032
- eodag/rest/templates/README +0 -1
- eodag/rest/types/__init__.py +0 -18
- eodag/rest/types/collections_search.py +0 -44
- eodag/rest/types/eodag_search.py +0 -386
- eodag/rest/types/queryables.py +0 -174
- eodag/rest/types/stac_search.py +0 -272
- eodag/rest/utils/__init__.py +0 -207
- eodag/rest/utils/cql_evaluate.py +0 -119
- eodag/rest/utils/rfc3339.py +0 -64
- eodag-3.10.1.dist-info/RECORD +0 -116
- {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/WHEEL +0 -0
- {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/licenses/LICENSE +0 -0
- {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/top_level.txt +0 -0
eodag/cli.py
CHANGED
|
@@ -28,13 +28,10 @@ Options:
|
|
|
28
28
|
--help Show this message and exit.
|
|
29
29
|
|
|
30
30
|
Commands:
|
|
31
|
-
|
|
32
|
-
providers...
|
|
33
|
-
discover Fetch providers to discover product types
|
|
31
|
+
discover Fetch providers to discover collections
|
|
34
32
|
download Download a list of products from a serialized search...
|
|
35
|
-
list List supported
|
|
36
|
-
search Search satellite images by their
|
|
37
|
-
serve-rest Start eodag HTTP server
|
|
33
|
+
list List supported collections
|
|
34
|
+
search Search satellite images by their collections,...
|
|
38
35
|
version Print eodag version and exit
|
|
39
36
|
|
|
40
37
|
noqa: D103
|
|
@@ -44,8 +41,6 @@ from __future__ import annotations
|
|
|
44
41
|
|
|
45
42
|
import functools
|
|
46
43
|
import json
|
|
47
|
-
import os
|
|
48
|
-
import shutil
|
|
49
44
|
import sys
|
|
50
45
|
import textwrap
|
|
51
46
|
from importlib.metadata import metadata
|
|
@@ -54,16 +49,12 @@ from urllib.parse import parse_qs
|
|
|
54
49
|
|
|
55
50
|
import click
|
|
56
51
|
|
|
52
|
+
from eodag.api.collection import CollectionsList
|
|
57
53
|
from eodag.api.core import EODataAccessGateway, SearchResult
|
|
58
54
|
from eodag.utils import DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE
|
|
59
|
-
from eodag.utils.exceptions import
|
|
55
|
+
from eodag.utils.exceptions import NoMatchingCollection, UnsupportedProvider
|
|
60
56
|
from eodag.utils.logging import setup_logging
|
|
61
57
|
|
|
62
|
-
try:
|
|
63
|
-
from eodag.rest.utils import LIVENESS_PROBE_PATH
|
|
64
|
-
except ImportError:
|
|
65
|
-
pass
|
|
66
|
-
|
|
67
58
|
if TYPE_CHECKING:
|
|
68
59
|
from click import Context
|
|
69
60
|
|
|
@@ -77,18 +68,6 @@ CRUNCHERS = [
|
|
|
77
68
|
]
|
|
78
69
|
|
|
79
70
|
|
|
80
|
-
class LivenessFilter:
|
|
81
|
-
"""
|
|
82
|
-
Filter out requests to the liveness probe endpoint
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
def filter(self, record):
|
|
86
|
-
"""
|
|
87
|
-
Filter method required by the Python logging API.
|
|
88
|
-
"""
|
|
89
|
-
return LIVENESS_PROBE_PATH not in record.getMessage()
|
|
90
|
-
|
|
91
|
-
|
|
92
71
|
class MutuallyExclusiveOption(click.Option):
|
|
93
72
|
"""Mutually Exclusive Options for Click
|
|
94
73
|
from https://gist.github.com/jacobtolar/fb80d5552a9a9dfc32b12a829fa21c0c
|
|
@@ -164,8 +143,8 @@ def version() -> None:
|
|
|
164
143
|
|
|
165
144
|
@eodag.command(
|
|
166
145
|
name="search",
|
|
167
|
-
help="Search satellite images by their
|
|
168
|
-
"platform
|
|
146
|
+
help="Search satellite images by their collections, instruments, constellation, "
|
|
147
|
+
"platform, processing level or sensor type. It is mandatory to provide "
|
|
169
148
|
"at least one of the previous criteria for eodag to perform a search. "
|
|
170
149
|
"Optionally crunch the search results before storing them in a geojson file",
|
|
171
150
|
)
|
|
@@ -181,6 +160,7 @@ def version() -> None:
|
|
|
181
160
|
help="File path to the user locations configuration file, default is ~/.config/eodag/locations.yml",
|
|
182
161
|
type=click.Path(exists=True),
|
|
183
162
|
)
|
|
163
|
+
@click.option("-p", "--provider", help="Search on this provider")
|
|
184
164
|
@click.option(
|
|
185
165
|
"-b",
|
|
186
166
|
"--box",
|
|
@@ -210,25 +190,18 @@ def version() -> None:
|
|
|
210
190
|
type=click.DateTime(),
|
|
211
191
|
help="End sensing time in ISO8601 format (e.g. '1990-11-26', '1990-11-26T14:30:10'). UTC is assumed",
|
|
212
192
|
)
|
|
193
|
+
@click.option("-c", "--collection", help="The collection to search")
|
|
194
|
+
@click.option("--instruments", help="Search for products matching these instruments")
|
|
195
|
+
@click.option("--platform", help="Search for products matching this platform")
|
|
196
|
+
@click.option("--constellation", help="Search for products matching this constellation")
|
|
213
197
|
@click.option(
|
|
214
|
-
"-
|
|
215
|
-
"--cloudCover",
|
|
216
|
-
type=click.IntRange(0, 100),
|
|
217
|
-
help="Maximum cloud cover percentage needed for the product",
|
|
198
|
+
"--processing-level", help="Search for products matching this processing level"
|
|
218
199
|
)
|
|
219
|
-
@click.option("-
|
|
220
|
-
@click.option("-i", "--instrument", help="Search for products matching this instrument")
|
|
221
|
-
@click.option("-P", "--platform", help="Search for products matching this platform")
|
|
200
|
+
@click.option("--sensor-type", help="Search for products matching this type of sensor")
|
|
222
201
|
@click.option(
|
|
223
|
-
"-
|
|
224
|
-
|
|
225
|
-
help="
|
|
226
|
-
)
|
|
227
|
-
@click.option(
|
|
228
|
-
"-L", "--processingLevel", help="Search for products matching this processing level"
|
|
229
|
-
)
|
|
230
|
-
@click.option(
|
|
231
|
-
"-S", "--sensorType", help="Search for products matching this type of sensor"
|
|
202
|
+
"--cloud-cover",
|
|
203
|
+
type=click.IntRange(0, 100),
|
|
204
|
+
help="Maximum cloud cover percentage needed for the product",
|
|
232
205
|
)
|
|
233
206
|
@click.option("--id", help="Search for the product identified by this id")
|
|
234
207
|
@click.option(
|
|
@@ -299,23 +272,24 @@ def version() -> None:
|
|
|
299
272
|
)
|
|
300
273
|
@click.pass_context
|
|
301
274
|
def search_crunch(ctx: Context, **kwargs: Any) -> None:
|
|
302
|
-
"""Search
|
|
275
|
+
"""Search collections and optionnaly apply crunchers to search results"""
|
|
303
276
|
# Process inputs for search
|
|
304
|
-
|
|
305
|
-
|
|
277
|
+
provider = kwargs.pop("provider")
|
|
278
|
+
collection = kwargs.pop("collection")
|
|
279
|
+
instruments = kwargs.pop("instruments")
|
|
306
280
|
platform = kwargs.pop("platform")
|
|
307
|
-
|
|
308
|
-
processing_level = kwargs.pop("
|
|
309
|
-
sensor_type = kwargs.pop("
|
|
281
|
+
constellation = kwargs.pop("constellation")
|
|
282
|
+
processing_level = kwargs.pop("processing_level")
|
|
283
|
+
sensor_type = kwargs.pop("sensor_type")
|
|
310
284
|
id_ = kwargs.pop("id")
|
|
311
285
|
locations_qs = kwargs.pop("locations")
|
|
312
286
|
custom = kwargs.pop("query")
|
|
313
287
|
if not any(
|
|
314
288
|
[
|
|
315
|
-
|
|
316
|
-
|
|
289
|
+
collection,
|
|
290
|
+
instruments,
|
|
317
291
|
platform,
|
|
318
|
-
|
|
292
|
+
constellation,
|
|
319
293
|
processing_level,
|
|
320
294
|
sensor_type,
|
|
321
295
|
id_,
|
|
@@ -342,16 +316,17 @@ def search_crunch(ctx: Context, **kwargs: Any) -> None:
|
|
|
342
316
|
start_date = kwargs.pop("start")
|
|
343
317
|
stop_date = kwargs.pop("end")
|
|
344
318
|
criteria = {
|
|
319
|
+
"provider": provider,
|
|
345
320
|
"geometry": footprint,
|
|
346
|
-
"
|
|
347
|
-
"
|
|
348
|
-
"
|
|
349
|
-
"
|
|
350
|
-
"
|
|
321
|
+
"start_datetime": None,
|
|
322
|
+
"end_datetime": None,
|
|
323
|
+
"eo:cloud_cover": kwargs.pop("cloud_cover"),
|
|
324
|
+
"collection": collection,
|
|
325
|
+
"instruments": instruments,
|
|
326
|
+
"constellation": constellation,
|
|
351
327
|
"platform": platform,
|
|
352
|
-
"
|
|
353
|
-
"
|
|
354
|
-
"sensorType": sensor_type,
|
|
328
|
+
"processing:level": processing_level,
|
|
329
|
+
"eodag:sensor_type": sensor_type,
|
|
355
330
|
"id": id_,
|
|
356
331
|
}
|
|
357
332
|
if custom:
|
|
@@ -367,9 +342,9 @@ def search_crunch(ctx: Context, **kwargs: Any) -> None:
|
|
|
367
342
|
locations = None
|
|
368
343
|
criteria["locations"] = locations
|
|
369
344
|
if start_date:
|
|
370
|
-
criteria["
|
|
345
|
+
criteria["start_datetime"] = start_date.isoformat()
|
|
371
346
|
if stop_date:
|
|
372
|
-
criteria["
|
|
347
|
+
criteria["end_datetime"] = stop_date.isoformat()
|
|
373
348
|
conf_file = kwargs.pop("conf")
|
|
374
349
|
if conf_file:
|
|
375
350
|
conf_file = click.format_filename(conf_file)
|
|
@@ -431,54 +406,48 @@ def search_crunch(ctx: Context, **kwargs: Any) -> None:
|
|
|
431
406
|
ctx.obj["search_results"] = results
|
|
432
407
|
|
|
433
408
|
|
|
434
|
-
@eodag.command(name="list", help="List supported
|
|
435
|
-
@click.option("-p", "--provider", help="List
|
|
409
|
+
@eodag.command(name="list", help="List supported collections")
|
|
410
|
+
@click.option("-p", "--provider", help="List collections supported by this provider")
|
|
436
411
|
@click.option(
|
|
437
|
-
"
|
|
412
|
+
"--instruments", help="List collections originating from these instruments"
|
|
438
413
|
)
|
|
414
|
+
@click.option("--platform", help="List collections originating from this platform")
|
|
439
415
|
@click.option(
|
|
440
|
-
"
|
|
416
|
+
"--constellation",
|
|
417
|
+
help="List collections originating from this constellation",
|
|
441
418
|
)
|
|
419
|
+
@click.option("--processing-level", help="List collections of processing level")
|
|
442
420
|
@click.option(
|
|
443
|
-
"-
|
|
444
|
-
"--platformSerialIdentifier",
|
|
445
|
-
help="List product types originating from the satellite identified by this keyword",
|
|
421
|
+
"--sensor-type", help="List collections originating from this type of sensor"
|
|
446
422
|
)
|
|
447
|
-
@click.option("-L", "--processingLevel", help="List product types of processing level")
|
|
448
423
|
@click.option(
|
|
449
|
-
"-
|
|
450
|
-
)
|
|
451
|
-
@click.option(
|
|
452
|
-
"--no-fetch", is_flag=True, help="Do not fetch providers for new product types"
|
|
424
|
+
"--no-fetch", is_flag=True, help="Do not fetch providers for new collections"
|
|
453
425
|
)
|
|
454
426
|
@click.pass_context
|
|
455
|
-
def
|
|
456
|
-
"""Print the list of supported
|
|
427
|
+
def list_col(ctx: Context, **kwargs: Any) -> None:
|
|
428
|
+
"""Print the list of supported collections"""
|
|
457
429
|
setup_logging(verbose=ctx.obj["verbosity"])
|
|
458
430
|
dag = EODataAccessGateway()
|
|
459
431
|
provider = kwargs.pop("provider")
|
|
460
432
|
fetch_providers = not kwargs.pop("no_fetch")
|
|
461
433
|
text_wrapper = textwrap.TextWrapper()
|
|
462
|
-
|
|
434
|
+
guessed_collections = CollectionsList([])
|
|
463
435
|
try:
|
|
464
|
-
|
|
465
|
-
platformSerialIdentifier=kwargs.get("platformserialidentifier"),
|
|
466
|
-
processingLevel=kwargs.get("processinglevel"),
|
|
467
|
-
sensorType=kwargs.get("sensortype"),
|
|
436
|
+
guessed_collections = dag.guess_collection(
|
|
468
437
|
**kwargs,
|
|
469
438
|
)
|
|
470
|
-
except
|
|
439
|
+
except NoMatchingCollection:
|
|
471
440
|
if any(
|
|
472
441
|
kwargs[arg]
|
|
473
442
|
for arg in [
|
|
474
|
-
"
|
|
443
|
+
"instruments",
|
|
444
|
+
"constellation",
|
|
475
445
|
"platform",
|
|
476
|
-
"
|
|
477
|
-
"
|
|
478
|
-
"sensortype",
|
|
446
|
+
"processing_level",
|
|
447
|
+
"sensor_type",
|
|
479
448
|
]
|
|
480
449
|
):
|
|
481
|
-
click.echo("No
|
|
450
|
+
click.echo("No collection match the following criteria you provided:")
|
|
482
451
|
click.echo(
|
|
483
452
|
"\n".join(
|
|
484
453
|
"-{param}={value}".format(**locals())
|
|
@@ -488,23 +457,25 @@ def list_pt(ctx: Context, **kwargs: Any) -> None:
|
|
|
488
457
|
)
|
|
489
458
|
sys.exit(1)
|
|
490
459
|
try:
|
|
491
|
-
if
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
460
|
+
if guessed_collections:
|
|
461
|
+
collections = CollectionsList(
|
|
462
|
+
[
|
|
463
|
+
col
|
|
464
|
+
for col in dag.list_collections(
|
|
465
|
+
provider=provider, fetch_providers=fetch_providers
|
|
466
|
+
)
|
|
467
|
+
if col.id in [guessed_col.id for guessed_col in guessed_collections]
|
|
468
|
+
]
|
|
469
|
+
)
|
|
499
470
|
else:
|
|
500
|
-
|
|
471
|
+
collections = dag.list_collections(
|
|
501
472
|
provider=provider, fetch_providers=fetch_providers
|
|
502
473
|
)
|
|
503
|
-
click.echo("Listing available
|
|
504
|
-
for
|
|
505
|
-
click.echo("\n* {}: ".format(
|
|
506
|
-
for prop, value in
|
|
507
|
-
if prop != "
|
|
474
|
+
click.echo("Listing available collections:")
|
|
475
|
+
for collection in collections:
|
|
476
|
+
click.echo("\n* {}: ".format(collection.id))
|
|
477
|
+
for prop, value in collection.model_dump().items():
|
|
478
|
+
if prop != "id":
|
|
508
479
|
text_wrapper.initial_indent = " - {}: ".format(prop)
|
|
509
480
|
text_wrapper.subsequent_indent = " " * len(
|
|
510
481
|
text_wrapper.initial_indent
|
|
@@ -519,34 +490,34 @@ def list_pt(ctx: Context, **kwargs: Any) -> None:
|
|
|
519
490
|
sys.exit(1)
|
|
520
491
|
|
|
521
492
|
|
|
522
|
-
@eodag.command(name="discover", help="Fetch providers to discover
|
|
493
|
+
@eodag.command(name="discover", help="Fetch providers to discover collections")
|
|
523
494
|
@click.option("-p", "--provider", help="Fetch only the given provider")
|
|
524
495
|
@click.option(
|
|
525
496
|
"--storage",
|
|
526
497
|
type=click.Path(dir_okay=False, writable=True, readable=False),
|
|
527
|
-
default="
|
|
528
|
-
help="Path to the file where to store external
|
|
498
|
+
default="ext_collections.json",
|
|
499
|
+
help="Path to the file where to store external collections configuration "
|
|
529
500
|
"(.json extension will be automatically appended to the filename). "
|
|
530
|
-
"DEFAULT:
|
|
501
|
+
"DEFAULT: ext_collections.json",
|
|
531
502
|
)
|
|
532
503
|
@click.pass_context
|
|
533
|
-
def
|
|
534
|
-
"""Fetch external
|
|
504
|
+
def discover_col(ctx: Context, **kwargs: Any) -> None:
|
|
505
|
+
"""Fetch external collections configuration and save result"""
|
|
535
506
|
setup_logging(verbose=ctx.obj["verbosity"])
|
|
536
507
|
dag = EODataAccessGateway()
|
|
537
508
|
provider = kwargs.pop("provider")
|
|
538
509
|
|
|
539
|
-
|
|
540
|
-
dag.
|
|
510
|
+
ext_collections_conf = (
|
|
511
|
+
dag.discover_collections(provider=provider)
|
|
541
512
|
if provider
|
|
542
|
-
else dag.
|
|
513
|
+
else dag.discover_collections()
|
|
543
514
|
)
|
|
544
515
|
|
|
545
516
|
storage_filepath = kwargs.pop("storage")
|
|
546
517
|
if not storage_filepath.endswith(".json"):
|
|
547
518
|
storage_filepath += ".json"
|
|
548
519
|
with open(storage_filepath, "w") as f:
|
|
549
|
-
json.dump(
|
|
520
|
+
json.dump(ext_collections_conf, f)
|
|
550
521
|
click.echo("Results stored at '{}'".format(storage_filepath))
|
|
551
522
|
|
|
552
523
|
|
|
@@ -647,296 +618,5 @@ def download(ctx: Context, **kwargs: Any) -> None:
|
|
|
647
618
|
)
|
|
648
619
|
|
|
649
620
|
|
|
650
|
-
@eodag.command(
|
|
651
|
-
help="(deprecated) Start eodag HTTP server\n\n"
|
|
652
|
-
+ (
|
|
653
|
-
click.style(
|
|
654
|
-
"Running a web server from the CLI is deprecated and will be removed in a future version.\n"
|
|
655
|
-
"This feature has been moved to its own repository: https://github.com/CS-SI/stac-fastapi-eodag\n\n",
|
|
656
|
-
fg="yellow",
|
|
657
|
-
bold=True,
|
|
658
|
-
)
|
|
659
|
-
+ "Set EODAG_CORS_ALLOWED_ORIGINS environment variable to configure Cross-Origin Resource Sharing allowed "
|
|
660
|
-
"origins as comma-separated URLs (e.g. 'http://somewhere,http://somewhere.else')."
|
|
661
|
-
)
|
|
662
|
-
)
|
|
663
|
-
@click.option(
|
|
664
|
-
"-f",
|
|
665
|
-
"--config",
|
|
666
|
-
type=click.Path(exists=True, resolve_path=True),
|
|
667
|
-
help="File path to the user configuration file with its credentials, default is ~/.config/eodag/eodag.yml",
|
|
668
|
-
)
|
|
669
|
-
@click.option(
|
|
670
|
-
"-l",
|
|
671
|
-
"--locs",
|
|
672
|
-
type=click.Path(exists=True, resolve_path=True),
|
|
673
|
-
required=False,
|
|
674
|
-
help="File path to the location shapefiles configuration file",
|
|
675
|
-
)
|
|
676
|
-
@click.option(
|
|
677
|
-
"-d", "--daemon", is_flag=True, show_default=True, help="run in daemon mode"
|
|
678
|
-
)
|
|
679
|
-
@click.option(
|
|
680
|
-
"-w",
|
|
681
|
-
"--world",
|
|
682
|
-
is_flag=True,
|
|
683
|
-
show_default=True,
|
|
684
|
-
help=(
|
|
685
|
-
"run uvicorn using IPv4 0.0.0.0 (all network interfaces), "
|
|
686
|
-
"otherwise bind to 127.0.0.1 (localhost). "
|
|
687
|
-
),
|
|
688
|
-
)
|
|
689
|
-
@click.option(
|
|
690
|
-
"-p",
|
|
691
|
-
"--port",
|
|
692
|
-
type=int,
|
|
693
|
-
default=5000,
|
|
694
|
-
show_default=True,
|
|
695
|
-
help="The port on which to listen",
|
|
696
|
-
)
|
|
697
|
-
@click.option(
|
|
698
|
-
"--debug",
|
|
699
|
-
is_flag=True,
|
|
700
|
-
show_default=True,
|
|
701
|
-
help="Run in debug mode (for development purpose)",
|
|
702
|
-
)
|
|
703
|
-
@click.pass_context
|
|
704
|
-
@_deprecated_cli(
|
|
705
|
-
message=(
|
|
706
|
-
"Running a web server from the CLI is deprecated and will be removed in a future version. "
|
|
707
|
-
"This feature has been moved to its own repository: https://github.com/CS-SI/stac-fastapi-eodag"
|
|
708
|
-
),
|
|
709
|
-
version="3.9.0",
|
|
710
|
-
)
|
|
711
|
-
def serve_rest(
|
|
712
|
-
ctx: Context,
|
|
713
|
-
daemon: bool,
|
|
714
|
-
world: bool,
|
|
715
|
-
port: int,
|
|
716
|
-
config: str,
|
|
717
|
-
locs: str,
|
|
718
|
-
debug: bool,
|
|
719
|
-
) -> None:
|
|
720
|
-
"""Serve EODAG functionalities through a WEB interface"""
|
|
721
|
-
setup_logging(verbose=ctx.obj["verbosity"])
|
|
722
|
-
try:
|
|
723
|
-
import uvicorn
|
|
724
|
-
import uvicorn.config
|
|
725
|
-
except ImportError:
|
|
726
|
-
raise ImportError(
|
|
727
|
-
"Feature not available, please install eodag[server] or eodag[all]"
|
|
728
|
-
)
|
|
729
|
-
|
|
730
|
-
# Set the settings of the app
|
|
731
|
-
# IMPORTANT: the order of imports counts here (first we override the settings,
|
|
732
|
-
# then we import the app so that the updated settings is taken into account in
|
|
733
|
-
# the app initialization)
|
|
734
|
-
if config:
|
|
735
|
-
os.environ["EODAG_CFG_FILE"] = config
|
|
736
|
-
|
|
737
|
-
if locs:
|
|
738
|
-
os.environ["EODAG_LOCS_CFG_FILE"] = locs
|
|
739
|
-
|
|
740
|
-
bind_host = "127.0.0.1"
|
|
741
|
-
if world:
|
|
742
|
-
bind_host = "0.0.0.0"
|
|
743
|
-
if daemon:
|
|
744
|
-
try:
|
|
745
|
-
pid = os.fork()
|
|
746
|
-
except OSError as e:
|
|
747
|
-
raise Exception(
|
|
748
|
-
"%s [%d]" % (e.strerror, e.errno) if e.errno is not None else e.strerror
|
|
749
|
-
)
|
|
750
|
-
|
|
751
|
-
if pid == 0:
|
|
752
|
-
os.setsid()
|
|
753
|
-
uvicorn.run("eodag.rest.server:app", host=bind_host, port=port)
|
|
754
|
-
else:
|
|
755
|
-
sys.exit(0)
|
|
756
|
-
else:
|
|
757
|
-
import logging
|
|
758
|
-
|
|
759
|
-
logging_config = uvicorn.config.LOGGING_CONFIG
|
|
760
|
-
uvicorn_fmt = "%(asctime)-15s %(name)-32s [%(levelname)-8s] %(message)s"
|
|
761
|
-
logging_config["filters"] = {"liveness": {"()": LivenessFilter}}
|
|
762
|
-
logging_config["formatters"]["access"]["fmt"] = uvicorn_fmt
|
|
763
|
-
logging_config["formatters"]["default"]["fmt"] = uvicorn_fmt
|
|
764
|
-
logging_config["loggers"]["uvicorn.access"]["filters"] = ["liveness"]
|
|
765
|
-
|
|
766
|
-
eodag_formatter = logging.Formatter(
|
|
767
|
-
"%(asctime)-15s %(name)-32s [%(levelname)-8s] (tid=%(thread)d) %(message)s"
|
|
768
|
-
)
|
|
769
|
-
logging.getLogger("eodag").handlers[0].setFormatter(eodag_formatter)
|
|
770
|
-
|
|
771
|
-
if ctx.obj["verbosity"] <= 1:
|
|
772
|
-
logging_config["handlers"]["null"] = {
|
|
773
|
-
"level": "DEBUG",
|
|
774
|
-
"class": "logging.NullHandler",
|
|
775
|
-
}
|
|
776
|
-
logging_config["loggers"]["uvicorn"]["handlers"] = ["null"]
|
|
777
|
-
logging_config["loggers"]["uvicorn.error"]["handlers"] = ["null"]
|
|
778
|
-
logging_config["loggers"]["uvicorn.access"]["handlers"] = ["null"]
|
|
779
|
-
else:
|
|
780
|
-
log_level = "INFO" if ctx.obj["verbosity"] == 2 else "DEBUG"
|
|
781
|
-
logging_config["loggers"]["uvicorn"]["level"] = log_level
|
|
782
|
-
logging_config["loggers"]["uvicorn.error"]["level"] = log_level
|
|
783
|
-
logging_config["loggers"]["uvicorn.access"]["level"] = log_level
|
|
784
|
-
|
|
785
|
-
uvicorn.run(
|
|
786
|
-
"eodag.rest.server:app",
|
|
787
|
-
host=bind_host,
|
|
788
|
-
port=port,
|
|
789
|
-
reload=debug,
|
|
790
|
-
log_config=logging_config,
|
|
791
|
-
)
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
@eodag.command(
|
|
795
|
-
help="Configure the settings of the HTTP web app (the providers credential "
|
|
796
|
-
"files essentially) and copy the web app source directory into the "
|
|
797
|
-
"specified directory"
|
|
798
|
-
)
|
|
799
|
-
@click.option(
|
|
800
|
-
"--root",
|
|
801
|
-
type=click.Path(exists=True, resolve_path=True),
|
|
802
|
-
default="/var/www/",
|
|
803
|
-
show_default=True,
|
|
804
|
-
help="The directory where to deploy the webapp (a subdirectory with the name "
|
|
805
|
-
"from --name option will be created there)",
|
|
806
|
-
)
|
|
807
|
-
@click.option(
|
|
808
|
-
"-f",
|
|
809
|
-
"--config",
|
|
810
|
-
type=click.Path(exists=True, resolve_path=True),
|
|
811
|
-
required=True,
|
|
812
|
-
help="File path to the user configuration file with its credentials",
|
|
813
|
-
)
|
|
814
|
-
@click.option(
|
|
815
|
-
"--webserver",
|
|
816
|
-
type=click.Choice(["apache"]),
|
|
817
|
-
default="apache",
|
|
818
|
-
show_default=True,
|
|
819
|
-
help="The webserver for which to generate sample configuration",
|
|
820
|
-
)
|
|
821
|
-
@click.option(
|
|
822
|
-
"--threads",
|
|
823
|
-
type=int,
|
|
824
|
-
default=5,
|
|
825
|
-
show_default=True,
|
|
826
|
-
help="Number of threads for apache webserver config (ignored if not apache "
|
|
827
|
-
"webserver)",
|
|
828
|
-
)
|
|
829
|
-
@click.option(
|
|
830
|
-
"--user",
|
|
831
|
-
type=str,
|
|
832
|
-
default="www-data",
|
|
833
|
-
show_default=True,
|
|
834
|
-
help="The user of the webserver",
|
|
835
|
-
)
|
|
836
|
-
@click.option(
|
|
837
|
-
"--group",
|
|
838
|
-
type=str,
|
|
839
|
-
default="www-data",
|
|
840
|
-
show_default=True,
|
|
841
|
-
help="The group of the webserver",
|
|
842
|
-
)
|
|
843
|
-
@click.option(
|
|
844
|
-
"--server-name",
|
|
845
|
-
type=str,
|
|
846
|
-
default="localhost",
|
|
847
|
-
show_default=True,
|
|
848
|
-
help="The name to give to the server",
|
|
849
|
-
)
|
|
850
|
-
@click.option(
|
|
851
|
-
"--wsgi-process-group",
|
|
852
|
-
type=str,
|
|
853
|
-
default="eodag-server",
|
|
854
|
-
show_default=True,
|
|
855
|
-
help="The name of the wsgi process group (ignored if not apache webserver",
|
|
856
|
-
)
|
|
857
|
-
@click.option(
|
|
858
|
-
"--wsgi-daemon-process",
|
|
859
|
-
type=str,
|
|
860
|
-
default="eodag-server",
|
|
861
|
-
show_default=True,
|
|
862
|
-
help="The name of the wsgi daemon process (ignored if not apache webserver",
|
|
863
|
-
)
|
|
864
|
-
@click.option(
|
|
865
|
-
"--name",
|
|
866
|
-
type=str,
|
|
867
|
-
default="eodag_server",
|
|
868
|
-
show_default=True,
|
|
869
|
-
help="The name of the directory that will be created in the webserver root "
|
|
870
|
-
"directory to host the WSGI app",
|
|
871
|
-
)
|
|
872
|
-
@click.pass_context
|
|
873
|
-
def deploy_wsgi_app(
|
|
874
|
-
ctx: Context,
|
|
875
|
-
root: str,
|
|
876
|
-
config: str,
|
|
877
|
-
webserver: str,
|
|
878
|
-
threads: int,
|
|
879
|
-
user: str,
|
|
880
|
-
group: str,
|
|
881
|
-
server_name: str,
|
|
882
|
-
wsgi_process_group: str,
|
|
883
|
-
wsgi_daemon_process: str,
|
|
884
|
-
name: str,
|
|
885
|
-
) -> None:
|
|
886
|
-
"""Deploy the WEB interface of eodag behind a web server"""
|
|
887
|
-
setup_logging(verbose=ctx.obj["verbosity"])
|
|
888
|
-
import eodag as eodag_package
|
|
889
|
-
|
|
890
|
-
server_config = {"EODAG_CFG_FILE": config}
|
|
891
|
-
eodag_package_path = eodag_package.__path__[0]
|
|
892
|
-
webapp_src_path = os.path.join(eodag_package_path, "rest")
|
|
893
|
-
webapp_dst_path = os.path.join(root, name)
|
|
894
|
-
if not os.path.exists(webapp_dst_path):
|
|
895
|
-
os.mkdir(webapp_dst_path)
|
|
896
|
-
wsgi_path = os.path.join(webapp_dst_path, "server.wsgi")
|
|
897
|
-
click.echo(
|
|
898
|
-
"Moving eodag HTTP web app from {} to {}".format(
|
|
899
|
-
webapp_src_path, webapp_dst_path
|
|
900
|
-
)
|
|
901
|
-
)
|
|
902
|
-
shutil.copy(os.path.join(webapp_src_path, "server.wsgi"), wsgi_path)
|
|
903
|
-
|
|
904
|
-
click.echo(
|
|
905
|
-
"Overriding eodag HTTP server config with values: {}".format(server_config)
|
|
906
|
-
)
|
|
907
|
-
with open(os.path.join(webapp_dst_path, "eodag_server_settings.json"), "w") as fd:
|
|
908
|
-
json.dump(server_config, fd)
|
|
909
|
-
|
|
910
|
-
click.echo("Finished ! The WSGI file is in {}".format(wsgi_path))
|
|
911
|
-
if webserver == "apache":
|
|
912
|
-
application_group = "%{GLOBAL}"
|
|
913
|
-
apache_config_sample = (
|
|
914
|
-
"""
|
|
915
|
-
<VirtualHost *>
|
|
916
|
-
ServerName %(server_name)s
|
|
917
|
-
|
|
918
|
-
WSGIDaemonProcess %(wsgi_daemon_process)s user=%(user)s group=%(group)s \
|
|
919
|
-
threads=%(threads)s
|
|
920
|
-
WSGIScriptAlias / %(wsgi_path)s
|
|
921
|
-
|
|
922
|
-
<Directory %(webapp_dst_path)s>
|
|
923
|
-
WSGIProcessGroup %(wsgi_process_group)s
|
|
924
|
-
WSGIApplicationGroup %(application_group)s
|
|
925
|
-
<IfVersion < 2.4>
|
|
926
|
-
Order allow,deny
|
|
927
|
-
Allow from all
|
|
928
|
-
</IfVersion>
|
|
929
|
-
<IfVersion >= 2.4>
|
|
930
|
-
Require all granted
|
|
931
|
-
</IfVersion>
|
|
932
|
-
</Directory>
|
|
933
|
-
</VirtualHost>
|
|
934
|
-
"""
|
|
935
|
-
% locals()
|
|
936
|
-
)
|
|
937
|
-
click.echo("Sample Apache2 config to add in a your virtual host:")
|
|
938
|
-
click.echo(apache_config_sample)
|
|
939
|
-
|
|
940
|
-
|
|
941
621
|
if __name__ == "__main__":
|
|
942
622
|
eodag(obj={})
|