1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
import os
import requests
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.management.base import BaseCommand, CommandError
from django.template import loader
from haystack import connections, constants
from haystack.backends.solr_backend import SolrSearchBackend
class Command(BaseCommand):
help = ( # noqa A003
"Generates a Solr schema that reflects the indexes using templates "
" under a django template dir 'search_configuration/*.xml'. If none are "
" found, then provides defaults suitable to Solr 6.4"
)
schema_template_loc = "search_configuration/schema.xml"
solrcfg_template_loc = "search_configuration/solrconfig.xml"
def add_arguments(self, parser):
parser.add_argument(
"-f",
"--filename",
help="Generate schema.xml directly into a file instead of stdout."
" Does not render solrconfig.xml",
)
parser.add_argument(
"-u",
"--using",
default=constants.DEFAULT_ALIAS,
help="Select a specific Solr connection to work with.",
)
parser.add_argument(
"-c",
"--configure-directory",
help="Attempt to configure a core located in the given directory"
" by removing the managed-schema.xml(renaming) if it "
" exists, configuring the core by rendering the schema.xml and "
" solrconfig.xml templates provided in the django project's "
" TEMPLATE_DIR/search_configuration directories",
)
parser.add_argument(
"-r",
"--reload-core",
help="If provided, attempts to automatically reload the solr core"
' via the urls in the "URL" and "ADMIN_URL" settings of the SOLR'
" HAYSTACK_CONNECTIONS entry. Both MUST be set.",
)
def handle(self, **options):
"""Generates a Solr schema that reflects the indexes."""
using = options.get("using")
if not isinstance(connections[using].get_backend(), SolrSearchBackend):
raise ImproperlyConfigured("'%s' isn't configured as a SolrEngine" % using)
schema_xml = self.build_template(
using=using, template_filename=Command.schema_template_loc
)
solrcfg_xml = self.build_template(
using=using, template_filename=Command.solrcfg_template_loc
)
filename = options.get("filename")
configure_directory = options.get("configure_directory")
reload_core = options.get("reload_core")
if filename:
self.stdout.write(
"Trying to write schema file located at {}".format(filename)
)
self.write_file(filename, schema_xml)
if reload_core:
connections[using].get_backend().reload()
if configure_directory:
self.stdout.write(
"Trying to configure core located at {}".format(configure_directory)
)
managed_schema_path = os.path.join(configure_directory, "managed-schema")
if os.path.isfile(managed_schema_path):
try:
os.rename(managed_schema_path, "%s.old" % managed_schema_path)
except OSError as exc:
raise CommandError(
"Could not rename old managed schema file {}: {}".format(
managed_schema_path, exc
)
)
schema_xml_path = os.path.join(configure_directory, "schema.xml")
try:
self.write_file(schema_xml_path, schema_xml)
except EnvironmentError as exc:
raise CommandError(
"Could not configure {}: {}".format(schema_xml_path, exc)
)
solrconfig_path = os.path.join(configure_directory, "solrconfig.xml")
try:
self.write_file(solrconfig_path, solrcfg_xml)
except EnvironmentError as exc:
raise CommandError(
"Could not write {}: {}".format(solrconfig_path, exc)
)
if reload_core:
core = settings.HAYSTACK_CONNECTIONS[using]["URL"].rsplit("/", 1)[-1]
if "ADMIN_URL" not in settings.HAYSTACK_CONNECTIONS[using]:
raise ImproperlyConfigured(
"'ADMIN_URL' must be specified in the HAYSTACK_CONNECTIONS"
" for the %s backend" % using
)
if "URL" not in settings.HAYSTACK_CONNECTIONS[using]:
raise ImproperlyConfigured(
"'URL' must be specified in the HAYSTACK_CONNECTIONS"
" for the %s backend" % using
)
try:
self.stdout.write("Trying to reload core named {}".format(core))
resp = requests.get(
settings.HAYSTACK_CONNECTIONS[using]["ADMIN_URL"],
params={"action": "RELOAD", "core": core},
)
if not resp.ok:
raise CommandError(
"Failed to reload core – Solr error: {}".format(resp)
)
except CommandError:
raise
except Exception as exc:
raise CommandError("Failed to reload core {}: {}".format(core, exc))
if not filename and not configure_directory and not reload_core:
self.print_stdout(schema_xml)
def build_context(self, using):
backend = connections[using].get_backend()
if not isinstance(backend, SolrSearchBackend):
raise ImproperlyConfigured(
"'%s' isn't configured as a SolrEngine" % backend.connection_alias
)
content_field_name, fields = backend.build_schema(
connections[using].get_unified_index().all_searchfields()
)
return {
"content_field_name": content_field_name,
"fields": fields,
"default_operator": constants.DEFAULT_OPERATOR,
"ID": constants.ID,
"DJANGO_CT": constants.DJANGO_CT,
"DJANGO_ID": constants.DJANGO_ID,
}
def build_template(self, using, template_filename=schema_template_loc):
t = loader.get_template(template_filename)
c = self.build_context(using=using)
return t.render(c)
def print_stdout(self, schema_xml):
self.stderr.write("\n")
self.stderr.write("\n")
self.stderr.write("\n")
self.stderr.write(
"Save the following output to 'schema.xml' and place it in your Solr configuration directory.\n"
)
self.stderr.write(
"--------------------------------------------------------------------------------------------\n"
)
self.stderr.write("\n")
self.stdout.write(schema_xml)
def write_file(self, filename, schema_xml):
with open(filename, "w") as schema_file:
schema_file.write(schema_xml)
os.fsync(schema_file.fileno())
|