eodag 3.0.0b3__py3-none-any.whl → 3.0.1__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/api/core.py +189 -125
- eodag/api/product/metadata_mapping.py +12 -3
- eodag/api/search_result.py +29 -3
- eodag/cli.py +35 -19
- eodag/config.py +412 -116
- eodag/plugins/apis/base.py +10 -4
- eodag/plugins/apis/ecmwf.py +14 -4
- eodag/plugins/apis/usgs.py +25 -2
- eodag/plugins/authentication/aws_auth.py +14 -5
- eodag/plugins/authentication/base.py +10 -1
- eodag/plugins/authentication/generic.py +14 -3
- eodag/plugins/authentication/header.py +12 -4
- eodag/plugins/authentication/keycloak.py +41 -22
- eodag/plugins/authentication/oauth.py +11 -1
- eodag/plugins/authentication/openid_connect.py +178 -163
- eodag/plugins/authentication/qsauth.py +12 -4
- eodag/plugins/authentication/sas_auth.py +19 -2
- eodag/plugins/authentication/token.py +57 -10
- eodag/plugins/authentication/token_exchange.py +19 -19
- eodag/plugins/crunch/base.py +4 -1
- eodag/plugins/crunch/filter_date.py +5 -2
- eodag/plugins/crunch/filter_latest_intersect.py +5 -4
- eodag/plugins/crunch/filter_latest_tpl_name.py +1 -1
- eodag/plugins/crunch/filter_overlap.py +5 -7
- eodag/plugins/crunch/filter_property.py +4 -3
- eodag/plugins/download/aws.py +39 -22
- eodag/plugins/download/base.py +11 -11
- eodag/plugins/download/creodias_s3.py +11 -2
- eodag/plugins/download/http.py +86 -52
- eodag/plugins/download/s3rest.py +20 -18
- eodag/plugins/manager.py +168 -23
- eodag/plugins/search/base.py +33 -14
- eodag/plugins/search/build_search_result.py +55 -51
- eodag/plugins/search/cop_marine.py +112 -29
- eodag/plugins/search/creodias_s3.py +20 -5
- eodag/plugins/search/csw.py +41 -1
- eodag/plugins/search/data_request_search.py +109 -9
- eodag/plugins/search/qssearch.py +532 -152
- eodag/plugins/search/static_stac_search.py +20 -21
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +187 -56
- eodag/resources/providers.yml +1610 -1701
- eodag/resources/stac.yml +3 -163
- eodag/resources/user_conf_template.yml +112 -97
- eodag/rest/config.py +1 -2
- eodag/rest/constants.py +0 -1
- eodag/rest/core.py +61 -51
- eodag/rest/errors.py +181 -0
- eodag/rest/server.py +24 -325
- eodag/rest/stac.py +93 -544
- eodag/rest/types/eodag_search.py +13 -8
- eodag/rest/types/queryables.py +1 -2
- eodag/rest/types/stac_search.py +11 -2
- eodag/types/__init__.py +15 -3
- eodag/types/download_args.py +1 -1
- eodag/types/queryables.py +1 -2
- eodag/types/search_args.py +3 -3
- eodag/utils/__init__.py +77 -57
- eodag/utils/exceptions.py +23 -9
- eodag/utils/logging.py +37 -77
- eodag/utils/requests.py +1 -3
- eodag/utils/stac_reader.py +1 -1
- {eodag-3.0.0b3.dist-info → eodag-3.0.1.dist-info}/METADATA +11 -12
- eodag-3.0.1.dist-info/RECORD +109 -0
- {eodag-3.0.0b3.dist-info → eodag-3.0.1.dist-info}/WHEEL +1 -1
- {eodag-3.0.0b3.dist-info → eodag-3.0.1.dist-info}/entry_points.txt +1 -0
- eodag/resources/constraints/climate-dt.json +0 -13
- eodag/resources/constraints/extremes-dt.json +0 -8
- eodag-3.0.0b3.dist-info/RECORD +0 -110
- {eodag-3.0.0b3.dist-info → eodag-3.0.1.dist-info}/LICENSE +0 -0
- {eodag-3.0.0b3.dist-info → eodag-3.0.1.dist-info}/top_level.txt +0 -0
|
@@ -28,7 +28,13 @@ from requests.auth import AuthBase
|
|
|
28
28
|
from urllib3 import Retry
|
|
29
29
|
|
|
30
30
|
from eodag.plugins.authentication.base import Authentication
|
|
31
|
-
from eodag.utils import
|
|
31
|
+
from eodag.utils import (
|
|
32
|
+
HTTP_REQ_TIMEOUT,
|
|
33
|
+
REQ_RETRY_BACKOFF_FACTOR,
|
|
34
|
+
REQ_RETRY_STATUS_FORCELIST,
|
|
35
|
+
REQ_RETRY_TOTAL,
|
|
36
|
+
USER_AGENT,
|
|
37
|
+
)
|
|
32
38
|
from eodag.utils.exceptions import AuthenticationError, MisconfiguredError, TimeOutError
|
|
33
39
|
|
|
34
40
|
if TYPE_CHECKING:
|
|
@@ -41,7 +47,36 @@ logger = logging.getLogger("eodag.authentication.token")
|
|
|
41
47
|
|
|
42
48
|
|
|
43
49
|
class TokenAuth(Authentication):
|
|
44
|
-
"""TokenAuth authentication plugin
|
|
50
|
+
"""TokenAuth authentication plugin - fetches a token which is added to search/download requests
|
|
51
|
+
|
|
52
|
+
:param provider: provider name
|
|
53
|
+
:param config: Authentication plugin configuration:
|
|
54
|
+
|
|
55
|
+
* :attr:`~eodag.config.PluginConfig.type` (``str``) (**mandatory**): TokenAuth
|
|
56
|
+
* :attr:`~eodag.config.PluginConfig.auth_uri` (``str``) (**mandatory**): url used to fetch
|
|
57
|
+
the access token with user/password
|
|
58
|
+
* :attr:`~eodag.config.PluginConfig.refresh_uri` (``str``) : url used to fetch the
|
|
59
|
+
access token with a refresh token
|
|
60
|
+
* :attr:`~eodag.config.PluginConfig.token_type` (``str``): type of the token (``json``
|
|
61
|
+
or ``text``); default: ``text``
|
|
62
|
+
* :attr:`~eodag.config.PluginConfig.token_key` (``str``): (mandatory if token_type=json)
|
|
63
|
+
key to get the access token in the response to the token request
|
|
64
|
+
* :attr:`~eodag.config.PluginConfig.refresh_token_key` (``str``): key to get the refresh
|
|
65
|
+
token in the response to the token request
|
|
66
|
+
* :attr:`~eodag.config.PluginConfig.ssl_verify` (``bool``): if the ssl certificates
|
|
67
|
+
should be verified in the requests; default: ``True``
|
|
68
|
+
* :attr:`~eodag.config.PluginConfig.auth_error_code` (``int``): which error code is
|
|
69
|
+
returned in case of an authentication error
|
|
70
|
+
* :attr:`~eodag.config.PluginConfig.req_data` (``Dict[str, Any]``): if the credentials
|
|
71
|
+
should be sent as data in the post request, the json structure can be given in this parameter
|
|
72
|
+
* :attr:`~eodag.config.PluginConfig.retry_total` (``int``): :class:`urllib3.util.Retry` ``total`` parameter,
|
|
73
|
+
total number of retries to allow; default: ``3``
|
|
74
|
+
* :attr:`~eodag.config.PluginConfig.retry_backoff_factor` (``int``): :class:`urllib3.util.Retry`
|
|
75
|
+
``backoff_factor`` parameter, backoff factor to apply between attempts after the second try; default: ``2``
|
|
76
|
+
* :attr:`~eodag.config.PluginConfig.retry_status_forcelist` (``List[int]``): :class:`urllib3.util.Retry`
|
|
77
|
+
``status_forcelist`` parameter, list of integer HTTP status codes that we should force a retry on; default:
|
|
78
|
+
``[401, 429, 500, 502, 503, 504]``
|
|
79
|
+
"""
|
|
45
80
|
|
|
46
81
|
def __init__(self, provider: str, config: PluginConfig) -> None:
|
|
47
82
|
super(TokenAuth, self).__init__(provider, config)
|
|
@@ -89,14 +124,15 @@ class TokenAuth(Authentication):
|
|
|
89
124
|
and e.response.status_code in auth_errors
|
|
90
125
|
):
|
|
91
126
|
raise AuthenticationError(
|
|
92
|
-
f"
|
|
93
|
-
f"
|
|
94
|
-
|
|
127
|
+
f"Please check your credentials for {self.provider}.",
|
|
128
|
+
f"HTTP Error {e.response.status_code} returned.",
|
|
129
|
+
response_text,
|
|
130
|
+
) from e
|
|
95
131
|
# other error
|
|
96
132
|
else:
|
|
97
133
|
raise AuthenticationError(
|
|
98
|
-
|
|
99
|
-
)
|
|
134
|
+
"Could no get authentication token", str(e), response_text
|
|
135
|
+
) from e
|
|
100
136
|
else:
|
|
101
137
|
if getattr(self.config, "token_type", "text") == "json":
|
|
102
138
|
token = response.json()[self.config.token_key]
|
|
@@ -116,16 +152,25 @@ class TokenAuth(Authentication):
|
|
|
116
152
|
self,
|
|
117
153
|
session: requests.Session,
|
|
118
154
|
) -> requests.Response:
|
|
155
|
+
retry_total = getattr(self.config, "retry_total", REQ_RETRY_TOTAL)
|
|
156
|
+
retry_backoff_factor = getattr(
|
|
157
|
+
self.config, "retry_backoff_factor", REQ_RETRY_BACKOFF_FACTOR
|
|
158
|
+
)
|
|
159
|
+
retry_status_forcelist = getattr(
|
|
160
|
+
self.config, "retry_status_forcelist", REQ_RETRY_STATUS_FORCELIST
|
|
161
|
+
)
|
|
162
|
+
|
|
119
163
|
retries = Retry(
|
|
120
|
-
total=
|
|
121
|
-
backoff_factor=
|
|
122
|
-
status_forcelist=
|
|
164
|
+
total=retry_total,
|
|
165
|
+
backoff_factor=retry_backoff_factor,
|
|
166
|
+
status_forcelist=retry_status_forcelist,
|
|
123
167
|
)
|
|
124
168
|
|
|
125
169
|
# append headers to req if some are specified in config
|
|
126
170
|
req_kwargs: Dict[str, Any] = {
|
|
127
171
|
"headers": dict(self.config.headers, **USER_AGENT)
|
|
128
172
|
}
|
|
173
|
+
ssl_verify = getattr(self.config, "ssl_verify", True)
|
|
129
174
|
|
|
130
175
|
if self.refresh_token:
|
|
131
176
|
logger.debug("fetching access token with refresh token")
|
|
@@ -135,6 +180,7 @@ class TokenAuth(Authentication):
|
|
|
135
180
|
self.config.refresh_uri,
|
|
136
181
|
data={"refresh_token": self.refresh_token},
|
|
137
182
|
timeout=HTTP_REQ_TIMEOUT,
|
|
183
|
+
verify=ssl_verify,
|
|
138
184
|
**req_kwargs,
|
|
139
185
|
)
|
|
140
186
|
response.raise_for_status()
|
|
@@ -170,6 +216,7 @@ class TokenAuth(Authentication):
|
|
|
170
216
|
method=method,
|
|
171
217
|
url=self.config.auth_uri,
|
|
172
218
|
timeout=HTTP_REQ_TIMEOUT,
|
|
219
|
+
verify=ssl_verify,
|
|
173
220
|
**req_kwargs,
|
|
174
221
|
)
|
|
175
222
|
|
|
@@ -38,25 +38,23 @@ class OIDCTokenExchangeAuth(Authentication):
|
|
|
38
38
|
"""Token exchange implementation using
|
|
39
39
|
:class:`~eodag.plugins.authentication.openid_connect.OIDCAuthorizationCodeFlowAuth` token as subject.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
:param provider: provider name
|
|
42
|
+
:param config: Authentication plugin configuration:
|
|
43
|
+
|
|
44
|
+
* :attr:`~eodag.config.PluginConfig.subject` (``Dict[str, Any]``) (**mandatory**):
|
|
45
|
+
The full :class:`~eodag.plugins.authentication.openid_connect.OIDCAuthorizationCodeFlowAuth` plugin
|
|
46
|
+
configuration used to retrieve subject token
|
|
47
|
+
* :attr:`~eodag.config.PluginConfig.subject_issuer` (``str``) (**mandatory**): Identifies
|
|
48
|
+
the issuer of the subject_token
|
|
49
|
+
* :attr:`~eodag.config.PluginConfig.token_uri` (``str``) (**mandatory**): The url to
|
|
50
|
+
query to get the authorized token
|
|
51
|
+
* :attr:`~eodag.config.PluginConfig.client_id` (``str``) (**mandatory**): The OIDC
|
|
52
|
+
provider's client ID of the eodag provider
|
|
53
|
+
* :attr:`~eodag.config.PluginConfig.audience` (``str``) (**mandatory**): This parameter
|
|
54
|
+
specifies the target client you want the new token minted for.
|
|
55
|
+
* :attr:`~eodag.config.PluginConfig.token_key` (``str``) (**mandatory**): The key
|
|
56
|
+
pointing to the token in the json response to the POST request to the token server
|
|
42
57
|
|
|
43
|
-
# (mandatory) The full OIDCAuthorizationCodeFlowAuth plugin configuration used to retrieve subject token
|
|
44
|
-
subject:
|
|
45
|
-
|
|
46
|
-
# (mandatory) Identifies the issuer of the subject_token
|
|
47
|
-
subject_issuer:
|
|
48
|
-
|
|
49
|
-
# (mandatory) The url to query to get the authorized token
|
|
50
|
-
token_uri:
|
|
51
|
-
|
|
52
|
-
# (mandatory) The OIDC provider's client ID of the eodag provider
|
|
53
|
-
client_id:
|
|
54
|
-
|
|
55
|
-
# (mandatory) This parameter specifies the target client you want the new token minted for.
|
|
56
|
-
audience:
|
|
57
|
-
|
|
58
|
-
# (mandatory) The key pointing to the token in the json response to the POST request to the token server
|
|
59
|
-
token_key:
|
|
60
58
|
"""
|
|
61
59
|
|
|
62
60
|
GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange"
|
|
@@ -71,7 +69,7 @@ class OIDCTokenExchangeAuth(Authentication):
|
|
|
71
69
|
]
|
|
72
70
|
|
|
73
71
|
def __init__(self, provider: str, config: PluginConfig) -> None:
|
|
74
|
-
super(
|
|
72
|
+
super().__init__(provider, config)
|
|
75
73
|
for required_key in self.REQUIRED_KEYS:
|
|
76
74
|
if getattr(self.config, required_key, None) is None:
|
|
77
75
|
raise MisconfiguredError(
|
|
@@ -100,12 +98,14 @@ class OIDCTokenExchangeAuth(Authentication):
|
|
|
100
98
|
"audience": self.config.audience,
|
|
101
99
|
}
|
|
102
100
|
logger.debug("Getting target auth token")
|
|
101
|
+
ssl_verify = getattr(self.config, "ssl_verify", True)
|
|
103
102
|
try:
|
|
104
103
|
auth_response = self.subject.session.post(
|
|
105
104
|
self.config.token_uri,
|
|
106
105
|
data=auth_data,
|
|
107
106
|
headers=USER_AGENT,
|
|
108
107
|
timeout=HTTP_REQ_TIMEOUT,
|
|
108
|
+
verify=ssl_verify,
|
|
109
109
|
)
|
|
110
110
|
auth_response.raise_for_status()
|
|
111
111
|
except requests.exceptions.Timeout as exc:
|
eodag/plugins/crunch/base.py
CHANGED
|
@@ -37,10 +37,13 @@ logger = logging.getLogger("eodag.crunch.date")
|
|
|
37
37
|
class FilterDate(Crunch):
|
|
38
38
|
"""FilterDate cruncher: filter products by date
|
|
39
39
|
|
|
40
|
+
Allows to filter out products that are older than a start date (optional) or more recent than an end date
|
|
41
|
+
(optional).
|
|
42
|
+
|
|
40
43
|
:param config: Crunch configuration, may contain :
|
|
41
44
|
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
* ``start`` (``str``): start sensing time in iso format
|
|
46
|
+
* ``end`` (``str``): end sensing time in iso format
|
|
44
47
|
"""
|
|
45
48
|
|
|
46
49
|
@staticmethod
|
|
@@ -39,7 +39,8 @@ logger = logging.getLogger("eodag.crunch.latest_intersect")
|
|
|
39
39
|
class FilterLatestIntersect(Crunch):
|
|
40
40
|
"""FilterLatestIntersect cruncher
|
|
41
41
|
|
|
42
|
-
Filter latest products (the ones with a the highest start date) that intersect search extent
|
|
42
|
+
Filter latest products (the ones with a the highest start date) that intersect search extent;
|
|
43
|
+
The configuration for this plugin is an empty dict
|
|
43
44
|
"""
|
|
44
45
|
|
|
45
46
|
@staticmethod
|
|
@@ -53,14 +54,14 @@ class FilterLatestIntersect(Crunch):
|
|
|
53
54
|
return dateutil.parser.parse(start_date)
|
|
54
55
|
|
|
55
56
|
def proceed(
|
|
56
|
-
self, products: List[EOProduct], **search_params: Any
|
|
57
|
+
self, products: List[EOProduct], **search_params: Dict[str, Any]
|
|
57
58
|
) -> List[EOProduct]:
|
|
58
59
|
"""Execute crunch:
|
|
59
60
|
Filter latest products (the ones with a the highest start date) that intersect search extent.
|
|
60
61
|
|
|
61
62
|
:param products: A list of products resulting from a search
|
|
62
|
-
:param search_params: Search criteria that must contain
|
|
63
|
-
|
|
63
|
+
:param search_params: Search criteria that must contain ``geometry`` or ``geom`` parameters having value of
|
|
64
|
+
type :class:`shapely.geometry.base.BaseGeometry` or ``Dict[str, Any]``
|
|
64
65
|
:returns: The filtered products
|
|
65
66
|
"""
|
|
66
67
|
logger.debug("Start filtering for latest products")
|
|
@@ -37,7 +37,7 @@ class FilterLatestByName(Crunch):
|
|
|
37
37
|
|
|
38
38
|
:param config: Crunch configuration, must contain :
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
* ``name_pattern`` (``str``) (**mandatory**): product name pattern
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
43
|
NAME_PATTERN_CONSTRAINT = re.compile(r"\(\?P<tileid>\\d\{6\}\)")
|
|
@@ -40,14 +40,12 @@ class FilterOverlap(Crunch):
|
|
|
40
40
|
|
|
41
41
|
Filter products, retaining only those that are overlapping with the search_extent
|
|
42
42
|
|
|
43
|
-
:param config: Crunch configuration
|
|
43
|
+
:param config: Crunch configuration may contain the following parameters which are mutually exclusive:
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
These configuration parameters are mutually exclusive.
|
|
45
|
+
* ``minimum_overlap`` (``Union[float, str]``): minimal overlap percentage; default: ``"0"``
|
|
46
|
+
* ``contains`` (``bool``): ``True`` if product geometry contains the search area; default: ``False``
|
|
47
|
+
* ``intersects`` (``bool``): ``True`` if product geometry intersects the search area; default: ``False``
|
|
48
|
+
* ``within`` (``bool``): ``True`` if product geometry is within the search area; default: ``False``
|
|
51
49
|
"""
|
|
52
50
|
|
|
53
51
|
def proceed(
|
|
@@ -34,10 +34,11 @@ class FilterProperty(Crunch):
|
|
|
34
34
|
|
|
35
35
|
Filter products, retaining only those whose property match criteria
|
|
36
36
|
|
|
37
|
-
:param config: Crunch configuration,
|
|
37
|
+
:param config: Crunch configuration, must contain :
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
* ``<property>`` ``(Any)`` (**mandatory**): property key from ``product.properties``, associated to its filter
|
|
40
|
+
value
|
|
41
|
+
* ``operator`` (``str``): Operator used for filtering (one of ``lt,le,eq,ne,ge,gt``). Default is ``eq``
|
|
41
42
|
"""
|
|
42
43
|
|
|
43
44
|
def proceed(
|
eodag/plugins/download/aws.py
CHANGED
|
@@ -70,6 +70,7 @@ from eodag.utils.exceptions import (
|
|
|
70
70
|
AuthenticationError,
|
|
71
71
|
DownloadError,
|
|
72
72
|
MisconfiguredError,
|
|
73
|
+
NoMatchingProductType,
|
|
73
74
|
NotAvailableError,
|
|
74
75
|
TimeOutError,
|
|
75
76
|
)
|
|
@@ -216,12 +217,28 @@ class AwsDownload(Download):
|
|
|
216
217
|
:param provider: provider name
|
|
217
218
|
:param config: Download plugin configuration:
|
|
218
219
|
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
*
|
|
224
|
-
|
|
220
|
+
* :attr:`~eodag.config.PluginConfig.type` (``str``) (**mandatory**): AwsDownload
|
|
221
|
+
* :attr:`~eodag.config.PluginConfig.base_uri` (``str``) (**mandatory**): s3 endpoint url
|
|
222
|
+
* :attr:`~eodag.config.PluginConfig.requester_pays` (``bool``): whether download is done
|
|
223
|
+
from a requester-pays bucket or not; default: ``False``
|
|
224
|
+
* :attr:`~eodag.config.PluginConfig.flatten_top_dirs` (``bool``): if the directory structure
|
|
225
|
+
should be flattened; default: ``True``
|
|
226
|
+
* :attr:`~eodag.config.PluginConfig.ignore_assets` (``bool``): ignore assets and download
|
|
227
|
+
using ``downloadLink``; default: ``False``
|
|
228
|
+
* :attr:`~eodag.config.PluginConfig.ssl_verify` (``bool``): if the ssl certificates should
|
|
229
|
+
be verified in requests; default: ``True``
|
|
230
|
+
* :attr:`~eodag.config.PluginConfig.bucket_path_level` (``int``): at which level of the
|
|
231
|
+
path part of the url the bucket can be found; If no bucket_path_level is given, the bucket
|
|
232
|
+
is taken from the first element of the netloc part.
|
|
233
|
+
* :attr:`~eodag.config.PluginConfig.products` (``Dict[str, Dict[str, Any]``): product type
|
|
234
|
+
specific config; the keys are the product types, the values are dictionaries which can contain the keys:
|
|
235
|
+
|
|
236
|
+
* **default_bucket** (``str``): bucket where the product type can be found
|
|
237
|
+
* **complementary_url_key** (``str``): keys to add additional urls
|
|
238
|
+
* **build_safe** (``bool``): if a SAFE (Standard Archive Format for Europe) product should
|
|
239
|
+
be created; used for Sentinel products; default: False
|
|
240
|
+
* **fetch_metadata** (``Dict[str, Any]``): config for metadata to be fetched for the SAFE product
|
|
241
|
+
|
|
225
242
|
"""
|
|
226
243
|
|
|
227
244
|
def __init__(self, provider: str, config: PluginConfig) -> None:
|
|
@@ -611,19 +628,20 @@ class AwsDownload(Download):
|
|
|
611
628
|
raise NotAvailableError(
|
|
612
629
|
rf"No file basename matching re.fullmatch(r'{asset_filter}') was found in {product.remote_location}"
|
|
613
630
|
)
|
|
631
|
+
|
|
632
|
+
if not unique_product_chunks:
|
|
633
|
+
raise NoMatchingProductType("No product found to download.")
|
|
634
|
+
|
|
614
635
|
return unique_product_chunks
|
|
615
636
|
|
|
616
637
|
def _raise_if_auth_error(self, exception: ClientError) -> None:
|
|
617
638
|
"""Raises an error if given exception is an authentication error"""
|
|
618
|
-
err = exception.response["Error"]
|
|
639
|
+
err = cast(Dict[str, str], exception.response["Error"])
|
|
619
640
|
if err["Code"] in AWS_AUTH_ERROR_MESSAGES and "key" in err["Message"].lower():
|
|
620
641
|
raise AuthenticationError(
|
|
621
|
-
"
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
err["Message"],
|
|
625
|
-
self.provider,
|
|
626
|
-
)
|
|
642
|
+
f"Please check your credentials for {self.provider}.",
|
|
643
|
+
f"HTTP Error {exception.response['ResponseMetadata']['HTTPStatusCode']} returned.",
|
|
644
|
+
err["Code"] + ": " + err["Message"],
|
|
627
645
|
)
|
|
628
646
|
|
|
629
647
|
def _stream_download_dict(
|
|
@@ -636,7 +654,7 @@ class AwsDownload(Download):
|
|
|
636
654
|
**kwargs: Unpack[DownloadConf],
|
|
637
655
|
) -> StreamResponse:
|
|
638
656
|
r"""
|
|
639
|
-
Returns
|
|
657
|
+
Returns dictionary of :class:`~fastapi.responses.StreamingResponse` keyword-arguments.
|
|
640
658
|
It contains a generator to streamed download chunks and the response headers.
|
|
641
659
|
|
|
642
660
|
:param product: The EO product to download
|
|
@@ -649,7 +667,7 @@ class AwsDownload(Download):
|
|
|
649
667
|
and `dl_url_params` (dict) can be provided as additional kwargs
|
|
650
668
|
and will override any other values defined in a configuration
|
|
651
669
|
file or with environment variables.
|
|
652
|
-
:returns:
|
|
670
|
+
:returns: Dictionary of :class:`~fastapi.responses.StreamingResponse` keyword-arguments
|
|
653
671
|
"""
|
|
654
672
|
if progress_callback is None:
|
|
655
673
|
logger.info(
|
|
@@ -751,7 +769,6 @@ class AwsDownload(Download):
|
|
|
751
769
|
product_chunk: Any, progress_callback: ProgressCallback
|
|
752
770
|
) -> Any:
|
|
753
771
|
try:
|
|
754
|
-
|
|
755
772
|
chunk_start = 0
|
|
756
773
|
chunk_end = chunk_start + chunk_size - 1
|
|
757
774
|
|
|
@@ -829,7 +846,7 @@ class AwsDownload(Download):
|
|
|
829
846
|
|
|
830
847
|
:param bucket_name: Bucket containg objects
|
|
831
848
|
:param prefix: Prefix used to try auth
|
|
832
|
-
:param auth_dict:
|
|
849
|
+
:param auth_dict: Dictionary containing authentication keys
|
|
833
850
|
:returns: The rasterio environement variables
|
|
834
851
|
"""
|
|
835
852
|
if self.s3_session is not None:
|
|
@@ -857,7 +874,7 @@ class AwsDownload(Download):
|
|
|
857
874
|
:param bucket_name: Bucket containg objects
|
|
858
875
|
:param prefix: Prefix used to filter objects on auth try
|
|
859
876
|
(not used to filter returned objects)
|
|
860
|
-
:param auth_dict:
|
|
877
|
+
:param auth_dict: Dictionary containing authentication keys
|
|
861
878
|
:returns: The boto3 authenticated objects
|
|
862
879
|
"""
|
|
863
880
|
auth_methods: List[
|
|
@@ -901,7 +918,7 @@ class AwsDownload(Download):
|
|
|
901
918
|
"""Auth strategy using no-sign-request"""
|
|
902
919
|
|
|
903
920
|
s3_resource = boto3.resource(
|
|
904
|
-
service_name="s3", endpoint_url=getattr(self.config, "
|
|
921
|
+
service_name="s3", endpoint_url=getattr(self.config, "s3_endpoint", None)
|
|
905
922
|
)
|
|
906
923
|
s3_resource.meta.client.meta.events.register(
|
|
907
924
|
"choose-signer.s3.*", disable_signing
|
|
@@ -919,7 +936,7 @@ class AwsDownload(Download):
|
|
|
919
936
|
s3_session = boto3.session.Session(profile_name=auth_dict["profile_name"])
|
|
920
937
|
s3_resource = s3_session.resource(
|
|
921
938
|
service_name="s3",
|
|
922
|
-
endpoint_url=getattr(self.config, "
|
|
939
|
+
endpoint_url=getattr(self.config, "s3_endpoint", None),
|
|
923
940
|
)
|
|
924
941
|
if self.requester_pays:
|
|
925
942
|
objects = s3_resource.Bucket(bucket_name).objects.filter(
|
|
@@ -958,7 +975,7 @@ class AwsDownload(Download):
|
|
|
958
975
|
s3_session = boto3.session.Session(**s3_session_kwargs)
|
|
959
976
|
s3_resource = s3_session.resource(
|
|
960
977
|
service_name="s3",
|
|
961
|
-
endpoint_url=getattr(self.config, "
|
|
978
|
+
endpoint_url=getattr(self.config, "s3_endpoint", None),
|
|
962
979
|
)
|
|
963
980
|
if self.requester_pays:
|
|
964
981
|
objects = s3_resource.Bucket(bucket_name).objects.filter(
|
|
@@ -979,7 +996,7 @@ class AwsDownload(Download):
|
|
|
979
996
|
|
|
980
997
|
s3_session = boto3.session.Session()
|
|
981
998
|
s3_resource = s3_session.resource(
|
|
982
|
-
service_name="s3", endpoint_url=getattr(self.config, "
|
|
999
|
+
service_name="s3", endpoint_url=getattr(self.config, "s3_endpoint", None)
|
|
983
1000
|
)
|
|
984
1001
|
if self.requester_pays:
|
|
985
1002
|
objects = s3_resource.Bucket(bucket_name).objects.filter(
|
eodag/plugins/download/base.py
CHANGED
|
@@ -81,15 +81,15 @@ class Download(PluginTopic):
|
|
|
81
81
|
|
|
82
82
|
- download data in the ``output_dir`` folder defined in the plugin's
|
|
83
83
|
configuration or passed through kwargs
|
|
84
|
-
- extract products from their archive (if relevant) if ``extract`` is set to True
|
|
85
|
-
(True by default)
|
|
84
|
+
- extract products from their archive (if relevant) if ``extract`` is set to ``True``
|
|
85
|
+
(``True`` by default)
|
|
86
86
|
- save a product in an archive/directory (in ``output_dir``) whose name must be
|
|
87
87
|
the product's ``title`` property
|
|
88
88
|
- update the product's ``location`` attribute once its data is downloaded (and
|
|
89
89
|
eventually after it's extracted) to the product's location given as a file URI
|
|
90
|
-
(e.g.
|
|
91
|
-
|
|
92
|
-
- save a *record* file in the directory ``output_dir/.downloaded`` whose name
|
|
90
|
+
(e.g. ``file:///tmp/product_folder`` on Linux or
|
|
91
|
+
``file:///C:/Users/username/AppData/Local/Temp`` on Windows)
|
|
92
|
+
- save a *record* file in the directory ``{output_dir}/.downloaded`` whose name
|
|
93
93
|
is built on the MD5 hash of the product's ``product_type`` and ``properties['id']``
|
|
94
94
|
attributes (``hashlib.md5((product.product_type+"-"+product.properties['id']).encode("utf-8")).hexdigest()``)
|
|
95
95
|
and whose content is the product's ``remote_location`` attribute itself.
|
|
@@ -130,8 +130,8 @@ class Download(PluginTopic):
|
|
|
130
130
|
and will override any other values defined in a configuration
|
|
131
131
|
file or with environment variables.
|
|
132
132
|
:returns: The absolute path to the downloaded product in the local filesystem
|
|
133
|
-
(e.g.
|
|
134
|
-
|
|
133
|
+
(e.g. ``/tmp/product.zip`` on Linux or
|
|
134
|
+
``C:\\Users\\username\\AppData\\Local\\Temp\\product.zip`` on Windows)
|
|
135
135
|
"""
|
|
136
136
|
raise NotImplementedError(
|
|
137
137
|
"A Download plugin must implement a method named download"
|
|
@@ -155,11 +155,11 @@ class Download(PluginTopic):
|
|
|
155
155
|
:param wait: (optional) If download fails, wait time in minutes between two download tries
|
|
156
156
|
:param timeout: (optional) If download fails, maximum time in minutes before stop retrying
|
|
157
157
|
to download
|
|
158
|
-
:param kwargs:
|
|
159
|
-
and
|
|
158
|
+
:param kwargs: ``output_dir`` (str), ``extract`` (bool), ``delete_archive`` (bool)
|
|
159
|
+
and ``dl_url_params`` (dict) can be provided as additional kwargs
|
|
160
160
|
and will override any other values defined in a configuration
|
|
161
161
|
file or with environment variables.
|
|
162
|
-
:returns:
|
|
162
|
+
:returns: Dictionary of :class:`~fastapi.responses.StreamingResponse` keyword-arguments
|
|
163
163
|
"""
|
|
164
164
|
raise NotImplementedError(
|
|
165
165
|
"Download streaming must be implemented using a method named _stream_download_dict"
|
|
@@ -458,7 +458,7 @@ class Download(PluginTopic):
|
|
|
458
458
|
:param auth: (optional) authenticated object
|
|
459
459
|
:param downloaded_callback: (optional) A method or a callable object which takes
|
|
460
460
|
as parameter the ``product``. You can use the base class
|
|
461
|
-
:class:`~eodag.
|
|
461
|
+
:class:`~eodag.utils.DownloadedCallback` and override
|
|
462
462
|
its ``__call__`` method. Will be called each time a product
|
|
463
463
|
finishes downloading
|
|
464
464
|
:param progress_callback: (optional) A progress callback
|
|
@@ -25,7 +25,16 @@ from eodag.utils.exceptions import MisconfiguredError
|
|
|
25
25
|
|
|
26
26
|
class CreodiasS3Download(AwsDownload):
|
|
27
27
|
"""
|
|
28
|
-
Download on creodias s3 from their VMs
|
|
28
|
+
Download on creodias s3 from their VMs (extension of :class:`~eodag.plugins.download.aws.AwsDownload`)
|
|
29
|
+
|
|
30
|
+
:param provider: provider name
|
|
31
|
+
:param config: Download plugin configuration:
|
|
32
|
+
|
|
33
|
+
* :attr:`~eodag.config.PluginConfig.type` (``str``) (**mandatory**): CreodiasS3Download
|
|
34
|
+
* :attr:`~eodag.config.PluginConfig.base_uri` (``str``) (**mandatory**): s3 endpoint url
|
|
35
|
+
* :attr:`~eodag.config.PluginConfig.s3_bucket` (``str``) (**mandatory**): bucket where the products can be found
|
|
36
|
+
* :attr:`~eodag.config.PluginConfig.ssl_verify` (``bool``): if the ssl certificates should be
|
|
37
|
+
verified in requests; default: ``True``
|
|
29
38
|
"""
|
|
30
39
|
|
|
31
40
|
def _get_authenticated_objects_unsigned(self, bucket_name, prefix, auth_dict):
|
|
@@ -50,7 +59,7 @@ class CreodiasS3Download(AwsDownload):
|
|
|
50
59
|
|
|
51
60
|
s3_session = boto3.session.Session(**auth_dict)
|
|
52
61
|
s3_resource = s3_session.resource(
|
|
53
|
-
"s3", endpoint_url=getattr(self.config, "
|
|
62
|
+
"s3", endpoint_url=getattr(self.config, "s3_endpoint", None)
|
|
54
63
|
)
|
|
55
64
|
objects = s3_resource.Bucket(bucket_name).objects.filter()
|
|
56
65
|
list(objects.filter(Prefix=prefix).limit(1))
|