datatracker/ietf/settings_test.py
Robert Sparks 997239a2ea
feat: write objects to blob storage (#8557)
* feat: basic blobstore infrastructure for dev

* refactor: (broken) attempt to put minio console behind nginx

* feat: initialize blobstore with boto3

* fix: abandon attempt to proxy minio. Use docker compose instead.

* feat: beginning of blob writes

* feat: storage utilities

* feat: test buckets

* chore: black

* chore: remove unused import

* chore: avoid f string when not needed

* fix: inform all settings files about blobstores

* fix: declare types for some settings

* ci: point to new target base

* ci: adjust test workflow

* fix: give the tests debug environment a blobstore

* fix: "better" name declarations

* ci: use devblobstore container

* chore: identify places to write to blobstorage

* chore: remove unreachable code

* feat: store materials

* feat: store statements

* feat: store status changes

* feat: store liaison attachments

* feat: store agendas provided with Interim session requests

* chore: capture TODOs

* feat: store polls and chatlogs

* chore: remove unneeded TODO

* feat: store drafts on submit and post

* fix: handle storage during doc expiration and resurrection

* fix: mirror an unlink

* chore: add/refine TODOs

* feat: store slide submissions

* fix: structure slide test correctly

* fix: correct sense of existence check

* feat: store some indexes

* feat: BlobShadowFileSystemStorage

* feat: shadow floorplans / host logos to the blob

* chore: remove unused import

* feat: strip path from blob shadow names

* feat: shadow photos / thumbs

* refactor: combine photo and photothumb blob kinds

The photos / thumbs were already dropped in the same
directory, so let's not add a distinction at this point.

* style: whitespace

* refactor: use kwargs consistently

* chore: migrations

* refactor: better deconstruct(); rebuild migrations

* fix: use new class in mack patch

* chore: add TODO

* feat: store group index documents

* chore: identify more TODO

* feat: store reviews

* fix: repair merge

* chore: remove unnecessary TODO

* feat: StoredObject metadata

* fix: deburr some debugging code

* fix: only set the deleted timestamp once

* chore: correct typo

* fix: get_or_create vs get and test

* fix: avoid the questionable is_seekable helper

* chore: capture future design consideration

* chore: blob store cfg for k8s

* chore: black

* chore: copyright

* ci: bucket name prefix option + run Black

Adds/uses DATATRACKER_BLOB_STORE_BUCKET_PREFIX option. Other changes
are just Black styling.

* ci: fix typo in bucket name expression

* chore: parameters in app-configure-blobstore

Allows use with other blob stores.

* ci: remove verify=False option

* fix: don't return value from __init__

* feat: option to log timing of S3Storage calls

* chore: units

* fix: deleted->null when storing a file

* style: Black

* feat: log as JSON; refactor to share code; handle exceptions

* ci: add ietf_log_blob_timing option for k8s

* test: --no-manage-blobstore option for running tests

* test: use blob store settings from env, if set

* test: actually set a couple more storage opts

* feat: offswitch (#8541)

* feat: offswitch

* fix: apply ENABLE_BLOBSTORAGE to BlobShadowFileSystemStorage behavior

* chore: log timing of blob reads

* chore: import Config from botocore.config

* chore(deps): import boto3-stubs / botocore

botocore is implicitly imported, but make it explicit
since we refer to it directly

* chore: drop type annotation that mypy loudly ignores

* refactor: add storage methods via mixin

Shares code between Document and DocHistory without
putting it in the base DocumentInfo class, which
lacks the name field. Also makes mypy happy.

* feat: add timeout / retry limit to boto client

* ci: let k8s config the timeouts via env

* chore: repair merge resolution typo

* chore: tweak settings imports

* chore: simplify k8s/settings_local.py imports

---------

Co-authored-by: Jennifer Richards <jennifer@staff.ietf.org>
2025-02-19 17:41:10 -06:00

136 lines
4.7 KiB
Python
Executable file

# Copyright The IETF Trust 2010-2023, All Rights Reserved
# -*- coding: utf-8 -*-
# Standard settings except we use Postgres and skip migrations, this is
# useful for speeding up tests that depend on the test database, try
# for instance:
#
# ./manage.py test --settings=settings_test doc.ChangeStateTestCase
#
import atexit
import os
import shutil
import tempfile
from ietf.settings import * # pyflakes:ignore
from ietf.settings import STORAGES, TEST_CODE_COVERAGE_CHECKER, MORE_STORAGE_NAMES, BLOBSTORAGE_CONNECT_TIMEOUT, BLOBSTORAGE_READ_TIMEOUT, BLOBSTORAGE_MAX_ATTEMPTS
import botocore.config
import debug # pyflakes:ignore
debug.debug = True
# Use a different hostname, to catch hardcoded values
IDTRACKER_BASE_URL = "https://postgrestest.ietf.org"
# Workaround to avoid spending minutes stepping through the migrations in
# every test run. The result of this is to use the 'syncdb' way of creating
# the test database instead of doing it through the migrations. Taken from
# https://gist.github.com/NotSqrt/5f3c76cd15e40ef62d09
class DisableMigrations(object):
def __contains__(self, item):
return True
def __getitem__(self, item):
return None
MIGRATION_MODULES = DisableMigrations()
DATABASES = {
'default': {
'HOST': 'db',
'PORT': '5432',
'NAME': 'test.db',
'ENGINE': 'django.db.backends.postgresql',
'USER': 'django',
'PASSWORD': 'RkTkDPFnKpko',
},
}
if TEST_CODE_COVERAGE_CHECKER and not TEST_CODE_COVERAGE_CHECKER._started: # pyflakes:ignore
TEST_CODE_COVERAGE_CHECKER.start() # pyflakes:ignore
def tempdir_with_cleanup(**kwargs):
"""Utility to create a temporary dir and arrange cleanup"""
_dir = tempfile.mkdtemp(**kwargs)
atexit.register(shutil.rmtree, _dir)
return _dir
NOMCOM_PUBLIC_KEYS_DIR = tempdir_with_cleanup(suffix="-nomcom-public-keys-dir")
MEDIA_ROOT = tempdir_with_cleanup(suffix="-media")
PHOTOS_DIRNAME = "photo"
PHOTOS_DIR = os.path.join(MEDIA_ROOT, PHOTOS_DIRNAME)
os.mkdir(PHOTOS_DIR)
# Undo any developer-dependent middleware when running the tests
MIDDLEWARE = [ c for c in MIDDLEWARE if not c in DEV_MIDDLEWARE ] # pyflakes:ignore
TEMPLATES[0]['OPTIONS']['context_processors'] = [ p for p in TEMPLATES[0]['OPTIONS']['context_processors'] if not p in DEV_TEMPLATE_CONTEXT_PROCESSORS ] # pyflakes:ignore
REQUEST_PROFILE_STORE_ANONYMOUS_SESSIONS = False
# Override loggers with a safer set in case things go to the log during testing. Specifically,
# make sure there are no syslog loggers that might send things to a real syslog.
LOGGING["loggers"] = { # pyflakes:ignore
'django': {
'handlers': ['debug_console'],
'level': 'INFO',
},
'django.request': {
'handlers': ['debug_console'],
'level': 'ERROR',
},
'django.server': {
'handlers': ['django.server'],
'level': 'INFO',
},
'django.security': {
'handlers': ['debug_console', ],
'level': 'INFO',
},
'oidc_provider': {
'handlers': ['debug_console', ],
'level': 'DEBUG',
},
'datatracker': {
'handlers': ['debug_console'],
'level': 'INFO',
},
'celery': {
'handlers': ['debug_console'],
'level': 'INFO',
},
}
# Configure storages for the blob store - use env settings if present. See the --no-manage-blobstore test option.
_blob_store_endpoint_url = os.environ.get("DATATRACKER_BLOB_STORE_ENDPOINT_URL", "http://blobstore:9000")
_blob_store_access_key = os.environ.get("DATATRACKER_BLOB_STORE_ACCESS_KEY", "minio_root")
_blob_store_secret_key = os.environ.get("DATATRACKER_BLOB_STORE_SECRET_KEY", "minio_pass")
_blob_store_bucket_prefix = os.environ.get("DATATRACKER_BLOB_STORE_BUCKET_PREFIX", "test-")
_blob_store_enable_profiling = (
os.environ.get("DATATRACKER_BLOB_STORE_ENABLE_PROFILING", "false").lower() == "true"
)
for storagename in MORE_STORAGE_NAMES:
STORAGES[storagename] = {
"BACKEND": "ietf.doc.storage_backends.CustomS3Storage",
"OPTIONS": dict(
endpoint_url=_blob_store_endpoint_url,
access_key=_blob_store_access_key,
secret_key=_blob_store_secret_key,
security_token=None,
client_config=botocore.config.Config(
signature_version="s3v4",
connect_timeout=BLOBSTORAGE_CONNECT_TIMEOUT,
read_timeout=BLOBSTORAGE_READ_TIMEOUT,
retries={"total_max_attempts": BLOBSTORAGE_MAX_ATTEMPTS},
),
bucket_name=f"{_blob_store_bucket_prefix}{storagename}",
ietf_log_blob_timing=_blob_store_enable_profiling,
),
}