-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Change Namespace for Stored Script to Only Use Id #22206
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
|
@jdconrad Have you added deprecation logging for when the old form (including lang) has been used? |
|
@clintongormley Sorry about missing the deprecation tag! I think I always miss one. To answer your question I added deprecation logging everywhere user-input can come in from that uses lang. |
martijnvg
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.
In general looks good. A left a number of comments.
I think that we should add some bwc tests too. I think we can add some tests around stored scripts in the qa/rolling-upgrade module?
Also I think in a followup issue, the rest actions / specs should be cleanup so that only the new api remains. This change should only go into master.
| // Version 5.2+ will output the contents of the scripts' Map using | ||
| // StoredScriptSource to stored the language, code, and options. | ||
| if (out.getVersion().onOrAfter(Version.V_5_2_0_UNRELEASED)) { | ||
| out.write(scripts.size()); |
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 should be out.writeVInt(scripts.size());.
Otherwise we overflow after 127 stored scripts :)
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.
Nice catch! :)
| */ | ||
| public Builder storeScript(String id, StoredScriptSource source) { | ||
| StoredScriptSource previous = scripts.put(id, source); | ||
| scripts.put(source.getLang() + "#" + id, 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.
I wonder whether we only can add scripts under the new scheme. That way script with old scheme would over time slowly disappear. I think this should work as we already deal with old and new scheme in get and delete?
I think we only need to worry about the update case. I think that is covered if we change the method into this:
StoredScriptSource previous = scripts.remove(source.getLang() + "#" + id);
if (previous != null && previous.getLang().equals(source.getLang()) == false) {
DEPRECATION_LOGGER.deprecated("stored script [" + id + "] already exists using a different lang " +
"[" + previous.getLang() + "], the new namespace for stored scripts will only use (id) instead of (lang, id)");
}
scripts.put(id, source);
return this;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 thought about this as well and it certainly makes sense, but the tricky part is the user has no choice for stored templates. I wanted to make sure that the user could still have a stored template with the same name as a script for this version so they have time to come up with an appropriate plan for the deprecation. With the correct planning the old scheme will simply disappear when loading the scripts from cluster state metadata because we can make it ignore (and print a warning) that an old script cannot be loaded similar to how file scripts work now for scripts that do not compile.
Also, right now this technically isn't a breaking change which I think supports the user a little better (though, hopefully no one is dependent on having scripts of the same name with different languages).
| === Scripting changes | ||
|
|
||
|
|
||
|
|
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.
missing?
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.
Accidental. Good catch!
| @@ -1,14 +1,20 @@ | |||
| --- | |||
| "Indexed script": | |||
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.
not part of this change, but this should be renamed to "Stored script" :)
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.
Done.
|
|
||
| - do: | ||
| warnings: | ||
| - 'specifying lang [painless] as part of the url path is deprecated' |
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.
Also I think we should update the yaml specs to just describe the id and update the yaml tests accordingly.
So that the new behavior gets tested too.
We can add get_script_deprecated.json, delete_script_deprecated.json etc. to test that the old behaviour and that warnings get returned in the response.
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.
Updated the tests to the new namespace.
| return request.param("lang"); | ||
| // Note {lang} is actually {id} in the first handler. It appears | ||
| // parameters as part of the path must be of the same ordering relative | ||
| // to name or they will not work as expected. |
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.
true... I also don't see a way to make this nicer.
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 it will be removed in master anyway
| * {@link StoredScriptSource} represents user-defined parameters for a script | ||
| * saved in the {@link ClusterState}. | ||
| */ | ||
| public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> implements Writeable, ToXContent { |
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.
👍 much better than script as bytes
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.
:)
| assertThat(rnfe.getMessage(), equalTo("stored script [test] does not exist and cannot be deleted")); | ||
| } | ||
|
|
||
| public void testSourceParsing() throws Exception { |
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.
@colings86 is adding base test classes for writeable and xcontent serialization / de-serialization via #22281
That should get merged quickly. When that is in can you make this test class extend from AbstractSerializingTestCase. That will add random serialization tests in addition that the serialization that exist already.
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.
and maybe do the same for ScriptMetaDataTests?
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.
Done.
|
|
||
| int split = id.indexOf('#'); | ||
|
|
||
| if (split == -1) { |
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 think we can move the split check to the place where we assign the id variable?
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.
split is used in both the if and else blocks
|
@martijnvg Thank you so much for reviewing this! I agree that the old API should be removed in master -- the plan was to get this in, backport it to version 5.2 (although maybe 5.3 is more realistic given the upcoming holidays), and then remove the old API in master where we can. |
|
Added tests for rolling upgrade. These will need to be updated when the code is backported to 5.3 and when 6.0 deletes the code for the old API. |
|
@martijnvg I think this is ready for another round of review. I believe I addressed all the comments, and added several tests that you requested. Thanks! |
|
@martijnvg I added the patch you sent me to address the bwc bugs you found with one minor change -- I decided to clean up the Script readFrom and writeTo a little bit to separate out each of the read and write versions into their own if/else block as I think that will help clear up potential future confusion. And thanks again so much for catching some of the bwc bugs! Ready for another round of review when you have the chance. |
martijnvg
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.
Thx Jack! LGTM
Maybe also open an issue to track to removal of the lang parameter from the script/template apis and internal classes for 6.0?
|
@martijnvg Thanks for all the reviews here! Added this as a follow up issue (#22887) I will commit this code once I get master integrated properly and all the tests passing. |
Currently, stored scripts use a namespace of (lang, id) to be put, get, deleted, and executed. This is not necessary since the lang is stored with the stored script. A user should only have to specify an id to use a stored script. This change makes that possible while keeping backwards compatibility with the previous namespace of (lang, id). Anywhere the previous namespace is used will log deprecation warnings.
The new behavior is the following:
When a user specifies a stored script, that script will be stored under both the new namespace and old namespace.
Take for example script 'A' with lang 'L0' and data 'D0'. If we add script 'A' to the empty set, the scripts map will be ["A" -- D0, "A#L0" -- D0]. If a script 'A' with lang 'L1' and data 'D1' is then added, the scripts map will be ["A" -- D1, "A#L1" -- D1, "A#L0" -- D0].
When a user deletes a stored script, that script will be deleted from both the new namespace (if it exists) and the old namespace.
Take for example a scripts map with {"A" -- D1, "A#L1" -- D1, "A#L0" -- D0}. If a script is removed specified by an id 'A' and lang null then the scripts map will be {"A#L0" -- D0}. To remove the final script, the deprecated namespace must be used, so an id 'A' and lang 'L0' would need to be specified.
When a user gets/executes a stored script, if the new namespace is used then the script will be retrieved/executed using only 'id', and if the old namespace is used then the script will be retrieved/executed using 'id' and 'lang'
|
@jdconrad in 6.0 i assume the namespace support will no longer be deprecated but will be removed? If so, please add a note to the migration docs for 6.0 |
|
@clintongormley Yes, it will be removed, but that requires another change to actually remove it from 6.0 that I'll try to follow up with this week. Right now, it's still technically deprecated there, but not removed. Once, I make the change I'll make sure to add that as a (breaking?) note to the migration docs. |
|
@jdconrad should the spec for script api's in "path": "/_scripts/{lang}",
"paths": [ "/_scripts/{lang}", "/_scripts/{lang}/{id}" ],to "path": "/_scripts/{id}",
"paths": [ "/_scripts/{id}" ],Or has the removal not made it in yet to |
Currently, stored scripts use a namespace of (lang, id) to be put, get, deleted, and executed. This is not necessary since the lang is stored with the stored script. A user should only have to specify an id to use a stored script. This change makes that possible while keeping backwards compatibility with the previous namespace of (lang, id). Anywhere the previous namespace is used will log deprecation warnings. The goal is to backport this change to 5.2 and then remove the previous namespace altogether in 6.0 giving users the opportunity to change their scripts to the new namespace.
Why is this change so large?
This change seems huge, but it's not really. The main files changed are ScriptMetaData and ScriptService with StoredScriptSource being added. Secondarily, most of the Request files have changed a bit to support the new/old namespaces. Many lines that have changed are added JavaDocs and some new tests. Also maintaining back compat eats up some lines for XContent and the wire format.
What is the new behavior?
When a user specifies a stored script, that script will be stored under both the new namespace and old namespace.
Take for example script 'A' with lang 'L0' and data 'D0'. If we add script 'A' to the empty set, the scripts map will be ["A" -- D0, "A#L0" -- D0]. If a script 'A' with lang 'L1' and data 'D1' is then added, the scripts map will be ["A" -- D1, "A#L1" -- D1, "A#L0" -- D0].
When a user deletes a stored script, that script will be deleted from both the new namespace (if it exists) and the old namespace.
Take for example a scripts map with {"A" -- D1, "A#L1" -- D1, "A#L0" -- D0}. If a script is removed specified by an id 'A' and lang null then the scripts map will be {"A#L0" -- D0}. To remove the final script, the deprecated namespace must be used, so an id 'A' and lang 'L0' would need to be specified.
When a user gets/executes a stored script, if the new namespace is used then the script will be retrieved/executed using only 'id', and if the old namespace is used then the script will be retrieved/executed using 'id' and 'lang'