Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 21 additions & 131 deletions geonode/br/management/commands/create_tile_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,155 +19,45 @@
#########################################################################

import logging
import requests
from requests.auth import HTTPBasicAuth

from django.core.management.base import BaseCommand
from django.conf import settings

from geonode.layers.models import Dataset
from typing_extensions import deprecated

from geonode.geoserver.management.commands.gwc_subcommands.create import CreateTileLayers as gwc_create

logger = logging.getLogger(__name__)


REQ_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
<GeoServerLayer>
<enabled>true</enabled>
<inMemoryCached>true</inMemoryCached>
<name>{}</name>
<metaWidthHeight>
<int>2</int>
<int>1</int>
</metaWidthHeight>
<mimeFormats>
<string>application/json;type=utfgrid</string>
<string>image/gif</string>
<string>image/jpeg</string>
<string>image/png</string>
<string>image/png8</string>
<string>image/vnd.jpeg-png</string>
<string>image/vnd.jpeg-png8</string>
</mimeFormats>
<gridSubsets>
<gridSubset>
<gridSetName>EPSG:3857</gridSetName>
</gridSubset>
<gridSubset>
<gridSetName>EPSG:3857x2</gridSetName>
</gridSubset>
<gridSubset>
<gridSetName>EPSG:4326</gridSetName>
</gridSubset>
<gridSubset>
<gridSetName>EPSG:4326x2</gridSetName>
</gridSubset>
<gridSubset>
<gridSetName>EPSG:900913</gridSetName>
</gridSubset>
</gridSubsets>
<expireCache>0</expireCache>
<expireClients>0</expireClients>
<autoCacheStyles>true</autoCacheStyles>
<gutter>0</gutter>
<cacheWarningSkips/>
</GeoServerLayer>"""


@deprecated("THIS COMMAND IS DEPRECATED - USE THE gwc COMMAND INSTEAD")
class Command(BaseCommand):
help = "Create missing TileLayers in GWC"
help = "DEPRECATED COMMAND - USE gwc COMMAND INSTEAD - Create missing TileLayers in GWC"

def add_arguments(self, parser):
parser.add_argument(
'-f',
'--force',
"-f",
"--force",
dest="force",
action='store_true',
help="Force tile layer re-creation also if it already exists in GWC")
action="store_true",
help="Force tile layer re-creation also if it already exists in GWC",
)

parser.add_argument(
'-l',
'--layer',
dest="layers",
action='append',
help="Only process specified layers ")
parser.add_argument("-l", "--layer", dest="layers", action="append", help="Only process specified layers ")

parser.add_argument(
'-d',
'--dry-run',
dest="dry-run",
action='store_true',
help="Do not actually perform any change on GWC")
"-d", "--dry-run", dest="dry-run", action="store_true", help="Do not actually perform any change on GWC"
)

def handle(self, **options):
force = options.get('force')
requested_layers = options.get('layers')
dry_run = options.get('dry-run')
logger.error("THIS COMMAND IS DEPRECATED - USE THE gwc COMMAND INSTEAD")

force = options.get("force")
requested_layers = options.get("layers") or []
dry_run = options.get("dry-run")

logger.debug(f"FORCE is {force}")
logger.debug(f"DRY-RUN is {dry_run}")
logger.debug(f"LAYERS is {requested_layers}")

try:
baseurl = settings.OGC_SERVER["default"]["LOCATION"]
user = settings.OGC_SERVER["default"]["USER"]
passwd = settings.OGC_SERVER["default"]["PASSWORD"]
"""
curl -v -u admin:geoserver -XGET \
"http://<host>:<port>/geoserver/gwc/rest/layers/geonode:tasmania_roads.xml"
"""
layers = Dataset.objects.all()
tot = len(layers)
logger.info(f"Total layers in GeoNode: {tot}")
i = 0
cnt_old = 0
cnt_new = 0
cnt_bad = 0
cnt_skip = 0
cnt_force = 0
for layer in layers:
i += 1
logger.info(f"- {i}/{tot} Processing layer: {layer.typename}")

if requested_layers and layer.typename not in requested_layers:
logger.info(" - Layer filtered out by args")
cnt_skip += 1
continue

r = requests.get(f"{baseurl}gwc/rest/layers/{layer.typename}.xml", auth=HTTPBasicAuth(user, passwd))

if r.status_code == 200:
if force:
logger.info(" - Forcing layer configuration in GWC")
cnt_force += 1
else:
logger.info(" - Layer already configured in GWC")
cnt_old += 1
continue
try:
data = REQ_TEMPLATE.format(layer.name)
url = f"{baseurl}gwc/rest/layers/{layer.typename}.xml"
logger.info(" - Configuring...")

if not dry_run:
response = requests.put(
url, data=data, headers={"Content-Type": "text/xml"}, auth=HTTPBasicAuth(user, passwd)
)

if dry_run or response.status_code == 200:
logger.info(f" - Done {layer.name}")
cnt_new += 1
else:
logger.warning(f"Layer {layer.typename} couldn't be configured: code {response.status_code}")
cnt_bad += 1

except Exception as e:
raise e
except Exception as e:
raise e

logger.info("Work completed")
logger.info(f"- TileLayers configured: {cnt_new}" + (f" (forced {cnt_force})" if cnt_force else ""))
logger.info(f"- TileLayers in error : {cnt_bad}")
logger.info(f"- TileLayers untouched : {cnt_old}")
logger.info(f"- TileLayers skipped : {cnt_skip}")
subcommand = gwc_create()
subcommand.run(
force=force, requested_layers=requested_layers, create_all=len(requested_layers) == 0, dry_run=dry_run
)
40 changes: 38 additions & 2 deletions geonode/geoserver/gwc.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,40 @@ class GWCClient:
A GeoWebCache REST client for interacting with the GWC API.
"""

def __init__(self) -> None:
def __init__(self, **kwargs) -> None:
self.base_url = f"{ogc_server_settings.LOCATION}gwc/rest/"
self.debug = kwargs.get("debug", False)

def __log_response(self, r):
if self.debug:
logger.debug(f'{r.request.method} response: code:{r.status_code} --> "{r.text}"')
else:
logger.debug(f"{r.request.method} response: code:{r.status_code} --> {len(r.text)} bytes")

def _get(self, urlpath):
_user, _password = ogc_server_settings.credentials

url = f"{self.base_url}{urlpath}"
r = requests.get(url=url, auth=HTTPBasicAuth(_user, _password), timeout=30)
self.__log_response(r)
return r

def _post(self, urlpath, data):
_user, _password = ogc_server_settings.credentials

url = f"{self.base_url}{urlpath}"
r = requests.post(url=url, data=data, auth=HTTPBasicAuth(_user, _password), timeout=30)
logger.debug(f'POST response: code:{r.status_code} --> "{r.text}"')
self.__log_response(r)
return r

def _put(self, urlpath, data):
_user, _password = ogc_server_settings.credentials

url = f"{self.base_url}{urlpath}"
r = requests.put(
url=url, data=data, headers={"Content-Type": "text/xml"}, auth=HTTPBasicAuth(_user, _password), timeout=30
)
self.__log_response(r)
return r

@staticmethod
Expand All @@ -60,6 +85,17 @@ def _validate_layer_name(layer_name: str, workspace: str | None = None) -> str:
layer_name = f"{workspace}:{layer_name}"
return layer_name

def get_layer(self, layer_name: str, workspace: str | None = None) -> requests.Response:
"""
Get GWC layer information. Returns the raw response from the GWC API.
"""
layer_name = self._validate_layer_name(layer_name, workspace)
return self._get(f"layers/{layer_name}.xml")

def set_layer(self, layer_name: str, workspace: str | None = None, data=None) -> requests.Response:
layer_name = self._validate_layer_name(layer_name, workspace)
return self._put(f"layers/{layer_name}.xml", data=data)

def truncate_layer(self, layer_name: str, workspace: str | None = None) -> None:
"""
Truncate all cached tiles for a GWC layer.
Expand Down
56 changes: 31 additions & 25 deletions geonode/geoserver/management/commands/gwc.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,47 +21,53 @@

from geonode.base.management.command_utils import setup_logger
from geonode.geoserver.management.commands.gwc_subcommands import truncate
from geonode.geoserver.management.commands.gwc_subcommands.create import CreateTileLayers

logger = setup_logger()

COMMAND_TRUNCATE = "truncate"
COMMANDS = [COMMAND_TRUNCATE]
COMMAND_CREATE = "create"
COMMANDS = [COMMAND_CREATE, COMMAND_TRUNCATE]


class Command(BaseCommand):
help = f"Handles GWC commands {COMMANDS}"

def _add_common_arguments(self, parser):
parser.add_argument(
'-d',
'--dry-run',
dest="dry-run",
action='store_true',
help="Do not actually perform any change on GWC")

parser.add_argument(
'--debug',
dest="debug",
action='store_true',
help="Show debug logging")

def add_arguments(self, parser):
parser.add_argument("subcommand", nargs="?", choices=COMMANDS, help="GWC operation to run")

truncate_group = parser.add_argument_group('Params for "truncate" subcommand')
truncate_group.add_argument(
"-l",
"--layer",
dest="layers",
action="append",
help="Name of the layer(s) to truncate. Can be repeated.",
)
truncate_group.add_argument(
"--all",
dest="truncate_all",
action="store_true",
help="Truncate all cache in GWC",
)
subparsers = parser.add_subparsers(dest="subcommand", required=True)

def handle(self, *args, **options):
subcommand = options["subcommand"]
logger.info("Starting GWC command.")
parser_truncate = subparsers.add_parser(COMMAND_TRUNCATE, help="Truncate tile layers")
truncate.add_arguments(parser_truncate)
self._add_common_arguments(parser_truncate)

if not subcommand:
logger.warning("No GWC subcommand provided.")
self.print_help("manage.py", "gwc")
return
parser_create = subparsers.add_parser(COMMAND_CREATE, help="Create tile layers")
CreateTileLayers().add_arguments(parser_create)
self._add_common_arguments(parser_create)

logger.info("Executing GWC subcommand '%s'.", subcommand)
def handle(self, *args, **options):
subcommand = options["subcommand"]
logger.info(f"Executing GWC subcommand '{subcommand}'...")

if subcommand == COMMAND_TRUNCATE:
truncate.handle(options)

elif subcommand == COMMAND_CREATE:
CreateTileLayers().handle(**options)
else:
raise CommandError(f"Unknown subcommand: {subcommand}")

logger.info(f"GWC subcommand {subcommand} completed.")
Loading
Loading