Skip to content

Issue with creating a simple cfg for Sentinel-2 #1099

@brunochatenoux

Description

@brunochatenoux

I'm trying to create a basic config file in a old instance of opendatacube-ows 1.8.26 which I cannot update yet, for Sentinel-2 product available at https://explorer.swissdatacube.org/products/s2_l2

# pylint: skip-file
# This file is part of datacube-ows, part of the Open Data Cube project.
# See https://opendatacube.org for more information.
#
# Copyright (c) 2017-2021 OWS Contributors
# SPDX-License-Identifier: Apache-2.0

import os

if os.environ.get("DATACUBE_OWS_CFG", "").startswith("integration_tests"):
    trans_dir = "."
else:
    trans_dir = "/code"


# THIS IS A TESTING FILE
# Please refer to datacube_ows/ows_cfg_example.py for EXAMPLE CONFIG

# REUSABLE CONFIG FRAGMENTS - Band alias maps
sentinel2_bands = {
    # "B01": ["coastal_aerosol", "band_1", "band_01"],
    "B02": ["blue", "band_2", "band_02"],
    "B03": ["green", "band_3", "band_03"],
    "B04": ["red", "band_4", "band_04"],
    # "B05": ["red_edge_1", "band_5", "band_05"],
    # "B06": ["red_edge_2", "band_6", "band_06"],
    # "B07": ["red_edge_3", "band_7", "band_07"],
    # "B08": ["nir", "nir_1", "band_8", "band_08"],
    # "B8A": ["nir_narrow", "nir_2", " band_8a", "narrow_nir"],
    # "B09": ["water_vapour", "band_9", "band_09"],
    # "B11": ["swir_1", "swir_16", "swir1", "band_11"],
    # "B12": ["swir_2", "swir_22", "swir2", "band_12"],
    # "AOT": ["aerosol_optical_thickness"],
    # "WVP": ["scene_average_water_vapour"],
    # "SCL": ["mask", "qa", "slc"],
}

# REUSABLE CONFIG FRAGMENTS - Style definitions
# Examples of styles which are linear combinations of the available spectral bands.
style_rgb = {
    "name": "simple_rgb",
    "title": "Simple RGB",
    "abstract": "Simple true-colour image, using the red, green and blue bands",
    # Components section is required for linear combination styles.
    # The component keys MUST be "red", "green" and "blue" (and optionally "alpha")
    "components": {
        "red": {"red": 1.0},
        "green": {"green": 1.0},
        "blue": {"blue": 1.0},
    },
    # The raw band value range to be compressed to an 8 bit range for the output image tiles.
    # Band values outside this range are clipped to 0 or 255 as appropriate.
    "scale_range": [0.0, 10000.0],
    # "pq_masks": [
    #     {
    #         "band": "quality",
    #         "flags": {"cloud": False}
    #     }
    # ],
    # "legend": {
    #     "show_legend": True,
    #     "url": {
    #         "en": "https://user-images.githubusercontent.com/4548530/112120795-b215b880-8c12-11eb-8bfa-1033961fb1ba.png"
    #     }
    # }
}

# REUSABLE CONFIG FRAGMENTS - resource limit declarations

standard_resource_limits = {
    "wms": {
        "zoomed_out_fill_colour": [150, 180, 200, 160],
        "min_zoom_factor": 35.0,
        "max_datasets": 16,  # Defaults to no dataset limit
    },
    "wcs": {
        # "max_datasets": 16, # Defaults to no dataset limit
    },
}

# MAIN CONFIGURATION OBJECT
ows_cfg = {
    # Config entries in the "global" section apply to all services and all layers/coverages
    "global": {
        "response_headers": {
            "Access-Control-Allow-Origin": "*",  # CORS header (strongly recommended)
        },
        "services": {"wms": True, "wmts": True, "wcs": True},
        "title": "Open web-services for the Swiss Data Cube",
        "allowed_urls": [
            "https://ows.swissdatacube.org/",
        ],
        # "message_file": f"{trans_dir}/integration_tests/cfg/message.po",
        # "translations_directory": f"{trans_dir}/integration_tests/cfg/translations",
        # "supported_languages": ["en", "de"],

        "info_url": "https://ows.swissdatacube.org",
        "abstract": """This web-service serves georectified raster data from SwissDatacube instance.""",
        "keywords": [
            "satellite",
            "switzerland",
            "time-series",
        ],
        # Contact info.
        # Optional but strongly recommended - defaults to blank.
        "contact_info": {
            "person": "Bruno Chatenoux",
            "organisation": "GRID_Geneva",
            "position": "Technical SDC lead",
            "address": {
                "type": "postal",
                "address": "11 chemin des Anemones",
                "city": "Chatelaine",
                "state": "Geneva",
                "postcode": "1219",
                "country": "Switzerland",
            },
            "telephone": "",
            "fax": "",
            "email": "[email protected]",
        },
        "fees": "",
        "access_constraints": "",
        # Attribution. This provides a way to identify the source of the data used in a layer or layers.
        # This entire section is optional.  If provided, it is taken as the
        # default attribution for any layer that does not override it.
        "attribution": {
            "title": "GRID Geneva",
            "url": "https://unepgrid.ch/en",
            # # Logo image - e.g. for the attributed organisation
            # "logo": {
            #     # Image width in pixels (optional)
            #     "width": 370,
            #     # Image height in pixels (optional)
            #     "height": 73,
            #     # URL for the logo image. (required if logo specified)
            #     "url": "https://www.acme.com/satellites/images/acme-370x73.png",
            #     # Image MIME type for the logo - should match type referenced in the logo url (required if logo specified.)
            #     "format": "image/png",
            # },
        },
        # Supported co-ordinate reference systems. Any coordinate system supported by GDAL and Proj.4J can be used.
        # At least one CRS must be included.  At least one geographic CRS must be included if WCS is active.
        # Web Mercator (EPSG:3857) and WGS-84 (EPSG:4326) are strongly recommended, but not required.
        "published_CRSs": {
            "EPSG:3857": {  # Web Mercator
                "geographic": False,
                "horizontal_coord": "y",
                "vertical_coord": "x",
            },
            "EPSG:4326": {  # WGS-84
                "geographic": True,
                "vertical_coord_first": True,
            },
            "EPSG:2056": {  # CH1903+ / LV95
                "geographic": False,
                "horizontal_coord": "y",
                "vertical_coord": "x",
            },
            "EPSG:32632": {  # WGS 84 / UTM zone 32N
                "geographic": False,
                "horizontal_coord": "y",
                "vertical_coord": "x",
            },
        },
        # If True the new EXPERIMENTAL materialised views are used for spatio-temporal extents.
        # If False (the default), the old "update_ranges" tables (and native ODC search methods) are used.
        # DO NOT SET THIS TO TRUE unless you understand what this means and want to participate
        # in the experiment!
        "use_extent_views": True,
    },  #### End of "global" section.
    # Config items in the "wms" section apply to the WMS service (and WMTS, which is implemented as a
    # thin wrapper to the WMS code unless stated otherwise) to all WMS/WMTS layers (unless over-ridden).
    "wms": {
        "max_width": 512,
        "max_height": 512,
    },  ####  End of "wms" section.
    # Config items in the "wcs" section apply to the WCS service to all WCS coverages
    # (unless over-ridden).
    "wcs": {
        # Must be a geographic CRS in the global published_CRSs list.
        "default_geographic_CRS": "EPSG:4326",
        "formats": {
            "GeoTIFF": {
                "renderers": {
                    "1": "datacube_ows.wcs1_utils.get_tiff",
                    "2": "datacube_ows.wcs2_utils.get_tiff",
                },
                "mime": "image/geotiff",
                "extension": "tif",
                "multi-time": False,
            },
            "netCDF": {
                "renderers": {
                    "1": "datacube_ows.wcs1_utils.get_netcdf",
                    "2": "datacube_ows.wcs2_utils.get_netcdf",
                },
                "mime": "application/x-netcdf",
                "extension": "nc",
                "multi-time": True,
            },
        },
        "native_format": "GeoTIFF",
    },  ###### End of "wcs" section
    # Products published by this datacube_ows instance.
    # The layers section is a list of layer definitions.  Each layer may be either:
    # 1) A folder-layer.  Folder-layers are not named and can contain a list of child layers.  Folder-layers are
    #    only used by WMS and WMTS - WCS does not support a hierarchical index of coverages.
    # 2) A mappable named layer that can be requested in WMS GetMap or WMTS GetTile requests.  A mappable named layer
    #    is also a coverage, that may be requested in WCS DescribeCoverage or WCS GetCoverage requests.
    "layers": [
        {
            "title": "Sentinel-2",
            "abstract": "Images from the Sentinel-2 satellite",
            "keywords": ["lsentinel2"],
            "attribution": {
                "title": "Swiss Data Cube - SDC",
                "url": "https://swissdatacube.org/",
                # # Logo image - e.g. for the attributed organisation
                # "logo": {
                #     # Image width in pixels (optional)
                #     "width": 268,
                #     # Image height in pixels (optional)
                #     "height": 68,
                #     # URL for the logo image. (required if logo specified)
                #     "url": "https://user-images.githubusercontent.com/4548530/112120795-b215b880-8c12-11eb-8bfa-1033961fb1ba.png",
                #     # Image MIME type for the logo - should match type referenced in the logo url (required if logo specified.)
                #     "format": "image/png",
                # },
            },
            "label": "sentinel-2",
            "layers": [
                {
                    "title": "Level 2 Sentinel-2",
                    "abstract": "Imagery from the Level 2 Sentinel-2",
                    "name": "s2_l2",
                    "product_name": "s2_l2",
                    # "user_band_math": True,
                    "bands": sentinel2_bands,
                    "resource_limits": standard_resource_limits,
                    "native_crs": "EPSG:3857",
                    "native_resolution": [10, 10],
                    # "flags": [
                    #     {
                    #         "band": "quality",
                    #         "product": "ls8_usgs_level1_scene",
                    #         "ignore_time": False,
                    #         "ignore_info_flags": [],
                    #         "manual_merge": True,
                    #     },
                    # ],
                    "image_processing": {
                        "extent_mask_func": "datacube_ows.ogc_utils.mask_by_val",
                        "always_fetch_bands": [],
                        "manual_merge": False,  # True
                        "apply_solar_corrections": False,
                    },
                    "styling": {
                        "default_style": "simple_rgb",
                        "styles": [
                            style_rgb,
                        ],
                    },
                },  ##### End of s2_l2 product definition.
            ],
        },  ### End of Sentinel 2 folder.
    ],  ##### End of "layers" list.
}  #### End of test configuration object

Which return:

$ datacube-ows-update --views
Refreshing materialised views...
 Setting default timezone to UTC

 Refreshing TIME materialized view (Blocking)

 Refreshing SPACE materialized view (blocking)

 Refreshing combined SPACE-TIME materialized view (concurrently)

Done

$ datacube-ows-update
Deriving extents from materialised views
OWS Layer s2_l2 maps to ODC Product(s): ('s2_l2',)
Updating range for ODC product s2_l2...
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 1802, in _execute_context
    self.dialect.do_execute(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/default.py", line 732, in do_execute
    cursor.execute(statement, parameters)
psycopg2.errors.NotNullViolation: null value in column "lat_min" of relation "product_ranges" violates not-null constraint
DETAIL:  Failing row contains (5, null, null, null, null, "", "").


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/bin/datacube-ows-update", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/datacube_ows/update_ranges_impl.py", line 98, in main
    errors = add_ranges(dc, layers, summary, merge_only)
  File "/usr/local/lib/python3.8/dist-packages/datacube_ows/product_ranges.py", line 356, in add_ranges
    create_range_entry(dc, dc_product, get_crses(), prod_summary)
  File "/usr/local/lib/python3.8/dist-packages/datacube_ows/product_ranges.py", line 168, in create_range_entry
    conn.execute(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 1274, in execute
    return self._exec_driver_sql(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 1578, in _exec_driver_sql
    ret = self._execute_context(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 1845, in _execute_context
    self._handle_dbapi_exception(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 2026, in _handle_dbapi_exception
    util.raise_(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/base.py", line 1802, in _execute_context
    self.dialect.do_execute(
  File "/usr/local/lib/python3.8/dist-packages/sqlalchemy/engine/default.py", line 732, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (psycopg2.errors.NotNullViolation) null value in column "lat_min" of relation "product_ranges" violates not-null constraint
DETAIL:  Failing row contains (5, null, null, null, null, "", "").

[SQL: 
      UPDATE wms.product_ranges pr
      SET lat_min = st_ymin(subq.bbox),
          lat_max = st_ymax(subq.bbox),
          lon_min = st_xmin(subq.bbox),
          lon_max = st_xmax(subq.bbox)
      FROM (
        SELECT st_extent(stv.spatial_extent) as bbox
        FROM public.space_time_view stv
        WHERE stv.dataset_type_ref = %(p_id)s
      ) as subq
      WHERE pr.id = %(p_id)s
      ]
[parameters: {'p_id': 5}]
(Background on this error at: https://sqlalche.me/e/14/gkpj)

Thanks in advance for any advice (other than updating) or example config file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions