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.
Files changed (75) hide show
  1. eodag/__init__.py +6 -1
  2. eodag/api/collection.py +353 -0
  3. eodag/api/core.py +606 -641
  4. eodag/api/product/__init__.py +3 -3
  5. eodag/api/product/_product.py +74 -56
  6. eodag/api/product/drivers/__init__.py +4 -46
  7. eodag/api/product/drivers/base.py +0 -28
  8. eodag/api/product/metadata_mapping.py +178 -216
  9. eodag/api/search_result.py +156 -15
  10. eodag/cli.py +83 -403
  11. eodag/config.py +81 -51
  12. eodag/plugins/apis/base.py +2 -2
  13. eodag/plugins/apis/ecmwf.py +36 -25
  14. eodag/plugins/apis/usgs.py +55 -40
  15. eodag/plugins/authentication/base.py +1 -3
  16. eodag/plugins/crunch/filter_date.py +3 -3
  17. eodag/plugins/crunch/filter_latest_intersect.py +2 -2
  18. eodag/plugins/crunch/filter_latest_tpl_name.py +1 -1
  19. eodag/plugins/download/aws.py +46 -42
  20. eodag/plugins/download/base.py +13 -14
  21. eodag/plugins/download/http.py +65 -65
  22. eodag/plugins/manager.py +28 -29
  23. eodag/plugins/search/__init__.py +6 -4
  24. eodag/plugins/search/base.py +131 -80
  25. eodag/plugins/search/build_search_result.py +245 -173
  26. eodag/plugins/search/cop_marine.py +87 -56
  27. eodag/plugins/search/csw.py +47 -37
  28. eodag/plugins/search/qssearch.py +653 -429
  29. eodag/plugins/search/stac_list_assets.py +1 -1
  30. eodag/plugins/search/static_stac_search.py +43 -44
  31. eodag/resources/{product_types.yml → collections.yml} +2594 -2453
  32. eodag/resources/ext_collections.json +1 -1
  33. eodag/resources/ext_product_types.json +1 -1
  34. eodag/resources/providers.yml +2706 -2733
  35. eodag/resources/stac_provider.yml +50 -92
  36. eodag/resources/user_conf_template.yml +9 -0
  37. eodag/types/__init__.py +2 -0
  38. eodag/types/queryables.py +70 -91
  39. eodag/types/search_args.py +1 -1
  40. eodag/utils/__init__.py +97 -21
  41. eodag/utils/dates.py +0 -12
  42. eodag/utils/exceptions.py +6 -6
  43. eodag/utils/free_text_search.py +3 -3
  44. eodag/utils/repr.py +2 -0
  45. {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/METADATA +13 -99
  46. eodag-4.0.0a2.dist-info/RECORD +93 -0
  47. {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/entry_points.txt +0 -4
  48. eodag/plugins/authentication/oauth.py +0 -60
  49. eodag/plugins/download/creodias_s3.py +0 -71
  50. eodag/plugins/download/s3rest.py +0 -351
  51. eodag/plugins/search/data_request_search.py +0 -565
  52. eodag/resources/stac.yml +0 -294
  53. eodag/resources/stac_api.yml +0 -2105
  54. eodag/rest/__init__.py +0 -24
  55. eodag/rest/cache.py +0 -70
  56. eodag/rest/config.py +0 -67
  57. eodag/rest/constants.py +0 -26
  58. eodag/rest/core.py +0 -764
  59. eodag/rest/errors.py +0 -210
  60. eodag/rest/server.py +0 -604
  61. eodag/rest/server.wsgi +0 -6
  62. eodag/rest/stac.py +0 -1032
  63. eodag/rest/templates/README +0 -1
  64. eodag/rest/types/__init__.py +0 -18
  65. eodag/rest/types/collections_search.py +0 -44
  66. eodag/rest/types/eodag_search.py +0 -386
  67. eodag/rest/types/queryables.py +0 -174
  68. eodag/rest/types/stac_search.py +0 -272
  69. eodag/rest/utils/__init__.py +0 -207
  70. eodag/rest/utils/cql_evaluate.py +0 -119
  71. eodag/rest/utils/rfc3339.py +0 -64
  72. eodag-3.10.1.dist-info/RECORD +0 -116
  73. {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/WHEEL +0 -0
  74. {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/licenses/LICENSE +0 -0
  75. {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
- deploy-wsgi-app Configure the settings of the HTTP web app (the
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 product types
36
- search Search satellite images by their product types,...
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 NoMatchingProductType, UnsupportedProvider
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 product types, instrument, platform, "
168
- "platform identifier, processing level or sensor type. It is mandatory to provide "
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
- "-c",
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("-p", "--productType", help="The product type to search")
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
- "-t",
224
- "--platformSerialIdentifier",
225
- help="Search for products originating from the satellite identified by this keyword",
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 product types and optionnaly apply crunchers to search results"""
275
+ """Search collections and optionnaly apply crunchers to search results"""
303
276
  # Process inputs for search
304
- product_type = kwargs.pop("producttype")
305
- instrument = kwargs.pop("instrument")
277
+ provider = kwargs.pop("provider")
278
+ collection = kwargs.pop("collection")
279
+ instruments = kwargs.pop("instruments")
306
280
  platform = kwargs.pop("platform")
307
- platform_identifier = kwargs.pop("platformserialidentifier")
308
- processing_level = kwargs.pop("processinglevel")
309
- sensor_type = kwargs.pop("sensortype")
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
- product_type,
316
- instrument,
289
+ collection,
290
+ instruments,
317
291
  platform,
318
- platform_identifier,
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
- "startTimeFromAscendingNode": None,
347
- "completionTimeFromAscendingNode": None,
348
- "cloudCover": kwargs.pop("cloudcover"),
349
- "productType": product_type,
350
- "instrument": instrument,
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
- "platformSerialIdentifier": platform_identifier,
353
- "processingLevel": processing_level,
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["startTimeFromAscendingNode"] = start_date.isoformat()
345
+ criteria["start_datetime"] = start_date.isoformat()
371
346
  if stop_date:
372
- criteria["completionTimeFromAscendingNode"] = stop_date.isoformat()
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 product types")
435
- @click.option("-p", "--provider", help="List product types supported by this provider")
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
- "-i", "--instrument", help="List product types originating from this instrument"
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
- "-P", "--platform", help="List product types originating from this platform"
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
- "-t",
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
- "-S", "--sensorType", help="List product types originating from this type of sensor"
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 list_pt(ctx: Context, **kwargs: Any) -> None:
456
- """Print the list of supported product types"""
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
- guessed_product_types = []
434
+ guessed_collections = CollectionsList([])
463
435
  try:
464
- guessed_product_types = dag.guess_product_type(
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 NoMatchingProductType:
439
+ except NoMatchingCollection:
471
440
  if any(
472
441
  kwargs[arg]
473
442
  for arg in [
474
- "instrument",
443
+ "instruments",
444
+ "constellation",
475
445
  "platform",
476
- "platformserialidentifier",
477
- "processinglevel",
478
- "sensortype",
446
+ "processing_level",
447
+ "sensor_type",
479
448
  ]
480
449
  ):
481
- click.echo("No product type match the following criteria you provided:")
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 guessed_product_types:
492
- product_types = [
493
- pt
494
- for pt in dag.list_product_types(
495
- provider=provider, fetch_providers=fetch_providers
496
- )
497
- if pt["ID"] in guessed_product_types
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
- product_types = dag.list_product_types(
471
+ collections = dag.list_collections(
501
472
  provider=provider, fetch_providers=fetch_providers
502
473
  )
503
- click.echo("Listing available product types:")
504
- for product_type in product_types:
505
- click.echo("\n* {}: ".format(product_type["ID"]))
506
- for prop, value in product_type.items():
507
- if prop != "ID":
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 product types")
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="ext_product_types.json",
528
- help="Path to the file where to store external product types configuration "
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: ext_product_types.json",
501
+ "DEFAULT: ext_collections.json",
531
502
  )
532
503
  @click.pass_context
533
- def discover_pt(ctx: Context, **kwargs: Any) -> None:
534
- """Fetch external product types configuration and save result"""
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
- ext_product_types_conf = (
540
- dag.discover_product_types(provider=provider)
510
+ ext_collections_conf = (
511
+ dag.discover_collections(provider=provider)
541
512
  if provider
542
- else dag.discover_product_types()
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(ext_product_types_conf, f)
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={})