|  | 
| 17 | 17 | from stac_fastapi.sfeos_helpers.database import add_bbox_shape_to_collection | 
| 18 | 18 | from stac_fastapi.sfeos_helpers.mappings import COLLECTIONS_INDEX | 
| 19 | 19 | 
 | 
|  | 20 | +from .reindex import run as unified_reindex_run | 
|  | 21 | + | 
| 20 | 22 | logging.basicConfig(level=logging.INFO) | 
| 21 | 23 | logger = logging.getLogger(__name__) | 
| 22 | 24 | 
 | 
| @@ -225,5 +227,111 @@ def add_bbox_shape(backend, host, port, use_ssl, user, password): | 
| 225 | 227 |         sys.exit(1) | 
| 226 | 228 | 
 | 
| 227 | 229 | 
 | 
|  | 230 | +@cli.command("reindex") | 
|  | 231 | +@click.option( | 
|  | 232 | +    "--backend", | 
|  | 233 | +    type=click.Choice(["elasticsearch", "opensearch"], case_sensitive=False), | 
|  | 234 | +    required=True, | 
|  | 235 | +    help="Database backend to use", | 
|  | 236 | +) | 
|  | 237 | +@click.option( | 
|  | 238 | +    "--host", | 
|  | 239 | +    type=str, | 
|  | 240 | +    default=None, | 
|  | 241 | +    help="Database host (default: localhost or ES_HOST env var)", | 
|  | 242 | +) | 
|  | 243 | +@click.option( | 
|  | 244 | +    "--port", | 
|  | 245 | +    type=int, | 
|  | 246 | +    default=None, | 
|  | 247 | +    help="Database port (default: 9200 for ES, 9202 for OS, or ES_PORT env var)", | 
|  | 248 | +) | 
|  | 249 | +@click.option( | 
|  | 250 | +    "--use-ssl/--no-ssl", | 
|  | 251 | +    default=None, | 
|  | 252 | +    help="Use SSL connection (default: true or ES_USE_SSL env var)", | 
|  | 253 | +) | 
|  | 254 | +@click.option( | 
|  | 255 | +    "--user", | 
|  | 256 | +    type=str, | 
|  | 257 | +    default=None, | 
|  | 258 | +    help="Database username (default: ES_USER env var)", | 
|  | 259 | +) | 
|  | 260 | +@click.option( | 
|  | 261 | +    "--password", | 
|  | 262 | +    type=str, | 
|  | 263 | +    default=None, | 
|  | 264 | +    help="Database password (default: ES_PASS env var)", | 
|  | 265 | +) | 
|  | 266 | +@click.option( | 
|  | 267 | +    "--yes", | 
|  | 268 | +    is_flag=True, | 
|  | 269 | +    help="Skip confirmation prompt", | 
|  | 270 | +) | 
|  | 271 | +def reindex(backend, host, port, use_ssl, user, password, yes): | 
|  | 272 | +    """Reindex all STAC indexes to the next version and update aliases. | 
|  | 273 | +
 | 
|  | 274 | +    For Elasticsearch, this runs a migration that: | 
|  | 275 | +    - Creates/updates index templates | 
|  | 276 | +    - Reindexes collections and item indexes to a new version | 
|  | 277 | +    - Applies asset migration script for compatibility | 
|  | 278 | +    - Switches aliases to the new indexes | 
|  | 279 | +    """ | 
|  | 280 | +    import os | 
|  | 281 | + | 
|  | 282 | +    backend = backend.lower() | 
|  | 283 | + | 
|  | 284 | +    if not yes: | 
|  | 285 | +        proceed = click.confirm( | 
|  | 286 | +            "This will reindex all collections and item indexes and update aliases. Proceed?", | 
|  | 287 | +            default=False, | 
|  | 288 | +        ) | 
|  | 289 | +        if not proceed: | 
|  | 290 | +            click.echo(click.style("Aborted", fg="yellow")) | 
|  | 291 | +            return | 
|  | 292 | + | 
|  | 293 | +    # Set environment variables from CLI options if provided | 
|  | 294 | +    if host: | 
|  | 295 | +        os.environ["ES_HOST"] = host | 
|  | 296 | +    if port: | 
|  | 297 | +        os.environ["ES_PORT"] = str(port) | 
|  | 298 | +    if use_ssl is not None: | 
|  | 299 | +        os.environ["ES_USE_SSL"] = "true" if use_ssl else "false" | 
|  | 300 | +    if user: | 
|  | 301 | +        os.environ["ES_USER"] = user | 
|  | 302 | +    if password: | 
|  | 303 | +        os.environ["ES_PASS"] = password | 
|  | 304 | + | 
|  | 305 | +    try: | 
|  | 306 | +        asyncio.run(unified_reindex_run(backend)) | 
|  | 307 | +        click.echo( | 
|  | 308 | +            click.style( | 
|  | 309 | +                f"✓ Reindex ({backend.title()}) completed successfully", fg="green" | 
|  | 310 | +            ) | 
|  | 311 | +        ) | 
|  | 312 | +    except KeyboardInterrupt: | 
|  | 313 | +        click.echo(click.style("\n✗ Reindex interrupted by user", fg="yellow")) | 
|  | 314 | +        sys.exit(1) | 
|  | 315 | +    except Exception as e: | 
|  | 316 | +        error_msg = str(e) | 
|  | 317 | +        click.echo(click.style(f"✗ Reindex failed: {error_msg}", fg="red")) | 
|  | 318 | +        # Provide helpful hints for common errors | 
|  | 319 | +        if "TLS" in error_msg or "SSL" in error_msg: | 
|  | 320 | +            click.echo( | 
|  | 321 | +                click.style( | 
|  | 322 | +                    "\n💡 Hint: If you're connecting to a local Docker Compose instance, try adding --no-ssl flag", | 
|  | 323 | +                    fg="yellow", | 
|  | 324 | +                ) | 
|  | 325 | +            ) | 
|  | 326 | +        elif "Connection refused" in error_msg: | 
|  | 327 | +            click.echo( | 
|  | 328 | +                click.style( | 
|  | 329 | +                    "\n💡 Hint: Make sure your database is running and accessible at the specified host:port", | 
|  | 330 | +                    fg="yellow", | 
|  | 331 | +                ) | 
|  | 332 | +            ) | 
|  | 333 | +        sys.exit(1) | 
|  | 334 | + | 
|  | 335 | + | 
| 228 | 336 | if __name__ == "__main__": | 
| 229 | 337 |     cli() | 
0 commit comments