-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Begin to break templates away from scripts #23744
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@dakrone this is what I told you about earlier. I don't quite have all the tests passing, but I'm oh so very close. |
|
So my goal here is to keep this as small as I could. I know there is a lot more to do here but I didn't want to copy and paste and then de-duplicate because it is so hard to find the duplicates when you do that. So instead I made two classes for the behaviors that I thought scripts and templates shared and relied on them in It ain't perfect, but it is a start. |
| @Deprecated | ||
| public static XContent xContent(BytesReference bytes) { | ||
| XContentType type = xContentType(bytes); | ||
| if (type == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my - I'm not sure why this is here......
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure we can remove this? (it's not too large of a change, it trades this exception for IllegalArgumentException("Cannot get xcontent for unknown type") )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I honestly think this was a leftover. I'm adding it back.
| MapperRegistry mapperRegistry, NamedWriteableRegistry namedWriteableRegistry, | ||
| ThreadPool threadPool, IndexScopedSettings indexScopedSettings, CircuitBreakerService circuitBreakerService, | ||
| BigArrays bigArrays, ScriptService scriptService, ClusterService clusterService, Client client, | ||
| BigArrays bigArrays, ScriptService scriptService, TemplateService templateService, Client client, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This didn't actually need ClusterService....
| * Manages caching, resource watching, permissions checking, and compilation of scripts (or | ||
| * templates). | ||
| */ | ||
| public abstract class CachingCompiler<CacheKeyT> implements ClusterStateListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really a fan of the name. It just delegates to actual compilers.
In this file I constantly say "script" when I mean "script or template". I'm not sure of a better way to say that.
| * {@link ScriptMetaData} adding the specified stored script. | ||
| */ | ||
| static ScriptMetaData putStoredScript(ScriptMetaData previous, String id, StoredScriptSource source) { | ||
| public static ScriptMetaData putStoredScript(ScriptMetaData previous, String id, StoredScriptSource source) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Public so lang-mustache can use them.
| scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry); | ||
| ScriptMetrics scriptMetrics = new ScriptMetrics(); | ||
| // Note that if templateBackend is null this won't register any settings for it | ||
| scriptSettings = new ScriptSettings(scriptEngineRegistry, templateBackend, scriptContextRegistry); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is useful for this to be able to handle a null templateBackend so we let this stay null here.
| } | ||
|
|
||
| if (templateBackend == null) { | ||
| templateBackend = new TemplatesUnsupportedBackend(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But now we have to feed TemplateService something so we feed it a backend that just throws exceptions telling the user they don't have a template backend.
|
|
||
| this.backend = backend; | ||
| this.scriptPermits = new ScriptPermits(settings, scriptSettings, scriptContextRegistry); | ||
| this.compiler = new CachingCompiler<String>(settings, env, resourceWatcherService, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We hardcode mustache in so many places I figured we really only need to support a single template language at a time. If we want to support multiple then we can revisit, but for now I went with only one at a time.
|
Ok. I've added content-type support. |
dakrone
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a bunch of comments
| @Deprecated | ||
| public static XContent xContent(BytesReference bytes) { | ||
| XContentType type = xContentType(bytes); | ||
| if (type == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure we can remove this? (it's not too large of a change, it trades this exception for IllegalArgumentException("Cannot get xcontent for unknown type") )
| public IngestService(Settings settings, ThreadPool threadPool, | ||
| Environment env, ScriptService scriptService, AnalysisRegistry analysisRegistry, | ||
| public IngestService(Settings settings, ThreadPool threadPool, Environment env, | ||
| org.elasticsearch.script.TemplateService esTemplateService, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unfortunate that we have an overlap here in class names :( I'm tempted to suggest renaming it to ScriptTemplateService or the ingest one to IngestTemplateService, not sure how large a change that would be though.
|
|
||
| InternalTemplateService(ScriptService scriptService) { | ||
| this.scriptService = scriptService; | ||
| InternalTemplateService(org.elasticsearch.script.TemplateService templateService) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is really ugly and prone to mistakes, I'm in favor of renaming the ingest version to IngestTemplateService if you don't think that'd be too disruptive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea, yeah.
|
|
||
| /** | ||
| * Returns a {@link TemplateService.Backend} if this plugin implements a template backend or null if it doesn't. Note that Elasticsearch | ||
| * will refuse to start if there is more than one template backend and it is bundled with Mustache. To replace that backend you'd have |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is the case, why do we support that? It seems like we should only support Mustache and nothing else if we think it may be unstable/untested when removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was pretty much my intent. Templates are in a module for permission isolation reasons but, yeah, we really don't support anything else. You could try but it isn't likely to work.
Would it be good enough to make this comment reflect that better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that sounds good to me.
|
|
||
| // add file watcher for file scripts and templates | ||
| scriptsDirectory = env.scriptsFile(); | ||
| if (logger.isTraceEnabled()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for this protection, I believe the logger.trace method has it already, and the arguments aren't evaluating anything expensive
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was copied from ScriptService. I can drop it though.
| validationException = addValidationError("must specify id for stored search template", | ||
| validationException); | ||
| } else | ||
| if (id.contains("#")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate the template doesn't start with _ also I think
| // ignore | ||
| } | ||
|
|
||
| return "put search template {id [" + id + "], content [" + source + "]}"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here about following the same pattern for these (regardless of what the pattern ends up being)
| @Override | ||
| public void readFrom(StreamInput in) throws IOException { | ||
| super.readFrom(in); | ||
| readAcknowledged(in); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
super.readFrom(in) already calls readAcknowledged, you're reading and writing the same boolean twice in these serialization functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it does actually. It probably ought to, but it doesn't seem to.
| @Override | ||
| protected void masterOperation(PutStoredTemplateRequest request, ClusterState state, | ||
| ActionListener<PutStoredTemplateResponse> listener) throws Exception { | ||
| if (request.content().length() > maxScriptSizeInBytes) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we already check this on the script service? I think we should delegate it there rather than having the transport layer do that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After this change ScriptService doesn't get involved in stored templates.
ScriptService does this check for scripts, yes, but I couldn't mirror that behavior for templates because these requests are in lang-mustache and TemplateService is in core.
I can do a few things:
- Move the template requests to core. We'd talked about not wanting to do that but I'm not 100% clear on the reasoning.
- Make a
StoredTemplatesServicethat does all the stored template work and leave it in lang-mustache.
| try { | ||
| templateService.checkCompileBeforeStore(source); | ||
| } catch (IllegalArgumentException | ScriptException e) { | ||
| throw new IllegalArgumentException("failed to parse/compile stored search template [" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, I'm pretty sure I've seen the same exception in the script service, are we catching and then basically duplicating the exception message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case we're literally copy and pasting the code for storage. In this case I wanted to duplicate the code because I know the script code is going to drift from the template code significantly and I want us to keep the template code as is while we do it.
Thanks for going through it. |
They don't help in log4j2. They are a leftover from a bygone age.
Also drop an unnecessary null check.
Move them to the superclass and move them to Optional
|
@nik9000 Thank you for working on this! I know it is a huge undertaking, and it is sorely needed. I have thought many times about this over the last year, but have never taken the initiative to do the grunt work. With that said, I think this PR is far too large to adequately review. It changes too many things at once, and ancillary changes exist which could be done as individual PRs. For example, the separation of script caching from the script service could be done on its own. In general, I think that the way to do this in smaller steps is to start from the consumers. We currently have the single I think this last part is incredibly important to maintain backcompat during this split. @jdconrad had a giant PR months ago that tried adding contexts to scripts. However, it was rejected on the premise that the PR was too large too review, and it broke backcompat in many ways. At this point I think maintaining backcompat is something we must strive for, however possible. Having something “not work” when upgrading, even if only while the system is in a mixed version state, breaks with our intention to give stronger backcompat guarantees, especially in providing major version rolling upgrades. |
|
Fair enough @rjernst. If you think this breaks too many things then I won't do it. I don't think I'm going to find the time or willpower start over your way for a while though. |
First: I'm genuinely sorry to whoever reviews this. It is big and will need to be looked at carefully.
This starts the process of breaking scripts and templates. I've intentionally preserved abstractions that will be lost eventually in an attempt to keep this change as small as I figured I could get away with while still enabling us to change things later. I believe I've preserved 95% of backwards compatibility. This is what I know I've broken:
Here are some things I intentionally didn't change that we probably will want to change later:
Scriptobject to refer to templates. This is pretty silly and the newTemplateServicedoesn't require it. I didn't change this to keep the PR small. It should be a followup.Script.TemplateService.Backendis the same asScriptEngineService. I didn't change this to keep the PR small. It should be a followup.Things I didn't change that we might want to change at some point but we'll need to be super careful about so we don't break backwards compatibility:
config/scriptsdirectory every few seconds.ScriptMetaData.Originally I'd planned to backport this to 5.x as well as commit to master but right now I don't have any appetite for it.