1
0
mirror of https://github.com/peeringdb/peeringdb.git synced 2024-05-11 05:55:09 +00:00
Files
peeringdb-peeringdb/peeringdb_server/management/commands/pdb_api_cache.py

214 lines
6.6 KiB
Python
Raw Normal View History

"""
Regen the api cache files.
"""
import datetime
2018-11-08 19:45:21 +00:00
import os
import shutil
import tempfile
import time
2018-11-08 19:45:21 +00:00
import traceback
from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from django.core.management.base import BaseCommand
from rest_framework.test import APIRequestFactory
2018-11-08 19:45:21 +00:00
import peeringdb_server.models as pdbm
import peeringdb_server.rest as pdbr
from peeringdb_server.renderers import MetaJSONRenderer
MODELS = [
2019-12-05 16:57:52 +00:00
pdbm.Organization,
pdbm.Network,
pdbm.InternetExchange,
pdbm.Facility,
pdbm.NetworkContact,
pdbm.NetworkFacility,
pdbm.IXLan,
pdbm.IXLanPrefix,
pdbm.NetworkIXLan,
2018-11-08 19:45:21 +00:00
]
VIEWSETS = {
"org": pdbr.OrganizationViewSet,
"net": pdbr.NetworkViewSet,
"ix": pdbr.InternetExchangeViewSet,
"fac": pdbr.FacilityViewSet,
Support 202211 (#1304) * Carrier object implementation #909 * API keys: disabling of user account by a PeeringDB admin does not disable access via a User API key. Also no disable mech, only revoke. #1140 * Ops: django needs lightweight healthcheck route that confirms database connectivity #1284 * Ops: various indexes are needed #1285 * API requests with invalid Authentication headers should notify users in some way. #1220 * Allow user to change account username #1130 * UX to remove carriers from facilities more inline the other similar UX * more UX fixes for removing carriers from facilities * Cache hints are needed for optimal CDN use #970 * fixes Commandline tool "Run command" button gone #1278 * RIR status gets deleted when changes are made to the network #1279 * Improve MTU field #658 * CSRF cookie not set error from email confirmation view #1296 * expose CSP_CONNECT_SRC * fix confirm email path checking in session middleware * Ops: Emails to OPERATIONS_EMAIL need to be rate-limited #1282 * add website field to carrier ux * website field on carrier optional with org fallback * linting * add *.google-analytics.com to CSP_CONNECT_SRC * poetry relock * fix issues with confirm-email reverse during session creation validation * fix tests * fix tests * pin django-peeringdb to support_202211 * linting * django ratelimit to <4 * regen docs * fix automated net stats to only include networks with status `ok` #1283 * linting * poetry lock Co-authored-by: Matt Griswold <grizz@20c.com>
2023-01-18 18:32:46 +02:00
"carrier": pdbr.CarrierViewSet,
2018-11-08 19:45:21 +00:00
"ixlan": pdbr.IXLanViewSet,
"ixfac": pdbr.InternetExchangeFacilityViewSet,
"ixpfx": pdbr.IXLanPrefixViewSet,
"netfac": pdbr.NetworkFacilityViewSet,
"netixlan": pdbr.NetworkIXLanViewSet,
2019-12-05 16:57:52 +00:00
"poc": pdbr.NetworkContactViewSet,
Support 202211 (#1304) * Carrier object implementation #909 * API keys: disabling of user account by a PeeringDB admin does not disable access via a User API key. Also no disable mech, only revoke. #1140 * Ops: django needs lightweight healthcheck route that confirms database connectivity #1284 * Ops: various indexes are needed #1285 * API requests with invalid Authentication headers should notify users in some way. #1220 * Allow user to change account username #1130 * UX to remove carriers from facilities more inline the other similar UX * more UX fixes for removing carriers from facilities * Cache hints are needed for optimal CDN use #970 * fixes Commandline tool "Run command" button gone #1278 * RIR status gets deleted when changes are made to the network #1279 * Improve MTU field #658 * CSRF cookie not set error from email confirmation view #1296 * expose CSP_CONNECT_SRC * fix confirm email path checking in session middleware * Ops: Emails to OPERATIONS_EMAIL need to be rate-limited #1282 * add website field to carrier ux * website field on carrier optional with org fallback * linting * add *.google-analytics.com to CSP_CONNECT_SRC * poetry relock * fix issues with confirm-email reverse during session creation validation * fix tests * fix tests * pin django-peeringdb to support_202211 * linting * django ratelimit to <4 * regen docs * fix automated net stats to only include networks with status `ok` #1283 * linting * poetry lock Co-authored-by: Matt Griswold <grizz@20c.com>
2023-01-18 18:32:46 +02:00
"carrierfac": pdbr.CarrierFacilityViewSet,
"campus": pdbr.CampusViewSet,
2018-11-08 19:45:21 +00:00
}
MONODEPTH = {
"carrierfac",
"fac",
"ixfac",
"ixpfx",
"netfac",
"netixlan",
"poc",
}
2018-11-08 19:45:21 +00:00
settings.DEBUG = False
class Command(BaseCommand):
help = "Regen the api cache files"
def add_arguments(self, parser):
parser.add_argument(
2019-12-05 16:57:52 +00:00
"--only", action="store", default=False, help="only run specified type"
)
parser.add_argument(
"--date",
action="store",
default=None,
help="generate cache for objects create before or at the specified date (YYYYMMDD)",
2018-11-08 19:45:21 +00:00
)
parser.add_argument(
"--depths",
action="store",
default="0,1,2,3",
help="comma separated list of depths to generate",
)
parser.add_argument(
"--output-dir",
action="store",
default=settings.API_CACHE_ROOT,
help=f"output files to this directory (default: {settings.API_CACHE_ROOT})",
)
parser.add_argument(
"--public-data",
action="store_true",
default=False,
help="dump public data only as anonymous user",
)
2018-11-08 19:45:21 +00:00
def log(self, id, msg):
if self.log_file:
self.log_file.write(f"{id}: {msg}")
2018-11-08 19:45:21 +00:00
self.log_file.flush()
print(f"{id}: {msg}")
2018-11-08 19:45:21 +00:00
def row_datetime(self, row, field="created"):
return datetime.datetime.strptime(row.get(field), "%Y-%m-%dT%H:%M:%SZ")
def handle(self, *args, **options):
2019-12-05 16:57:52 +00:00
only = options.get("only", None)
date = options.get("date", None)
output_dir = options.get("output_dir")
depths = list(map(int, options.get("depths").split(",")))
2018-11-08 19:45:21 +00:00
print(f"output_dir: {output_dir}")
if options.get("public_data"):
request_user = AnonymousUser()
else:
request_user = pdbm.User.objects.filter(is_superuser=True).first()
# temporary setting to indicate api-cache is being generated
# this forced api responses to be generated without permission
# checks
settings.GENERATING_API_CACHE = True
Support 202011 (#917) * install django-grainy * nsp to grainy first iteration * Fix validation error message overflow * Add migration, update views.py and template to add help_text to UI * nsp to grainy second iteration * grainy and django-grainy pinned to latest releases * deskpro ticket cc (#875) * black formatting * move ac link to bottom for ticket body * Fix typo * Update djangorestframework, peeringdb, django-ratelimit * Rewrite login view ratelimit decorator * Relock pipfile * add list() to make copy of dictionaries before iterating * respect ix-f url visibilty in ix-f conflict emails * Add type coercion to settings taken from environment variables * Add bool handling * relock pipfile with python3.9 change docker to use python3.9 * Check bool via isinstance * add ordering to admin search queryset for deskproticket and email * update settings with envvar_type option * Add tooltips to add ix and add exchange views (in org) * Add tooltip to suggest fac view * get phone information in view * add missing migration * add migration and make org a geo model * Wire normalization to put/create requests for Facility * Update admin with new address fields * Refactor serializer using mixin * Add floor and suite to address API * Write command to geonormalize existing entries * Remove unnecessary method from model * Add floor and suite to views * Add ignore geo status * Force refresh for fac and org updates * adjust frontend typo * add checking if update needs geosync * redo error handling for geosync * remove save keyword from geonormalize command script * change raw_id_fields * alternate autocomplete lookup field depending on where inline is called * remove unnecessary error handling * Add csv option * Fix bug with None vs empty string * add regex parsing for suite and floor conversion * Add migration that removes geo error as a field * add geostatus update to command * Ignore suite floor and address2 changes for api normalization * update geomodel by removing geo_error * Black models.py * Black serializers.py * remove geocode error from admin * Add function for reversing pretty speed * add conversion to export method * fix typo * fix speed value feedback after submit * remove conditional * Add error handling to create endpoint * Refine floor and suite parsing regex * Add geocoding tests * Add json for tests * IX-F Importer: Bogus output of "Preview" tool #896 * remove cruft * black formatting * IX-F Importer: history of changes per ixlan & netixlan #893 * 6 add geocode to org view * 4 update geocode without refresh * Update error display * Fix bug with formatting translated string * Add DateTimeFields to model * Add update signals * add last updated fields to views and serializers * Add last updated model migration * Add the data migration for last updated fields * add test that tests a normal org user with create org permissions * grainy to 1.7 django grainy to 1.9.1 * Fix formatting issues * Adjust var names * Refactor signals * Temporary: save override from network model * Empty vlan lists no longer cause error * typo in ixf.py * typo in admin * Typos in model verbose names * Add serializer IXLAN validation for ixf_ixp_import_enabled * Add model validation to IXLan * relock pipfile * relock pipfile * begin signal test file * Remove full clean from save in ixlan * use post_reversion_commit signal instead * remove redundant save override * remove cruft / debug code * Add signal tests * exclude organizations with city missing from commandline geosync * Skip geosync if the only address information we have is a country * initial commit for vlan matcher in importer * Add more tests and remove unused imports * update tests * Actually add vlan matching to importer * Add type checking for speed list and state * Change how we register connection.state * add bootstrap options * add rdap cache command * remove outdated perm docs * rdap from master and relock * propagate rdap settings to peeringdb.settings * add loaddata for initial fixtures * user friendly error message on RdapNotFound errors (#497) * update rdap errors * django-peeringdb to 2.5.0 and relock * rdap to 1.2.0 and relock * fix migration hierarchy * add ignore_recurse_errors option * add missing fields to mock remove cruft missed during merge * rdap to 1.2.1 * dont geo validate during api tests * fix tests * Add test file * fix merge * RDAP_SELF_BOOTSTRAP to False while running tests * black formatted * run black * add github actions * add runs on Co-authored-by: Stefan Pratter <stefan@20c.com> Co-authored-by: Elliot Frank <elliot@20c.com>
2021-01-13 20:35:07 +00:00
2018-11-08 19:45:21 +00:00
if only:
only = only.split(",")
if date:
dt = datetime.datetime.strptime(date, "%Y%m%d")
else:
dt = datetime.datetime.now()
dtstr = dt.strftime("%Y-%m-%dT%H:%M:%SZ")
self.log_file = open(settings.API_CACHE_LOG, "w+")
self.log("info", f"Regnerating cache files to '{output_dir}'")
self.log(
"info",
f"Caching depths {str(depths)} for timestamp: {str(dtstr)}",
)
request_factory = APIRequestFactory()
2018-11-08 19:45:21 +00:00
renderer = MetaJSONRenderer()
settings.API_DEPTH_ROW_LIMIT = 0
# will be using RequestFactory to spawn requests to generate api-cache
# CSRF_USE_SESSIONS needs to be disabled as these are not session-enabled requests
settings.CSRF_USE_SESSIONS = False
start_time = time.time()
2018-11-08 19:45:21 +00:00
try:
cache = {}
# make a temp dir to create the cache files for an atomic swap
tmpdir = tempfile.TemporaryDirectory()
2018-11-08 19:45:21 +00:00
for tag, viewset in list(VIEWSETS.items()):
2018-11-08 19:45:21 +00:00
if only and tag not in only:
continue
for depth in depths:
if depth >= 1 and tag in MONODEPTH:
break
2018-11-08 19:45:21 +00:00
self.log(tag, "generating depth %d" % depth)
if depth:
request = request_factory.get(
2019-12-05 16:57:52 +00:00
"/api/%s?depth=%d&updated__lte=%s&_ctf"
% (tag, depth, dtstr)
)
2018-11-08 19:45:21 +00:00
else:
request = request_factory.get(
f"/api/{tag}?updated__lte={dtstr}&_ctf"
)
request.user = request_user
2019-12-05 16:57:52 +00:00
vs = viewset.as_view({"get": "list"})
response = vs(request)
id = f"{tag}-{depth}"
file_name = os.path.join(tmpdir.name, f"{tag}-{depth}.json")
cache[id] = file_name
renderer.render(
response.data,
renderer_context={"response": response},
file_name=file_name,
2019-12-05 16:57:52 +00:00
)
del response
2018-11-08 19:45:21 +00:00
del vs
# move the tmp files to the cache dir
for id, src_file in list(cache.items()):
print(f"output_dir: {output_dir}")
file_name = os.path.join(output_dir, "%s.json" % (id))
shutil.move(src_file, file_name)
# copy the monodepth files to the other depths
for tag in MONODEPTH:
if only and tag not in only:
continue
for depth in [1, 2, 3]:
id = f"{tag}-{depth}"
src_file = os.path.join(output_dir, f"{tag}-0.json")
file_name = os.path.join(output_dir, f"{id}.json")
self.log("info", f"copying {src_file} to {file_name}")
shutil.copyfile(src_file, file_name)
2018-11-08 19:45:21 +00:00
except Exception:
self.log("error", traceback.format_exc())
raise
finally:
tmpdir.cleanup()
self.log_file.close()
end_time = time.time()
2018-11-08 19:45:21 +00:00
print("Finished after %.2f seconds" % (end_time - start_time))