You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2019/10/21 18:09:23 UTC
[trafficserver] branch 9.0.x updated (4c9bdef -> 970a9a2)
This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a change to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git.
from 4c9bdef Cleanup: unifdef TRACK_BUFFER_USER
new 28e1d6d Doc: Guide to remap plugin API.
new a8bcd1c Rearrange config reload notifications
new 970a9a2 "Plugin (un)used" post reload notification
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
build/plugins.mk | 2 +-
doc/developer-guide/api/functions/TSRemap.en.rst | 40 ++++-
doc/developer-guide/api/functions/TSTypes.en.rst | 40 +++++
doc/developer-guide/plugins/index.en.rst | 1 +
doc/developer-guide/plugins/remap-plugins.en.rst | 175 ++++++++++++++++++++
include/ts/remap.h | 32 +++-
proxy/ReverseProxy.cc | 2 +-
proxy/http/remap/Makefile.am | 2 +-
proxy/http/remap/PluginDso.h | 11 +-
proxy/http/remap/PluginFactory.cc | 87 +++++++---
proxy/http/remap/PluginFactory.h | 6 +-
proxy/http/remap/RemapConfig.cc | 15 +-
proxy/http/remap/RemapPluginInfo.cc | 37 +++--
proxy/http/remap/RemapPluginInfo.h | 27 +--
.../http/remap/unit-tests/plugin_testing_calls.cc | 11 +-
.../http/remap/unit-tests/plugin_testing_common.h | 48 +++---
proxy/http/remap/unit-tests/test_PluginDso.cc | 6 +-
proxy/http/remap/unit-tests/test_PluginFactory.cc | 184 +++++++++++++++++----
proxy/http/remap/unit-tests/test_RemapPlugin.cc | 44 ++++-
19 files changed, 642 insertions(+), 128 deletions(-)
create mode 100644 doc/developer-guide/plugins/remap-plugins.en.rst
[trafficserver] 02/03: Rearrange config reload notifications
Posted by zw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit a8bcd1c58cdf70e1fb810738a3ea76850e79baa0
Author: Gancho Tenev <ga...@apache.org>
AuthorDate: Tue Sep 3 13:19:40 2019 -0700
Rearrange config reload notifications
Renamed `TSRemapConfigReload` to `TSRemapPreConfigReload` to notify
all already loaded plugins that a configuration (re)load is about to
start.
Added new `TSRemapPostConfigReload(TSReturnCode)` to notify the plugins
that the configuration (re)load is done and provide status of its
success or failure.
(cherry picked from commit 70de21d9c72997564ee9ae549cac5407e0f48a98)
---
build/plugins.mk | 2 +-
doc/developer-guide/api/functions/TSRemap.en.rst | 14 ++-
doc/developer-guide/plugins/remap-plugins.en.rst | 79 ++++++++------
include/ts/remap.h | 22 +++-
proxy/ReverseProxy.cc | 2 +-
proxy/http/remap/Makefile.am | 2 +-
proxy/http/remap/PluginDso.h | 10 +-
proxy/http/remap/PluginFactory.cc | 75 ++++++++-----
proxy/http/remap/PluginFactory.h | 6 +-
proxy/http/remap/RemapConfig.cc | 15 ++-
proxy/http/remap/RemapPluginInfo.cc | 37 +++++--
proxy/http/remap/RemapPluginInfo.h | 27 +++--
.../http/remap/unit-tests/plugin_testing_calls.cc | 11 +-
.../http/remap/unit-tests/plugin_testing_common.h | 28 ++---
proxy/http/remap/unit-tests/test_PluginDso.cc | 6 +-
proxy/http/remap/unit-tests/test_PluginFactory.cc | 119 ++++++++++++++++-----
proxy/http/remap/unit-tests/test_RemapPlugin.cc | 9 +-
17 files changed, 320 insertions(+), 144 deletions(-)
diff --git a/build/plugins.mk b/build/plugins.mk
index 86d0a66..4556fc2 100644
--- a/build/plugins.mk
+++ b/build/plugins.mk
@@ -22,7 +22,7 @@ TS_PLUGIN_LD_FLAGS = \
-module \
-shared \
-avoid-version \
- -export-symbols-regex '^(TSRemapInit|TSRemapDone|TSRemapDoRemap|TSRemapNewInstance|TSRemapDeleteInstance|TSRemapOSResponse|TSPluginInit)$$'
+ -export-symbols-regex '^(TSRemapInit|TSRemapDone|TSRemapDoRemap|TSRemapNewInstance|TSRemapDeleteInstance|TSRemapOSResponse|TSPluginInit|TSRemapPreConfigReload|TSRemapPostConfigReload)$$'
TS_PLUGIN_CPPFLAGS = \
-I$(abs_top_builddir)/proxy/api \
diff --git a/doc/developer-guide/api/functions/TSRemap.en.rst b/doc/developer-guide/api/functions/TSRemap.en.rst
index ddd9917..bbfc220 100644
--- a/doc/developer-guide/api/functions/TSRemap.en.rst
+++ b/doc/developer-guide/api/functions/TSRemap.en.rst
@@ -30,7 +30,8 @@ Synopsis
`#include <ts/remap.h>`
.. function:: TSReturnCode TSRemapInit(TSRemapInterface * api_info, char * errbuff, int errbuff_size)
-.. function:: void TSRemapConfigReload(void)
+.. function:: void TSRemapPreConfigReload(void)
+.. function:: void TSRemapPostConfigReload(TSReturnCode reloadStatus)
.. function:: void TSRemapDone(void)
.. function:: TSRemapStatus TSRemapDoRemap(void * ih, TSHttpTxn rh, TSRemapRequestInfo * rri)
.. function:: TSReturnCode TSRemapNewInstance(int argc, char * argv[], void ** ih, char * errbuff, int errbuff_size)
@@ -65,9 +66,14 @@ any data or continuations associated with that instance.
entry point. In this function, the remap plugin may examine and modify
the HTTP transaction.
-:func:`TSRemapConfigReload` is called once for every remap plugin immediately after a new
-configuration is successfully loaded and immediately before the new remap configuration becomes
-active. This is an optional entry point, which takes no arguments and has no return value.
+:func:`TSRemapPreConfigReload` is called *before* the parsing of a new remap configuration starts
+to notify plugins of the coming configuration reload. It is called on all already loaded plugins,
+invoked by current and all previous still used configurations. This is an optional entry point.
+
+:func:`TSRemapPostConfigReload` is called to indicate the end of the the new remap configuration
+load. It is called on the newly and previously loaded plugins, invoked by the new, current and
+previous still used configurations. It also indicates if the configuration reload was successful
+by passing :macro:`TS_SUCCESS` or :macro:`TS_ERROR`. This is an optional entry point.
Generally speaking, calls to these functions are mutually exclusive. The exception
is for functions which take an HTTP transaction as a parameter. Calls to these
diff --git a/doc/developer-guide/plugins/remap-plugins.en.rst b/doc/developer-guide/plugins/remap-plugins.en.rst
index 7b691c6..ead70b2 100644
--- a/doc/developer-guide/plugins/remap-plugins.en.rst
+++ b/doc/developer-guide/plugins/remap-plugins.en.rst
@@ -80,12 +80,46 @@ multiple times for the rule, once for each invocation. Only the value store in :
available when the rule is actually matched. In particular the plugin arguments will not be
available.
-Calls to :func:`TSRemapNewInstance` are serialized.
+Calls to :func:`TSRemapNewInstance` are serialized. All calls to :func:`TSRemapNewInstance`
+for a given configuration will be called and completed before any calls to :func:`TSRemapDoRemap`.
If there is an error then the callback should return :macro:`TS_ERROR` and fill in the
:arg:`errbuff` with a C-string describing the error. Otherwise the function must return
:macro:`TS_SUCCESS`.
+
+Configuration reload notifications
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:func:`TSRemapPreConfigReload` is called *before* the parsing of a new remap configuration starts
+to notify plugins of the coming configuration reload. It is called on all already loaded plugins,
+invoked by current and all previous still used configurations. This is an optional entry point.
+
+:func:`TSRemapPostConfigReload` is called to indicate the end of the the new remap configuration
+load. It is called on the newly and previously loaded plugins, invoked by the new, current and
+previous still used configurations. It also indicates if the configuration reload was successful
+by passing :macro:`TS_SUCCESS` or :macro:`TS_ERROR`. This is an optional entry point.
+
+These calls are called per *plugin*, not per invocation of the plugin in :file:`remap.config`
+and only will be called if the plugin was called at least once with :func:`TSRemapNewInstance`
+for any configuration and at least one configuration using it is still loaded.
+
+:func:`TSRemapPreConfigReload` will be called serially for all loaded plugins
+before any call to :func:`TSRemapNewInstance` during parsing of the new configuration.
+
+:func:`TSRemapPostConfigReload` will be called serially for all plugins after
+all calls to :func:`TSRemapNewInstance` during parsing of the new configuration.
+
+The intention of these callbacks can be demonstrated with the following use-case.
+A plugin could use :func:`TSRemapPreConfigReload` as a signal to drop (or allocate) temporary
+per plugin data structures. These structures can be created (or updated) as needed
+when a plugin invocation instance is loaded (:func:`TSRemapNewInstance` is called).
+Then it could be used in subsequent invocation instances loading. After the configuration
+reload is done :func:`TSRemapPostConfigReload` could be used to confirm
+the data structures update if :macro:`TS_SUCCESS` is passed or recover / clean-up
+after a failed reload attempt if :macro:`TS_ERROR` is passed.
+
+
Runtime
=======
@@ -104,8 +138,13 @@ Calls to :func:`TSRemapDoRemap` are not serialized, they can be concurrent, even
invocation instance. However, the callbacks for a single rule for a single transaction are
serialized in the order the plugins are invoked in the rule.
-All calls to :func:`TSRemapNewInstance` for a given configuration will be called and completed
-before any calls to :func:`TSRemapDoRemap`.
+No calls to :func:`TSRemapDoRemap` will occur before :func:`TSRemapPostConfigReload` for
+all plugin instances invoked by the new configuration.
+
+The old configurations, if any, are still active during the calls to :func:`TSRemapPreConfigReload`
+and :func:`TSRemapPreConfigReload` and therefore calls to :func:`TSRemapDoRemap` may occur
+concurrently with those functions.
+
Cleanup
=======
@@ -114,35 +153,9 @@ When a new :file:`remap.config` is loaded successfully, the prior configuration
each call to :func:`TSRemapNewInstance` a corresponding call to :func:`TSRemapDeleteInstance` is
called. The only argument is the invocation instance handle, originally provided by the plugin to
:func:`TSRemapNewInstance`. This is expected to suffice for the plugin to clean up any rule specific
-data.
-
-As part of the old configuration cleanup :func:`TSRemapConfigReload` is called on the plugins in the
-old configuration before any calls to :func:`TSRemapDeleteInstance`. This is an optional entry
-point.
-
-.. note::
-
- This is called per *plugin*, not per invocation of the plugin in :file:`remap.config`, and only
- called if the plugin was called at least once with :func:`TSRemapNewInstance` for that
- configuration.
-
-.. note::
-
- There is no explicit indication or connection between the call to :func:`TSRemapConfigReload` and
- the "old" (existing) configuration. It is guaranteeed that :func:`TSRemapConfigReload` will be
- called on all the plugins before any :func:`TSRemapDeleteInstance` and these calls will be
- serial. Similarly, :func:`TSRemapConfigReload` will be called serially after all calls to
- :func:`TSRemapNewInstance` for a given configuration.
-
-.. note::
-
- The old configuration, if any, is still active during the call to :func:`TSRemapConfigReload` and
- therefore calls to :func:`TSRemapDoRemap` may occur concurrently with that function.
-
-The intention of :func:`TSRemapConfigReload` is to provide for temporary data structures used only
-during configuration loading. These can be created as needed when an invocation instance is loaded
-and used in subsequent invocation instance loading, then cleaned up in :func:`TSRemapConfigReload`.
+data. Calls to :func:`TSRemapDeleteInstance` will be serial for all plugin invocations in a
+remap configuration.
If no rule uses a plugin, it may be unloaded. In that case :func:`TSRemapDone` is called. This is
-an optional entry point, a plugin is not required to provide it. It is called once per plugin, not
-per plugin invocation.
+an optional entry point, a plugin is not required to provide it. It corresponds to :func:`TSRemapInit`.
+It is called once per plugin, not per plugin invocation.
diff --git a/include/ts/remap.h b/include/ts/remap.h
index cc263fd..dd7be38 100644
--- a/include/ts/remap.h
+++ b/include/ts/remap.h
@@ -88,13 +88,27 @@ typedef enum {
*/
tsapi TSReturnCode TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size);
-/* This gets called every time remap.config is reloaded. This is complementary
- to TSRemapInit() which gets called when the plugin is first loaded. You can
- not fail, or cause reload to stop here, it's merely a notification.
+/* This gets called every time before remap.config is reloaded. This is complementary
+ to TSRemapInit() which gets called when the plugin is first loaded.
+ It is guaranteed to be called before TSRemapInit() and TSRemapNewInstance().
+ It cannot fail, or cause reload to stop here, it's merely a notification.
Optional function.
+ Params: none
Return: none
*/
-tsapi void TSRemapConfigReload(void);
+tsapi void TSRemapPreConfigReload(void);
+
+/* This gets called every time afterremap.config is reloaded. This is complementary
+ to TSRemapInit() which gets called when the plugin is first loaded.
+ It is guaranteed to be called after TSRemapInit() and TSRemapNewInstance().
+ It cannot fail, or cause reload to stop here, it's merely a notification that
+ the (re)load is done and provide a status of its success or failure..
+ Optional function.
+ Params: reloadStatus - TS_SUCCESS - (re)load was successful,
+ TS_ERROR - (re)load failed.
+ Return: none
+*/
+tsapi void TSRemapPostConfigReload(TSReturnCode reloadStatus);
/* Remap new request
Mandatory interface function.
diff --git a/proxy/ReverseProxy.cc b/proxy/ReverseProxy.cc
index d7d3ae0..2f5de1a 100644
--- a/proxy/ReverseProxy.cc
+++ b/proxy/ReverseProxy.cc
@@ -151,7 +151,7 @@ reloadUrlRewrite()
ink_assert(oldTable != nullptr);
// Release the old one
- oldTable->pluginFactory.indicateReload();
+ oldTable->pluginFactory.deactivate();
oldTable->release();
Debug("url_rewrite", "%s", msg);
diff --git a/proxy/http/remap/Makefile.am b/proxy/http/remap/Makefile.am
index ad705d3..8973d1b 100644
--- a/proxy/http/remap/Makefile.am
+++ b/proxy/http/remap/Makefile.am
@@ -103,7 +103,7 @@ DSO_LDFLAGS = \
-module \
-shared \
-avoid-version \
- -export-symbols-regex '^(TSRemapInit|TSRemapDone|TSRemapDoRemap|TSRemapNewInstance|TSRemapDeleteInstance|TSRemapOSResponse|TSRemapConfigReload|TSPluginInit|pluginDsoVersionTest|getPluginDebugObjectTest)$$'
+ -export-symbols-regex '^(TSRemapInit|TSRemapDone|TSRemapDoRemap|TSRemapNewInstance|TSRemapDeleteInstance|TSRemapOSResponse|TSRemapPreConfigReload|TSRemapPostConfigReload|TSPluginInit|pluginDsoVersionTest|getPluginDebugObjectTest)$$'
# Build plugins for unit testing the plugin (re)load.
pkglib_LTLIBRARIES = \
diff --git a/proxy/http/remap/PluginDso.h b/proxy/http/remap/PluginDso.h
index 4554c6b..23a84b5 100644
--- a/proxy/http/remap/PluginDso.h
+++ b/proxy/http/remap/PluginDso.h
@@ -33,6 +33,7 @@
#include <vector>
#include <ctime>
+#include "ts/apidefs.h"
#include "tscore/ts_file.h"
namespace fs = ts::file;
@@ -73,10 +74,11 @@ public:
using Linkage = ts::IntrusiveLinkage<self_type>;
using PluginList = ts::IntrusiveDList<PluginDso::Linkage>;
- /* Methods to be called when processing a list of plugins, to overloaded by the remap or the global plugins correspondingly */
- virtual void indicateReload() = 0;
- virtual bool init(std::string &error) = 0;
- virtual void done() = 0;
+ /* Methods to be called when processing a list of plugins, to be overloaded by the remap or the global plugins correspondingly */
+ virtual void indicatePreReload() = 0;
+ virtual void indicatePostReload(TSReturnCode reloadStatus) = 0;
+ virtual bool init(std::string &error) = 0;
+ virtual void done() = 0;
void acquire();
void release();
diff --git a/proxy/http/remap/PluginFactory.cc b/proxy/http/remap/PluginFactory.cc
index c6b1c8a..8b045cc 100644
--- a/proxy/http/remap/PluginFactory.cc
+++ b/proxy/http/remap/PluginFactory.cc
@@ -35,28 +35,34 @@
RemapPluginInst::RemapPluginInst(RemapPluginInfo &plugin) : _plugin(plugin)
{
_plugin.acquire();
- _plugin.incInstanceCount();
}
RemapPluginInst::~RemapPluginInst()
{
- _plugin.decInstanceCount();
_plugin.release();
}
-bool
-RemapPluginInst::init(int argc, char **argv, std::string &error)
+RemapPluginInst *
+RemapPluginInst::init(RemapPluginInfo *plugin, int argc, char **argv, std::string &error)
{
- bool result = false;
- result = _plugin.initInstance(argc, argv, &_instance, error);
-
- return result;
+ RemapPluginInst *inst = new RemapPluginInst(*plugin);
+ if (plugin->initInstance(argc, argv, &(inst->_instance), error)) {
+ plugin->incInstanceCount();
+ return inst;
+ }
+ delete inst;
+ return nullptr;
}
void
RemapPluginInst::done()
{
+ _plugin.decInstanceCount();
_plugin.doneInstance(_instance);
+
+ if (0 == _plugin.instanceCount()) {
+ _plugin.done();
+ }
}
TSRemapStatus
@@ -163,9 +169,10 @@ PluginFactory::getRemapPlugin(const fs::path &configPath, int argc, char **argv,
_list.append(plugin);
if (plugin->init(error)) {
- inst = new RemapPluginInst(*plugin);
- inst->init(argc, argv, error);
- _instList.append(inst);
+ inst = RemapPluginInst::init(plugin, argc, argv, error);
+ if (nullptr != inst) {
+ _instList.append(inst);
+ }
}
if (_preventiveCleaning) {
@@ -177,9 +184,10 @@ PluginFactory::getRemapPlugin(const fs::path &configPath, int argc, char **argv,
}
} else {
Debug(_tag, "plugin '%s' has already been loaded", configPath.c_str());
- inst = new RemapPluginInst(*plugin);
- inst->init(argc, argv, error);
- _instList.append(inst);
+ inst = RemapPluginInst::init(plugin, argc, argv, error);
+ if (nullptr != inst) {
+ _instList.append(inst);
+ }
}
return inst;
@@ -236,25 +244,44 @@ PluginFactory::findByEffectivePath(const fs::path &path)
}
/**
- * @brief Tell all plugins (that so wish) that remap.config is being reloaded
+ * @brief Tell all plugins instantiated by this factory that the configuration
+ * they are using is no longer the active one.
*
* This method would be useful only in case configs are reloaded independently from
* factory/plugins instantiation and initialization.
*/
void
-PluginFactory::indicateReload()
+PluginFactory::deactivate()
{
- Debug(_tag, "indicated config reload to factory '%s'", getUuid());
+ Debug(_tag, "deactivate configuration used by factory '%s'", getUuid());
_instList.apply([](RemapPluginInst &pluginInst) -> void { pluginInst.done(); });
+}
- _list.apply([](PluginDso &plugin) -> void {
- if (1 == plugin.instanceCount()) {
- plugin.done();
- } else {
- plugin.indicateReload();
- }
- });
+/**
+ * @brief Tell all plugins (that so wish) that remap.config is going to be reloaded
+ */
+void
+PluginFactory::indicatePreReload()
+{
+ Debug(_tag, "indicated config is going to be reloaded by factory '%s' to %zu plugin%s", getUuid(), _list.count(),
+ _list.count() != 1 ? "s" : "");
+
+ _list.apply([](PluginDso &plugin) -> void { plugin.indicatePreReload(); });
+}
+
+/**
+ * @brief Tell all plugins (that so wish) that remap.config is done reloading
+ */
+void
+PluginFactory::indicatePostReload(TSReturnCode reloadStatus)
+{
+ Debug(_tag, "indicated config is done reloading by factory '%s' to %zu plugin%s", getUuid(), _list.count(),
+ _list.count() != 1 ? "s" : "");
+
+ for (auto it = _list.begin(); _list.end() != it; it++) {
+ it->indicatePostReload(reloadStatus);
+ }
}
void
diff --git a/proxy/http/remap/PluginFactory.h b/proxy/http/remap/PluginFactory.h
index 1cb0661..db722bd 100644
--- a/proxy/http/remap/PluginFactory.h
+++ b/proxy/http/remap/PluginFactory.h
@@ -47,7 +47,7 @@ public:
~RemapPluginInst();
/* Used by the PluginFactory */
- bool init(int argc, char **argv, std::string &error);
+ static RemapPluginInst *init(RemapPluginInfo *plugin, int argc, char **argv, std::string &error);
void done();
/* Used by the traffic server core while processing requests */
@@ -100,7 +100,9 @@ public:
virtual const char *getUuid();
void clean(std::string &error);
- void indicateReload();
+ void deactivate();
+ void indicatePreReload();
+ void indicatePostReload(TSReturnCode reloadStatus);
protected:
PluginDso *findByEffectivePath(const fs::path &path);
diff --git a/proxy/http/remap/RemapConfig.cc b/proxy/http/remap/RemapConfig.cc
index e231c09..5774b18 100644
--- a/proxy/http/remap/RemapConfig.cc
+++ b/proxy/http/remap/RemapConfig.cc
@@ -1320,9 +1320,16 @@ remap_parse_config(const char *path, UrlRewrite *rewrite)
{
BUILD_TABLE_INFO bti;
- // If this happens to be a config reload, the list of loaded remap plugins is non-empty, and we
- // can signal all these plugins that a reload has begun.
- rewrite->pluginFactory.indicateReload();
+ /* If this happens to be a config reload, the list of loaded remap plugins is non-empty, and we
+ * can signal all these plugins that a reload has begun. */
+ rewrite->pluginFactory.indicatePreReload();
+
bti.rewrite = rewrite;
- return remap_parse_config_bti(path, &bti);
+ bool status = remap_parse_config_bti(path, &bti);
+
+ /* Now after we parsed the configuration and (re)loaded plugins and plugin instances
+ * accordingly notify all plugins that we are done */
+ rewrite->pluginFactory.indicatePostReload(status ? TS_SUCCESS : TS_ERROR);
+
+ return status;
}
diff --git a/proxy/http/remap/RemapPluginInfo.cc b/proxy/http/remap/RemapPluginInfo.cc
index 8a1c00e..a98c3ee 100644
--- a/proxy/http/remap/RemapPluginInfo.cc
+++ b/proxy/http/remap/RemapPluginInfo.cc
@@ -52,7 +52,9 @@ RemapPluginInfo::getFunctionSymbol(const char *symbol)
{
std::string error; /* ignore the error, return nullptr if symbol not defined */
void *address = nullptr;
- getSymbol(symbol, address, error);
+ if (getSymbol(symbol, address, error)) {
+ Debug(_tag, "plugin '%s' found symbol '%s'", _configPath.c_str(), symbol);
+ }
return reinterpret_cast<T *>(address);
}
@@ -81,13 +83,14 @@ RemapPluginInfo::load(std::string &error)
return false;
}
- init_cb = getFunctionSymbol<Init_F>(TSREMAP_FUNCNAME_INIT);
- config_reload_cb = getFunctionSymbol<Reload_F>(TSREMAP_FUNCNAME_CONFIG_RELOAD);
- done_cb = getFunctionSymbol<Done_F>(TSREMAP_FUNCNAME_DONE);
- new_instance_cb = getFunctionSymbol<New_Instance_F>(TSREMAP_FUNCNAME_NEW_INSTANCE);
- delete_instance_cb = getFunctionSymbol<Delete_Instance_F>(TSREMAP_FUNCNAME_DELETE_INSTANCE);
- do_remap_cb = getFunctionSymbol<Do_Remap_F>(TSREMAP_FUNCNAME_DO_REMAP);
- os_response_cb = getFunctionSymbol<OS_Response_F>(TSREMAP_FUNCNAME_OS_RESPONSE);
+ init_cb = getFunctionSymbol<Init_F>(TSREMAP_FUNCNAME_INIT);
+ pre_config_reload_cb = getFunctionSymbol<PreReload_F>(TSREMAP_FUNCNAME_PRE_CONFIG_RELOAD);
+ post_config_reload_cb = getFunctionSymbol<PostReload_F>(TSREMAP_FUNCNAME_POST_CONFIG_RELOAD);
+ done_cb = getFunctionSymbol<Done_F>(TSREMAP_FUNCNAME_DONE);
+ new_instance_cb = getFunctionSymbol<New_Instance_F>(TSREMAP_FUNCNAME_NEW_INSTANCE);
+ delete_instance_cb = getFunctionSymbol<Delete_Instance_F>(TSREMAP_FUNCNAME_DELETE_INSTANCE);
+ do_remap_cb = getFunctionSymbol<Do_Remap_F>(TSREMAP_FUNCNAME_DO_REMAP);
+ os_response_cb = getFunctionSymbol<OS_Response_F>(TSREMAP_FUNCNAME_OS_RESPONSE);
/* Validate if the callback TSREMAP functions are specified correctly in the plugin. */
bool valid = true;
@@ -243,12 +246,24 @@ RemapPluginInfo::osResponse(void *ih, TSHttpTxn rh, int os_response_type)
RemapPluginInfo::~RemapPluginInfo() {}
void
-RemapPluginInfo::indicateReload()
+RemapPluginInfo::indicatePreReload()
+{
+ setPluginContext();
+
+ if (pre_config_reload_cb) {
+ pre_config_reload_cb();
+ }
+
+ resetPluginContext();
+}
+
+void
+RemapPluginInfo::indicatePostReload(TSReturnCode reloadStatus)
{
setPluginContext();
- if (config_reload_cb) {
- config_reload_cb();
+ if (post_config_reload_cb) {
+ post_config_reload_cb(reloadStatus);
}
resetPluginContext();
diff --git a/proxy/http/remap/RemapPluginInfo.h b/proxy/http/remap/RemapPluginInfo.h
index cc5941d..731196a 100644
--- a/proxy/http/remap/RemapPluginInfo.h
+++ b/proxy/http/remap/RemapPluginInfo.h
@@ -36,13 +36,14 @@ class url_mapping;
extern thread_local PluginThreadContext *pluginThreadContext;
-static constexpr const char *const TSREMAP_FUNCNAME_INIT = "TSRemapInit";
-static constexpr const char *const TSREMAP_FUNCNAME_CONFIG_RELOAD = "TSRemapConfigReload";
-static constexpr const char *const TSREMAP_FUNCNAME_DONE = "TSRemapDone";
-static constexpr const char *const TSREMAP_FUNCNAME_NEW_INSTANCE = "TSRemapNewInstance";
-static constexpr const char *const TSREMAP_FUNCNAME_DELETE_INSTANCE = "TSRemapDeleteInstance";
-static constexpr const char *const TSREMAP_FUNCNAME_DO_REMAP = "TSRemapDoRemap";
-static constexpr const char *const TSREMAP_FUNCNAME_OS_RESPONSE = "TSRemapOSResponse";
+static constexpr const char *const TSREMAP_FUNCNAME_INIT = "TSRemapInit";
+static constexpr const char *const TSREMAP_FUNCNAME_PRE_CONFIG_RELOAD = "TSRemapPreConfigReload";
+static constexpr const char *const TSREMAP_FUNCNAME_POST_CONFIG_RELOAD = "TSRemapPostConfigReload";
+static constexpr const char *const TSREMAP_FUNCNAME_DONE = "TSRemapDone";
+static constexpr const char *const TSREMAP_FUNCNAME_NEW_INSTANCE = "TSRemapNewInstance";
+static constexpr const char *const TSREMAP_FUNCNAME_DELETE_INSTANCE = "TSRemapDeleteInstance";
+static constexpr const char *const TSREMAP_FUNCNAME_DO_REMAP = "TSRemapDoRemap";
+static constexpr const char *const TSREMAP_FUNCNAME_OS_RESPONSE = "TSRemapOSResponse";
/**
* Holds information for a remap plugin, remap specific callback entry points for plugin init/done and instance init/done, do_remap,
@@ -53,8 +54,10 @@ class RemapPluginInfo : public PluginDso
public:
/// Initialization function, called on library load.
using Init_F = TSReturnCode(TSRemapInterface *api_info, char *errbuf, int errbuf_size);
- /// Reload function, called to inform the plugin of a configuration reload.
- using Reload_F = void();
+ /// Reload function, called to inform the plugin that configuration is going to be reloaded.
+ using PreReload_F = void();
+ /// Reload function, called to inform the plugin that configuration is done reloading.
+ using PostReload_F = void(TSReturnCode);
/// Called when remapping for a transaction has finished.
using Done_F = void();
/// Create an rule instance.
@@ -68,7 +71,8 @@ public:
void *dl_handle = nullptr; /* "handle" for the dynamic library */
Init_F *init_cb = nullptr;
- Reload_F *config_reload_cb = nullptr;
+ PreReload_F *pre_config_reload_cb = nullptr;
+ PostReload_F *post_config_reload_cb = nullptr;
Done_F *done_cb = nullptr;
New_Instance_F *new_instance_cb = nullptr;
Delete_Instance_F *delete_instance_cb = nullptr;
@@ -94,7 +98,8 @@ public:
void osResponse(void *ih, TSHttpTxn rh, int os_response_type);
/* Used by traffic server core to indicate configuration reload */
- virtual void indicateReload();
+ virtual void indicatePreReload();
+ virtual void indicatePostReload(TSReturnCode reloadStatus);
protected:
/* Utility to be used only with unit testing */
diff --git a/proxy/http/remap/unit-tests/plugin_testing_calls.cc b/proxy/http/remap/unit-tests/plugin_testing_calls.cc
index 89c8df2..1d57da3 100644
--- a/proxy/http/remap/unit-tests/plugin_testing_calls.cc
+++ b/proxy/http/remap/unit-tests/plugin_testing_calls.cc
@@ -103,9 +103,16 @@ TSRemapOSResponse(void *ih, TSHttpTxn rh, int os_response_type)
}
void
-TSRemapConfigReload(void)
+TSRemapPreConfigReload(void)
{
- debugObject.reloadConfigCalled++;
+ debugObject.preReloadConfigCalled++;
+}
+
+void
+TSRemapPostConfigReload(TSReturnCode reloadStatus)
+{
+ debugObject.postReloadConfigCalled++;
+ debugObject.postReloadConfigSuccess = (TS_SUCCESS == reloadStatus);
}
/* The folowing functions are meant for unit testing */
diff --git a/proxy/http/remap/unit-tests/plugin_testing_common.h b/proxy/http/remap/unit-tests/plugin_testing_common.h
index 66a8dd6..3662d0c 100644
--- a/proxy/http/remap/unit-tests/plugin_testing_common.h
+++ b/proxy/http/remap/unit-tests/plugin_testing_common.h
@@ -51,17 +51,19 @@ public:
void
clear()
{
- contextInit = nullptr;
- contextInitInstance = nullptr;
- doRemapCalled = 0;
- initCalled = 0;
- doneCalled = 0;
- initInstanceCalled = 0;
- deleteInstanceCalled = 0;
- reloadConfigCalled = 0;
- ih = nullptr;
- argc = 0;
- argv = nullptr;
+ contextInit = nullptr;
+ contextInitInstance = nullptr;
+ doRemapCalled = 0;
+ initCalled = 0;
+ doneCalled = 0;
+ initInstanceCalled = 0;
+ deleteInstanceCalled = 0;
+ preReloadConfigCalled = 0;
+ postReloadConfigCalled = 0;
+ postReloadConfigSuccess = 0;
+ ih = nullptr;
+ argc = 0;
+ argv = nullptr;
}
/* Input fields used to set the test behavior of the plugin call-backs */
@@ -76,7 +78,9 @@ public:
int doneCalled = 0; /* mark if done was called */
int initInstanceCalled = 0; /* mark if instance init was called */
int deleteInstanceCalled = 0; /* mark if delete instance was called */
- int reloadConfigCalled = 0; /* mark if reload config was called */
+ int preReloadConfigCalled = 0; /* mark if pre-reload config was called */
+ int postReloadConfigCalled = 0; /* mark if post-reload config was called */
+ bool postReloadConfigSuccess = 0; /* mark if plugin reload status is passed correctly */
void *ih = nullptr; /* instance handler */
int argc = 0; /* number of plugin instance parameters received by the plugin */
char **argv = nullptr; /* plugin instance parameters received by the plugin */
diff --git a/proxy/http/remap/unit-tests/test_PluginDso.cc b/proxy/http/remap/unit-tests/test_PluginDso.cc
index 092261b..1635a65 100644
--- a/proxy/http/remap/unit-tests/test_PluginDso.cc
+++ b/proxy/http/remap/unit-tests/test_PluginDso.cc
@@ -69,7 +69,11 @@ public:
}
virtual void
- indicateReload()
+ indicatePreReload()
+ {
+ }
+ virtual void
+ indicatePostReload(TSReturnCode reloadStatus)
{
}
virtual bool
diff --git a/proxy/http/remap/unit-tests/test_PluginFactory.cc b/proxy/http/remap/unit-tests/test_PluginFactory.cc
index 9c2d819..1c75bbe 100644
--- a/proxy/http/remap/unit-tests/test_PluginFactory.cc
+++ b/proxy/http/remap/unit-tests/test_PluginFactory.cc
@@ -554,7 +554,7 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
GIVEN("simple configuration with 1 plugin and 1 factory")
{
- WHEN("indicating config reload")
+ WHEN("(1) signal pre-new-config-load, (2) signal post-new-config-load, (3) old-config deactivate")
{
/* Simulate configuration without plugins - an unused factory */
setupConfigPathTest(configName1, buildPath, uuid_t1, effectivePath1, runtimePath1, 1556825556);
@@ -566,17 +566,43 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
/* Prapare the debug object */
PluginDebugObject *debugObject = getDebugObject(plugin1->_plugin);
- debugObject->clear();
- THEN("expect 'done' methods to be called for plugin and the instance but not the 'reload config' methods")
+ THEN("expect pre-, post- and done/delete_instance to be called accordingly ")
{
- /* Simulate reloading the config */
- factory1->indicateReload();
-
- /* was "done" method called? */
- CHECK(1 == debugObject->doneCalled);
+ /* Signal before loading the config */
+ debugObject->clear();
+
+ factory1->indicatePreReload();
+ CHECK(0 == debugObject->deleteInstanceCalled);
+ CHECK(0 == debugObject->doneCalled);
+ CHECK(1 == debugObject->preReloadConfigCalled);
+
+ /* ... parse the new remap config ... */
+
+ /* Assume (re)load was done OK and test */
+ debugObject->clear();
+ factory1->indicatePostReload(TS_SUCCESS);
+ CHECK(0 == debugObject->deleteInstanceCalled);
+ CHECK(0 == debugObject->doneCalled);
+ CHECK(1 == debugObject->postReloadConfigCalled);
+ CHECK(true == debugObject->postReloadConfigSuccess);
+
+ /* Assume (re)load failed and test */
+ debugObject->clear();
+ factory1->indicatePostReload(TS_ERROR);
+ CHECK(0 == debugObject->deleteInstanceCalled);
+ CHECK(0 == debugObject->doneCalled);
+ CHECK(1 == debugObject->postReloadConfigCalled);
+ CHECK(false == debugObject->postReloadConfigSuccess);
+
+ /* ... swap the new and the old config ... */
+
+ /* Signal de-activation of the old config */
+ debugObject->clear();
+ factory1->deactivate();
CHECK(1 == debugObject->deleteInstanceCalled);
- CHECK(0 == debugObject->reloadConfigCalled);
+ CHECK(1 == debugObject->doneCalled);
+ CHECK(0 == debugObject->preReloadConfigCalled);
}
teardownConfigPathTest(factory1);
@@ -585,7 +611,7 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
GIVEN("configuration with 2 plugins loaded by 1 factory")
{
- WHEN("indicating config reload")
+ WHEN("(1) signal pre-new-config-load, (2) signal post-new-config-load, (3) old-config deactivate")
{
/* Simulate configuration without plugins - an unused factory */
setupConfigPathTest(configName1, buildPath, uuid_t1, effectivePath1, runtimePath1, 1556825556);
@@ -601,21 +627,60 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
/* Prapare the debug objects */
PluginDebugObject *debugObject1 = getDebugObject(plugin1->_plugin);
PluginDebugObject *debugObject2 = getDebugObject(plugin2->_plugin);
- debugObject1->clear();
- debugObject2->clear();
- THEN("expect 'done' methods to be called but not the 'reload config' methods")
+ THEN("expect pre-, post- and done/delete_instance to be called accordingly")
{
- /* Simulate reloading the config */
- factory1->indicateReload();
+ /* Signal before loading the config */
+ debugObject1->clear();
+ debugObject2->clear();
+ factory1->indicatePreReload();
+ CHECK(0 == debugObject1->deleteInstanceCalled);
+ CHECK(0 == debugObject1->doneCalled);
+ CHECK(1 == debugObject1->preReloadConfigCalled);
+ CHECK(0 == debugObject2->doneCalled);
+ CHECK(0 == debugObject2->deleteInstanceCalled);
+ CHECK(1 == debugObject2->preReloadConfigCalled);
- /* Was "done" method called? */
- CHECK(1 == debugObject1->doneCalled);
+ /* ... parse the new remap config ... */
+
+ /* Assume (re)load was done OK */
+ debugObject1->clear();
+ debugObject2->clear();
+ factory1->indicatePostReload(TS_SUCCESS);
+ CHECK(0 == debugObject1->deleteInstanceCalled);
+ CHECK(0 == debugObject1->doneCalled);
+ CHECK(1 == debugObject1->postReloadConfigCalled);
+ CHECK(true == debugObject1->postReloadConfigSuccess);
+ CHECK(0 == debugObject2->deleteInstanceCalled);
+ CHECK(0 == debugObject2->doneCalled);
+ CHECK(1 == debugObject2->postReloadConfigCalled);
+ CHECK(true == debugObject2->postReloadConfigSuccess);
+
+ /* Assume (re)load failed */
+ debugObject1->clear();
+ debugObject2->clear();
+ factory1->indicatePostReload(TS_ERROR);
+ CHECK(0 == debugObject1->deleteInstanceCalled);
+ CHECK(0 == debugObject1->doneCalled);
+ CHECK(1 == debugObject1->postReloadConfigCalled);
+ CHECK(false == debugObject1->postReloadConfigSuccess);
+ CHECK(0 == debugObject2->deleteInstanceCalled);
+ CHECK(0 == debugObject2->doneCalled);
+ CHECK(1 == debugObject2->postReloadConfigCalled);
+ CHECK(false == debugObject2->postReloadConfigSuccess);
+
+ /* ... swap the new and the old config ... */
+
+ /* Signal de-activation of the old config */
+ debugObject1->clear();
+ debugObject2->clear();
+ factory1->deactivate();
CHECK(1 == debugObject1->deleteInstanceCalled);
- CHECK(0 == debugObject1->reloadConfigCalled);
- CHECK(1 == debugObject2->doneCalled);
+ CHECK(1 == debugObject1->doneCalled);
+ CHECK(0 == debugObject1->preReloadConfigCalled);
CHECK(1 == debugObject2->deleteInstanceCalled);
- CHECK(0 == debugObject2->reloadConfigCalled);
+ CHECK(1 == debugObject2->doneCalled);
+ CHECK(0 == debugObject2->preReloadConfigCalled);
}
teardownConfigPathTest(factory1);
@@ -624,7 +689,7 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
GIVEN("configuration with 1 plugin loaded by 2 separate factories")
{
- WHEN("indicating config reload")
+ WHEN("indicating de-activation of the factories")
{
/* Simulate configuration without plugins - an unused factory */
setupConfigPathTest(configName1, buildPath, uuid_t1, effectivePath1, runtimePath1, 1556825556);
@@ -633,25 +698,25 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
RemapPluginInst *plugin1 = factory1->getRemapPlugin(configName1, 0, nullptr, error);
RemapPluginInst *plugin2 = factory2->getRemapPlugin(configName1, 0, nullptr, error);
- /* Prapare the debug objects */
+ /* Prepare the debug objects */
PluginDebugObject *debugObject1 = getDebugObject(plugin1->_plugin);
PluginDebugObject *debugObject2 = getDebugObject(plugin2->_plugin);
- THEN("expect instance 'done' to be always called, but plugin 'done' called only after destroying one factory")
+ THEN("expect instance 'done' to be always called, but plugin 'done' called only after destroying both factories")
{
debugObject2->clear();
- factory2->indicateReload();
+ factory2->deactivate();
CHECK(0 == debugObject2->doneCalled);
CHECK(1 == debugObject2->deleteInstanceCalled);
- CHECK(1 == debugObject2->reloadConfigCalled);
+ CHECK(0 == debugObject2->preReloadConfigCalled);
delete factory2;
debugObject1->clear();
- factory1->indicateReload();
+ factory1->deactivate();
CHECK(1 == debugObject1->doneCalled);
CHECK(1 == debugObject1->deleteInstanceCalled);
- CHECK(0 == debugObject1->reloadConfigCalled);
+ CHECK(0 == debugObject1->preReloadConfigCalled);
delete factory1;
}
diff --git a/proxy/http/remap/unit-tests/test_RemapPlugin.cc b/proxy/http/remap/unit-tests/test_RemapPlugin.cc
index 1b385cc..49be30f 100644
--- a/proxy/http/remap/unit-tests/test_RemapPlugin.cc
+++ b/proxy/http/remap/unit-tests/test_RemapPlugin.cc
@@ -426,9 +426,14 @@ SCENARIO("config reload", "[plugin][core]")
{
debugObject->clear();
- plugin->indicateReload();
+ plugin->indicatePreReload();
+ plugin->indicatePostReload(TS_SUCCESS);
- THEN("expect it to run") { CHECK(1 == debugObject->reloadConfigCalled); }
+ THEN("expect it to run")
+ {
+ CHECK(1 == debugObject->preReloadConfigCalled);
+ CHECK(1 == debugObject->postReloadConfigCalled);
+ }
cleanupSandBox(plugin);
}
}
[trafficserver] 01/03: Doc: Guide to remap plugin API.
Posted by zw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 28e1d6d47b4aab5635677a56e6926829345ae15c
Author: Alan M. Carroll <am...@apache.org>
AuthorDate: Fri Aug 16 18:55:48 2019 -0500
Doc: Guide to remap plugin API.
(cherry picked from commit 5cb4b316ad93fd4c78f44effc4c1dfbe4949543c)
---
doc/developer-guide/api/functions/TSRemap.en.rst | 16 +--
doc/developer-guide/api/functions/TSTypes.en.rst | 40 ++++++
doc/developer-guide/plugins/index.en.rst | 1 +
doc/developer-guide/plugins/remap-plugins.en.rst | 148 +++++++++++++++++++++++
4 files changed, 198 insertions(+), 7 deletions(-)
diff --git a/doc/developer-guide/api/functions/TSRemap.en.rst b/doc/developer-guide/api/functions/TSRemap.en.rst
index 38d06d8..ddd9917 100644
--- a/doc/developer-guide/api/functions/TSRemap.en.rst
+++ b/doc/developer-guide/api/functions/TSRemap.en.rst
@@ -29,11 +29,11 @@ Synopsis
`#include <ts/ts.h>`
`#include <ts/remap.h>`
-.. function:: TSReturnCode TSRemapInit(TSRemapInterface * api_info, char * errbuf, int errbuf_size)
+.. function:: TSReturnCode TSRemapInit(TSRemapInterface * api_info, char * errbuff, int errbuff_size)
.. function:: void TSRemapConfigReload(void)
.. function:: void TSRemapDone(void)
.. function:: TSRemapStatus TSRemapDoRemap(void * ih, TSHttpTxn rh, TSRemapRequestInfo * rri)
-.. function:: TSReturnCode TSRemapNewInstance(int argc, char * argv[], void ** ih, char * errbuf, int errbuf_size)
+.. function:: TSReturnCode TSRemapNewInstance(int argc, char * argv[], void ** ih, char * errbuff, int errbuff_size)
.. function:: void TSRemapDeleteInstance(void * )
.. function:: void TSRemapOSResponse(void * ih, TSHttpTxn rh, int os_response_type)
@@ -50,8 +50,8 @@ route the transaction through your plugin. Multiple remap plugins can be
specified for a single remap rule, resulting in a remap plugin chain
where each plugin is given an opportunity to examine the HTTP transaction.
-:func:`TSRemapInit` is a required entry point. This function will be called
-once when Traffic Server loads the plugin. If the optional :func:`TSRemapDone`
+:func:`TSRemapInit` is a required entry point. This function will be called once when Traffic Server
+loads the plugin. If the optional :func:`TSRemapDone`
entry point is available, Traffic Server will call then when unloading
the remap plugin.
@@ -65,15 +65,17 @@ any data or continuations associated with that instance.
entry point. In this function, the remap plugin may examine and modify
the HTTP transaction.
-:func:`TSRemapConfigReload` is called once for every remap plugin just before the
-remap configuration file (:file:`remap.config`) is reloaded. This is an optional
-entry point, which takes no arguments and has no return value.
+:func:`TSRemapConfigReload` is called once for every remap plugin immediately after a new
+configuration is successfully loaded and immediately before the new remap configuration becomes
+active. This is an optional entry point, which takes no arguments and has no return value.
Generally speaking, calls to these functions are mutually exclusive. The exception
is for functions which take an HTTP transaction as a parameter. Calls to these
transaction-specific functions for different transactions are not necessarily mutually exclusive
of each other.
+For further information, see :ref:`developer-plugins-remap`.
+
Types
=====
diff --git a/doc/developer-guide/api/functions/TSTypes.en.rst b/doc/developer-guide/api/functions/TSTypes.en.rst
index 9ffc318..20bed44 100644
--- a/doc/developer-guide/api/functions/TSTypes.en.rst
+++ b/doc/developer-guide/api/functions/TSTypes.en.rst
@@ -143,8 +143,48 @@ more widely. Those are described on this page.
.. type:: TSRemapInterface
+ Data passed to a remap plugin via :func:`TSRemapInit`.
+
+ .. member:: unsigned long size
+
+ The size of the structure in bytes, including this member.
+
+ .. member:: unsigned long tsremap_version
+
+ The API version of the C API. The lower 16 bits are the minor version, and the upper bits
+ the major version.
+
.. type:: TSRemapRequestInfo
+ Data passed to a remap plugin during the invocation of a remap rule.
+
+ .. member:: TSMBuffer requestBufp
+
+ The client request. All of the other :type:`TSMLoc` values use this as the base buffer.
+
+ .. member:: TSMLoc requestHdrp
+
+ The client request.
+
+ .. member:: TSMLoc mapFromUrl
+
+ The match URL in the remap rule.
+
+ .. member:: TSMLoc mapToUrl
+
+ The target URL in the remap rule.
+
+ .. member:: TSMLoc requestUrl
+
+ The current request URL. The remap rule and plugins listed earlier in the remap rule can modify this
+ from the client request URL. Remap plugins are expected to modify this value to perform the
+ remapping of the request. Note this is the same :code:`TSMLoc` as would be obtained by
+ calling :func:`TSHttpTxnClientReqGet`.
+
+ .. member:: int redirect
+
+ Flag for using the remapped URL as an explicit redirection. This can be set by the remap plugin.
+
.. type:: TSSslX509
This type represents the :code:`X509` object created from an SSL certificate.
diff --git a/doc/developer-guide/plugins/index.en.rst b/doc/developer-guide/plugins/index.en.rst
index 35ba0ff..4f52843 100644
--- a/doc/developer-guide/plugins/index.en.rst
+++ b/doc/developer-guide/plugins/index.en.rst
@@ -37,6 +37,7 @@ Plugin Development
io/index.en
http-headers/index.en
http-transformations/index.en
+ remap-plugins.en
new-protocol-plugins.en
plugin-interfaces.en
adding-statistics.en
diff --git a/doc/developer-guide/plugins/remap-plugins.en.rst b/doc/developer-guide/plugins/remap-plugins.en.rst
new file mode 100644
index 0000000..7b691c6
--- /dev/null
+++ b/doc/developer-guide/plugins/remap-plugins.en.rst
@@ -0,0 +1,148 @@
+.. Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ agreements. See the NOTICE file distributed with this work for additional information regarding
+ copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the License. You may obtain
+ a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software distributed under the License
+ is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ or implied. See the License for the specific language governing permissions and limitations
+ under the License.
+
+.. include:: ../../common.defs
+.. default-domain:: c
+.. _developer-plugins-remap:
+
+Remap Plugins
+*************
+
+Remap plugins are called during remap (URL rewriting). The particular plugins and the order is
+determined by the remap rule. The :file:`remap.config` file can contain explicit references to
+remap plugins in a rule and the presence of such a reference in a rule causes the plugin to be
+invoked when the rule is matched. For example, a rule such as
+
+.. code-block:: text
+
+ map http://example.one/ http://example.two/ @plugin=example.so @pparam=first_arg @pparm=second_arg
+
+will, if matched, cause the plugin "example.so" to be called with parameters "first_arg" and "second_arg".
+
+A key difference between global and remap plugins is reconfiguration and reloading. If
+:file:`remap.config` is reloaded, then all remap plugins are reconfigured based on the new version
+of the file. Global plugins need to handle their own configuration reloading, if any.
+
+In addition, as of |TS| 9.0, remap plugins can be reloaded during runtime. During a
+:file:`remap.config` reload, if the plugin image file has changed, a new one is loaded and used.
+
+All of the externally invoked functions must be declared as :code:`extern "C"` in order to be
+correctly located by the Traffic Server core. This is already done if :ts:git:`include/ts/remap.h`
+is included, otherwise it must be done explicitly.
+
+Initialization
+==============
+
+If any rule uses a plugin, the remap configuration loading will load the dynamic library and then
+call :func:`TSRemapInit`. The plugin must return :macro:`TS_SUCCESS` or the configuration loading
+will fail. If there is an error during the invocation of this function a C string style message
+should be placed in :arg:`errbuff`, taking note of the maximum size of the buffer passed in
+:arg:`errbuff_size`. The message is checked if the function returns a value other than
+:macro:`TS_SUCCESS`.
+
+This function should perform any plugin global initialization, such as setting up static data
+tables. It only be called immediately after the dynamic library is loaded from disk.
+
+Configuration
+=============
+
+For each plugin invocation in a remap rule, :func:`TSRemapNewInstance` is called.
+
+The parameters :arg:`argc`, :arg:`argv` specify an array of arguments to the invocation instance in
+the standard way. :arg:`argc` is the number of arguments present and :arg:`argv` is an array of
+pointers, each of which points to a plugin parameter. The number of valid elements is :arg:`argc`.
+Note these pointers are valid only for the duration of the function call. If any part of them need
+persistent storage, that must be provided by the plugin.
+
+:arg:`ih` is for invocation instance storage data. This initially points at a :code:`nullptr`. If
+that pointer is updated the new value will be preserved and passed back to the plugin in later
+callbacks. This enables it to serve to identify which particular rule was matched and provide
+context data. The standard use is to allocate a class instance, store rule relevant context data in
+that instance, and update :arg:`ih` to point at the instance. The most common data is that derived
+from the invocation arguments passed in :arg:`argc`, :arg:`argv`.
+
+:arg:`errbuff` and :arg:`errbuff_size` specify a writeable buffer used to report errors. Error
+messages must be C strings and must fit in the buffer, including the terminating null.
+
+In essence, :func:`TSRemapNewInstance` is called to create an invocation instance for the plugin to
+store rule local data. If the plugin is invoked multiples time on a rule, this will be called
+multiple times for the rule, once for each invocation. Only the value store in :arg:`ih` will be
+available when the rule is actually matched. In particular the plugin arguments will not be
+available.
+
+Calls to :func:`TSRemapNewInstance` are serialized.
+
+If there is an error then the callback should return :macro:`TS_ERROR` and fill in the
+:arg:`errbuff` with a C-string describing the error. Otherwise the function must return
+:macro:`TS_SUCCESS`.
+
+Runtime
+=======
+
+At runtime, if a remap rule is matched, the plugin is invoked by calling :func:`TSRemapDoRemap`.
+This function is responsible for performing the plugin operation for the transaction.
+
+:arg:`ih` is the same value set in :func:`TSRemapNewInstance` for the invocation instance. This is
+not examined or checked by the core. :arg:`rh` is the transaction for which the rule matched.
+:arg:`rri` is information about the rule and the transaction.
+
+The callback is required to return a :type:`TSRemapStatus` indicating whether it performed a remap.
+This is used for verifying a request was remapped if remapping is required. This can also be used
+to prevent further remapping, although this should be used with caution.
+
+Calls to :func:`TSRemapDoRemap` are not serialized, they can be concurrent, even for the same
+invocation instance. However, the callbacks for a single rule for a single transaction are
+serialized in the order the plugins are invoked in the rule.
+
+All calls to :func:`TSRemapNewInstance` for a given configuration will be called and completed
+before any calls to :func:`TSRemapDoRemap`.
+
+Cleanup
+=======
+
+When a new :file:`remap.config` is loaded successfully, the prior configuration is cleaned up. For
+each call to :func:`TSRemapNewInstance` a corresponding call to :func:`TSRemapDeleteInstance` is
+called. The only argument is the invocation instance handle, originally provided by the plugin to
+:func:`TSRemapNewInstance`. This is expected to suffice for the plugin to clean up any rule specific
+data.
+
+As part of the old configuration cleanup :func:`TSRemapConfigReload` is called on the plugins in the
+old configuration before any calls to :func:`TSRemapDeleteInstance`. This is an optional entry
+point.
+
+.. note::
+
+ This is called per *plugin*, not per invocation of the plugin in :file:`remap.config`, and only
+ called if the plugin was called at least once with :func:`TSRemapNewInstance` for that
+ configuration.
+
+.. note::
+
+ There is no explicit indication or connection between the call to :func:`TSRemapConfigReload` and
+ the "old" (existing) configuration. It is guaranteeed that :func:`TSRemapConfigReload` will be
+ called on all the plugins before any :func:`TSRemapDeleteInstance` and these calls will be
+ serial. Similarly, :func:`TSRemapConfigReload` will be called serially after all calls to
+ :func:`TSRemapNewInstance` for a given configuration.
+
+.. note::
+
+ The old configuration, if any, is still active during the call to :func:`TSRemapConfigReload` and
+ therefore calls to :func:`TSRemapDoRemap` may occur concurrently with that function.
+
+The intention of :func:`TSRemapConfigReload` is to provide for temporary data structures used only
+during configuration loading. These can be created as needed when an invocation instance is loaded
+and used in subsequent invocation instance loading, then cleaned up in :func:`TSRemapConfigReload`.
+
+If no rule uses a plugin, it may be unloaded. In that case :func:`TSRemapDone` is called. This is
+an optional entry point, a plugin is not required to provide it. It is called once per plugin, not
+per plugin invocation.
[trafficserver] 03/03: "Plugin (un)used" post reload notification
Posted by zw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 970a9a2fceb9a12d39c757909b234fbf9a87ce90
Author: Gancho Tenev <ga...@apache.org>
AuthorDate: Fri Sep 27 13:28:22 2019 -0700
"Plugin (un)used" post reload notification
Most of the plugins is assumed to use per-plugin-instance data-structures
when reloading their configs and only a few of them that wish to optimize
performance or deal with the complexities of using per-plugin DSO "global"
data-structures would use plugin configuration reload notifications like
`TSRemapPreConfigReload` and `TSRemapPostConfigReload`.
Instead of trying to foresee the needs or the expectations of each use-case,
a more "open-ended" and straight-forward design was chosen for the configuration
reload notifications. The notifications are broadcasted to all loaded plugins
at the moments before and after the reload attempt, regardless of whether
a plugin is part of the new configuration or not.
During the `TSRemapPostConfigReload` we already decided to notify the
plugin if the plugin reload was successful or not so the plugins can
recover adequately in case of configuration reload failure.
This change adds a signal to show if the particular plugin was part of
the new configuration. This will be beneficial for use-cases that expect
plugin reload notification not to be called in case they are not part of
the new configuration so they can ignore the notification.
This change also attempts to clarify related documentation and code
comments as well.
(cherry picked from commit 78c7c0c0bf2afa87a90da5fa948a55d8ba747dbd)
---
doc/developer-guide/api/functions/TSRemap.en.rst | 20 ++++-
doc/developer-guide/plugins/remap-plugins.en.rst | 32 +++++---
include/ts/remap.h | 12 ++-
proxy/http/remap/PluginDso.h | 9 ++-
proxy/http/remap/PluginFactory.cc | 20 ++++-
proxy/http/remap/PluginFactory.h | 2 +-
proxy/http/remap/RemapConfig.cc | 2 +-
proxy/http/remap/RemapPluginInfo.cc | 2 +-
proxy/http/remap/RemapPluginInfo.h | 4 +-
.../http/remap/unit-tests/plugin_testing_calls.cc | 4 +-
.../http/remap/unit-tests/plugin_testing_common.h | 52 ++++++-------
proxy/http/remap/unit-tests/test_PluginDso.cc | 2 +-
proxy/http/remap/unit-tests/test_PluginFactory.cc | 85 ++++++++++++++++++----
proxy/http/remap/unit-tests/test_RemapPlugin.cc | 37 +++++++++-
14 files changed, 215 insertions(+), 68 deletions(-)
diff --git a/doc/developer-guide/api/functions/TSRemap.en.rst b/doc/developer-guide/api/functions/TSRemap.en.rst
index bbfc220..0e8ad4e 100644
--- a/doc/developer-guide/api/functions/TSRemap.en.rst
+++ b/doc/developer-guide/api/functions/TSRemap.en.rst
@@ -72,8 +72,10 @@ invoked by current and all previous still used configurations. This is an option
:func:`TSRemapPostConfigReload` is called to indicate the end of the the new remap configuration
load. It is called on the newly and previously loaded plugins, invoked by the new, current and
-previous still used configurations. It also indicates if the configuration reload was successful
-by passing :macro:`TS_SUCCESS` or :macro:`TS_ERROR`. This is an optional entry point.
+previous still used configurations. It also indicates wheather the configuration reload was successful
+by passing :macro:`TSREMAP_CONFIG_RELOAD_FAILURE` in case of failure and to notify the plugins if they
+are going to be part of the new configuration by passing :macro:`TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED`
+or :macro:`TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_UNUSED`. This is an optional entry point.
Generally speaking, calls to these functions are mutually exclusive. The exception
is for functions which take an HTTP transaction as a parameter. Calls to these
@@ -111,6 +113,20 @@ Types
The remapping attempt in general failed and the transaction should fail with an
error return to the user agent.
+.. type:: TSRemapReloadStatus
+
+ .. macro:: TSREMAP_CONFIG_RELOAD_FAILURE
+
+ Notify the plugin that configuration parsing failed.
+
+ .. macro:: TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED
+
+ Configuration parsing succeeded and plugin was used by the new configuration.
+
+ .. macro:: TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_UNUSED
+
+ Configuration parsing succeeded but plugin was NOT used by the new configuration.
+
Return Values
=============
diff --git a/doc/developer-guide/plugins/remap-plugins.en.rst b/doc/developer-guide/plugins/remap-plugins.en.rst
index ead70b2..d436169 100644
--- a/doc/developer-guide/plugins/remap-plugins.en.rst
+++ b/doc/developer-guide/plugins/remap-plugins.en.rst
@@ -80,8 +80,9 @@ multiple times for the rule, once for each invocation. Only the value store in :
available when the rule is actually matched. In particular the plugin arguments will not be
available.
-Calls to :func:`TSRemapNewInstance` are serialized. All calls to :func:`TSRemapNewInstance`
-for a given configuration will be called and completed before any calls to :func:`TSRemapDoRemap`.
+Calls to :func:`TSRemapNewInstance` are guaranteed to be serialized. All calls to
+:func:`TSRemapNewInstance` for a given new configuration are guaranteed to be called and
+completed before any calls to :func:`TSRemapDoRemap`.
If there is an error then the callback should return :macro:`TS_ERROR` and fill in the
:arg:`errbuff` with a C-string describing the error. Otherwise the function must return
@@ -91,18 +92,30 @@ If there is an error then the callback should return :macro:`TS_ERROR` and fill
Configuration reload notifications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Most of the plugins is assumed to use per-plugin-instance data-structures when reloading their
+configs and only a few of them that wish to optimize performance or deal with the complexities
+of using a per-plugin DSO "global" data-structures would use pluging configuration reload
+notifications like :func:`TSRemapPreConfigReload` and :func:`TSRemapPostConfigReload`.
+
+Instead of trying to foresee the needs or the expectations of each use-case, a more "open-ended"
+and straight-forward design was chosen for the configuration reload notifications.
+The notifications are broadcasted to all loaded plugins at the moments before and after
+the reload attempt, regardless of whether a plugin is part of the new configuration or not.
+
:func:`TSRemapPreConfigReload` is called *before* the parsing of a new remap configuration starts
to notify plugins of the coming configuration reload. It is called on all already loaded plugins,
invoked by current and all previous still used configurations. This is an optional entry point.
:func:`TSRemapPostConfigReload` is called to indicate the end of the the new remap configuration
load. It is called on the newly and previously loaded plugins, invoked by the new, current and
-previous still used configurations. It also indicates if the configuration reload was successful
-by passing :macro:`TS_SUCCESS` or :macro:`TS_ERROR`. This is an optional entry point.
+previous still used configurations. It also indicates wheather the configuration reload was successful
+by passing :macro:`TSREMAP_CONFIG_RELOAD_FAILURE` in case of failure and to notify the plugins if they
+are going to be part of the new configuration by passing :macro:`TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED`
+or :macro:`TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_UNUSED`. This is an optional entry point.
These calls are called per *plugin*, not per invocation of the plugin in :file:`remap.config`
-and only will be called if the plugin was called at least once with :func:`TSRemapNewInstance`
-for any configuration and at least one configuration using it is still loaded.
+and only will be called if the plugin was instantianted by at least one configuration loaded
+after the traffic server started and at least one configuration using it is still loaded.
:func:`TSRemapPreConfigReload` will be called serially for all loaded plugins
before any call to :func:`TSRemapNewInstance` during parsing of the new configuration.
@@ -115,9 +128,10 @@ A plugin could use :func:`TSRemapPreConfigReload` as a signal to drop (or alloca
per plugin data structures. These structures can be created (or updated) as needed
when a plugin invocation instance is loaded (:func:`TSRemapNewInstance` is called).
Then it could be used in subsequent invocation instances loading. After the configuration
-reload is done :func:`TSRemapPostConfigReload` could be used to confirm
-the data structures update if :macro:`TS_SUCCESS` is passed or recover / clean-up
-after a failed reload attempt if :macro:`TS_ERROR` is passed.
+reload is done :func:`TSRemapPostConfigReload` could be used to confirm the data
+structures update if reload was successful, recover / clean-up after a failed
+reload attempt, or if so wishes to ignore the notification if plugin is not part
+of the new configuration..
Runtime
diff --git a/include/ts/remap.h b/include/ts/remap.h
index dd7be38..1e804b9 100644
--- a/include/ts/remap.h
+++ b/include/ts/remap.h
@@ -75,6 +75,16 @@ typedef enum {
TSREMAP_ERROR = -1 /* Some error, that should generate an error page */
} TSRemapStatus;
+/* Status code passed to the plugin by TSRemapPostConfigReload() signaling
+ * (1) if the configuration reload was successful and
+ * (2) if (1) is successful show if the plugin was part of the new configuration */
+typedef enum {
+ TSREMAP_CONFIG_RELOAD_FAILURE = 0, /* notify the plugin that configuration parsing failed */
+ TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED = 1, /* configuration parsing succeeded and plugin was used by the new configuration */
+ TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_UNUSED =
+ 2 /* configuration parsing succeeded but plugin was NOT used by the new configuration */
+} TSRemapReloadStatus;
+
/* ----------------------------------------------------------------------------------
These are the entry points a plugin can implement. Note that TSRemapInit() and
TSRemapDoRemap() are both required.
@@ -108,7 +118,7 @@ tsapi void TSRemapPreConfigReload(void);
TS_ERROR - (re)load failed.
Return: none
*/
-tsapi void TSRemapPostConfigReload(TSReturnCode reloadStatus);
+tsapi void TSRemapPostConfigReload(TSRemapReloadStatus reloadStatus);
/* Remap new request
Mandatory interface function.
diff --git a/proxy/http/remap/PluginDso.h b/proxy/http/remap/PluginDso.h
index 23a84b5..e542718 100644
--- a/proxy/http/remap/PluginDso.h
+++ b/proxy/http/remap/PluginDso.h
@@ -34,6 +34,7 @@
#include <ctime>
#include "ts/apidefs.h"
+#include "ts/remap.h"
#include "tscore/ts_file.h"
namespace fs = ts::file;
@@ -75,10 +76,10 @@ public:
using PluginList = ts::IntrusiveDList<PluginDso::Linkage>;
/* Methods to be called when processing a list of plugins, to be overloaded by the remap or the global plugins correspondingly */
- virtual void indicatePreReload() = 0;
- virtual void indicatePostReload(TSReturnCode reloadStatus) = 0;
- virtual bool init(std::string &error) = 0;
- virtual void done() = 0;
+ virtual void indicatePreReload() = 0;
+ virtual void indicatePostReload(TSRemapReloadStatus reloadStatus) = 0;
+ virtual bool init(std::string &error) = 0;
+ virtual void done() = 0;
void acquire();
void release();
diff --git a/proxy/http/remap/PluginFactory.cc b/proxy/http/remap/PluginFactory.cc
index 8b045cc..9491228 100644
--- a/proxy/http/remap/PluginFactory.cc
+++ b/proxy/http/remap/PluginFactory.cc
@@ -22,6 +22,8 @@
*/
+#include <unordered_map>
+
#include "RemapPluginInfo.h"
#include "PluginFactory.h"
#ifdef PLUGIN_DSO_TESTS
@@ -274,13 +276,25 @@ PluginFactory::indicatePreReload()
* @brief Tell all plugins (that so wish) that remap.config is done reloading
*/
void
-PluginFactory::indicatePostReload(TSReturnCode reloadStatus)
+PluginFactory::indicatePostReload(bool reloadSuccessful)
{
Debug(_tag, "indicated config is done reloading by factory '%s' to %zu plugin%s", getUuid(), _list.count(),
_list.count() != 1 ? "s" : "");
- for (auto it = _list.begin(); _list.end() != it; it++) {
- it->indicatePostReload(reloadStatus);
+ /* Find out which plugins (DSO) are actually instantiated by this factory */
+ std::unordered_map<PluginDso *, int> pluginUsed;
+ for (auto &inst : _instList) {
+ pluginUsed[&(inst._plugin)]++;
+ }
+
+ for (auto &plugin : _list) {
+ TSRemapReloadStatus status = TSREMAP_CONFIG_RELOAD_FAILURE;
+ if (reloadSuccessful) {
+ /* reload succeeded but was the plugin instantiated by this factory? */
+ status = (pluginUsed.end() == pluginUsed.find(&plugin) ? TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_UNUSED :
+ TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED);
+ }
+ plugin.indicatePostReload(status);
}
}
diff --git a/proxy/http/remap/PluginFactory.h b/proxy/http/remap/PluginFactory.h
index db722bd..5982db4 100644
--- a/proxy/http/remap/PluginFactory.h
+++ b/proxy/http/remap/PluginFactory.h
@@ -102,7 +102,7 @@ public:
void deactivate();
void indicatePreReload();
- void indicatePostReload(TSReturnCode reloadStatus);
+ void indicatePostReload(bool reloadSuccessful);
protected:
PluginDso *findByEffectivePath(const fs::path &path);
diff --git a/proxy/http/remap/RemapConfig.cc b/proxy/http/remap/RemapConfig.cc
index 5774b18..424f4bf 100644
--- a/proxy/http/remap/RemapConfig.cc
+++ b/proxy/http/remap/RemapConfig.cc
@@ -1329,7 +1329,7 @@ remap_parse_config(const char *path, UrlRewrite *rewrite)
/* Now after we parsed the configuration and (re)loaded plugins and plugin instances
* accordingly notify all plugins that we are done */
- rewrite->pluginFactory.indicatePostReload(status ? TS_SUCCESS : TS_ERROR);
+ rewrite->pluginFactory.indicatePostReload(status);
return status;
}
diff --git a/proxy/http/remap/RemapPluginInfo.cc b/proxy/http/remap/RemapPluginInfo.cc
index a98c3ee..8f8962b 100644
--- a/proxy/http/remap/RemapPluginInfo.cc
+++ b/proxy/http/remap/RemapPluginInfo.cc
@@ -258,7 +258,7 @@ RemapPluginInfo::indicatePreReload()
}
void
-RemapPluginInfo::indicatePostReload(TSReturnCode reloadStatus)
+RemapPluginInfo::indicatePostReload(TSRemapReloadStatus reloadStatus)
{
setPluginContext();
diff --git a/proxy/http/remap/RemapPluginInfo.h b/proxy/http/remap/RemapPluginInfo.h
index 731196a..6d06b45 100644
--- a/proxy/http/remap/RemapPluginInfo.h
+++ b/proxy/http/remap/RemapPluginInfo.h
@@ -57,7 +57,7 @@ public:
/// Reload function, called to inform the plugin that configuration is going to be reloaded.
using PreReload_F = void();
/// Reload function, called to inform the plugin that configuration is done reloading.
- using PostReload_F = void(TSReturnCode);
+ using PostReload_F = void(TSRemapReloadStatus);
/// Called when remapping for a transaction has finished.
using Done_F = void();
/// Create an rule instance.
@@ -99,7 +99,7 @@ public:
/* Used by traffic server core to indicate configuration reload */
virtual void indicatePreReload();
- virtual void indicatePostReload(TSReturnCode reloadStatus);
+ virtual void indicatePostReload(TSRemapReloadStatus reloadStatus);
protected:
/* Utility to be used only with unit testing */
diff --git a/proxy/http/remap/unit-tests/plugin_testing_calls.cc b/proxy/http/remap/unit-tests/plugin_testing_calls.cc
index 1d57da3..883b971 100644
--- a/proxy/http/remap/unit-tests/plugin_testing_calls.cc
+++ b/proxy/http/remap/unit-tests/plugin_testing_calls.cc
@@ -109,10 +109,10 @@ TSRemapPreConfigReload(void)
}
void
-TSRemapPostConfigReload(TSReturnCode reloadStatus)
+TSRemapPostConfigReload(TSRemapReloadStatus reloadStatus)
{
debugObject.postReloadConfigCalled++;
- debugObject.postReloadConfigSuccess = (TS_SUCCESS == reloadStatus);
+ debugObject.postReloadConfigStatus = reloadStatus;
}
/* The folowing functions are meant for unit testing */
diff --git a/proxy/http/remap/unit-tests/plugin_testing_common.h b/proxy/http/remap/unit-tests/plugin_testing_common.h
index 3662d0c..f96c420 100644
--- a/proxy/http/remap/unit-tests/plugin_testing_common.h
+++ b/proxy/http/remap/unit-tests/plugin_testing_common.h
@@ -51,19 +51,19 @@ public:
void
clear()
{
- contextInit = nullptr;
- contextInitInstance = nullptr;
- doRemapCalled = 0;
- initCalled = 0;
- doneCalled = 0;
- initInstanceCalled = 0;
- deleteInstanceCalled = 0;
- preReloadConfigCalled = 0;
- postReloadConfigCalled = 0;
- postReloadConfigSuccess = 0;
- ih = nullptr;
- argc = 0;
- argv = nullptr;
+ contextInit = nullptr;
+ contextInitInstance = nullptr;
+ doRemapCalled = 0;
+ initCalled = 0;
+ doneCalled = 0;
+ initInstanceCalled = 0;
+ deleteInstanceCalled = 0;
+ preReloadConfigCalled = 0;
+ postReloadConfigCalled = 0;
+ postReloadConfigStatus = TSREMAP_CONFIG_RELOAD_FAILURE;
+ ih = nullptr;
+ argc = 0;
+ argv = nullptr;
}
/* Input fields used to set the test behavior of the plugin call-backs */
@@ -71,19 +71,19 @@ public:
void *input_ih; /* the value to be returned by the plugin instance init function */
/* Output fields showing what happend during the test */
- const PluginThreadContext *contextInit = nullptr; /* plugin initialization context */
- const PluginThreadContext *contextInitInstance = nullptr; /* plugin instance initialization context */
- int doRemapCalled = 0; /* mark if remap was called */
- int initCalled = 0; /* mark if plugin init was called */
- int doneCalled = 0; /* mark if done was called */
- int initInstanceCalled = 0; /* mark if instance init was called */
- int deleteInstanceCalled = 0; /* mark if delete instance was called */
- int preReloadConfigCalled = 0; /* mark if pre-reload config was called */
- int postReloadConfigCalled = 0; /* mark if post-reload config was called */
- bool postReloadConfigSuccess = 0; /* mark if plugin reload status is passed correctly */
- void *ih = nullptr; /* instance handler */
- int argc = 0; /* number of plugin instance parameters received by the plugin */
- char **argv = nullptr; /* plugin instance parameters received by the plugin */
+ const PluginThreadContext *contextInit = nullptr; /* plugin initialization context */
+ const PluginThreadContext *contextInitInstance = nullptr; /* plugin instance initialization context */
+ int doRemapCalled = 0; /* mark if remap was called */
+ int initCalled = 0; /* mark if plugin init was called */
+ int doneCalled = 0; /* mark if done was called */
+ int initInstanceCalled = 0; /* mark if instance init was called */
+ int deleteInstanceCalled = 0; /* mark if delete instance was called */
+ int preReloadConfigCalled = 0; /* mark if pre-reload config was called */
+ int postReloadConfigCalled = 0; /* mark if post-reload config was called */
+ TSRemapReloadStatus postReloadConfigStatus = TSREMAP_CONFIG_RELOAD_FAILURE; /* mark if plugin reload status is passed correctly */
+ void *ih = nullptr; /* instance handler */
+ int argc = 0; /* number of plugin instance parameters received by the plugin */
+ char **argv = nullptr; /* plugin instance parameters received by the plugin */
};
#ifdef __cplusplus
diff --git a/proxy/http/remap/unit-tests/test_PluginDso.cc b/proxy/http/remap/unit-tests/test_PluginDso.cc
index 1635a65..2db5d1c 100644
--- a/proxy/http/remap/unit-tests/test_PluginDso.cc
+++ b/proxy/http/remap/unit-tests/test_PluginDso.cc
@@ -73,7 +73,7 @@ public:
{
}
virtual void
- indicatePostReload(TSReturnCode reloadStatus)
+ indicatePostReload(TSRemapReloadStatus reloadStatus)
{
}
virtual bool
diff --git a/proxy/http/remap/unit-tests/test_PluginFactory.cc b/proxy/http/remap/unit-tests/test_PluginFactory.cc
index 1c75bbe..1456f20 100644
--- a/proxy/http/remap/unit-tests/test_PluginFactory.cc
+++ b/proxy/http/remap/unit-tests/test_PluginFactory.cc
@@ -556,7 +556,7 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
{
WHEN("(1) signal pre-new-config-load, (2) signal post-new-config-load, (3) old-config deactivate")
{
- /* Simulate configuration without plugins - an unused factory */
+ /* Simulate configuration with 1 factory and 1 plugin */
setupConfigPathTest(configName1, buildPath, uuid_t1, effectivePath1, runtimePath1, 1556825556);
PluginFactoryUnitTest *factory1 = getFactory(uuid_t1);
RemapPluginInst *plugin1 = factory1->getRemapPlugin(configName1, 0, nullptr, error);
@@ -581,19 +581,19 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
/* Assume (re)load was done OK and test */
debugObject->clear();
- factory1->indicatePostReload(TS_SUCCESS);
+ factory1->indicatePostReload(/* reload succeeded */ true);
CHECK(0 == debugObject->deleteInstanceCalled);
CHECK(0 == debugObject->doneCalled);
CHECK(1 == debugObject->postReloadConfigCalled);
- CHECK(true == debugObject->postReloadConfigSuccess);
+ CHECK(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED == debugObject->postReloadConfigStatus);
/* Assume (re)load failed and test */
debugObject->clear();
- factory1->indicatePostReload(TS_ERROR);
+ factory1->indicatePostReload(/* reload succeeded */ false);
CHECK(0 == debugObject->deleteInstanceCalled);
CHECK(0 == debugObject->doneCalled);
CHECK(1 == debugObject->postReloadConfigCalled);
- CHECK(false == debugObject->postReloadConfigSuccess);
+ CHECK(TSREMAP_CONFIG_RELOAD_FAILURE == debugObject->postReloadConfigStatus);
/* ... swap the new and the old config ... */
@@ -613,7 +613,7 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
{
WHEN("(1) signal pre-new-config-load, (2) signal post-new-config-load, (3) old-config deactivate")
{
- /* Simulate configuration without plugins - an unused factory */
+ /* Simulate configuration with 1 factories and 2 plugin */
setupConfigPathTest(configName1, buildPath, uuid_t1, effectivePath1, runtimePath1, 1556825556);
setupConfigPathTest(configName2, buildPath, uuid_t1, effectivePath2, runtimePath2, 1556825556, /* append */ true);
PluginFactoryUnitTest *factory1 = getFactory(uuid_t1);
@@ -646,28 +646,28 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
/* Assume (re)load was done OK */
debugObject1->clear();
debugObject2->clear();
- factory1->indicatePostReload(TS_SUCCESS);
+ factory1->indicatePostReload(/* reload succeeded */ true);
CHECK(0 == debugObject1->deleteInstanceCalled);
CHECK(0 == debugObject1->doneCalled);
CHECK(1 == debugObject1->postReloadConfigCalled);
- CHECK(true == debugObject1->postReloadConfigSuccess);
+ CHECK(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED == debugObject1->postReloadConfigStatus);
CHECK(0 == debugObject2->deleteInstanceCalled);
CHECK(0 == debugObject2->doneCalled);
CHECK(1 == debugObject2->postReloadConfigCalled);
- CHECK(true == debugObject2->postReloadConfigSuccess);
+ CHECK(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED == debugObject2->postReloadConfigStatus);
/* Assume (re)load failed */
debugObject1->clear();
debugObject2->clear();
- factory1->indicatePostReload(TS_ERROR);
+ factory1->indicatePostReload(/* reload succeeded */ false);
CHECK(0 == debugObject1->deleteInstanceCalled);
CHECK(0 == debugObject1->doneCalled);
CHECK(1 == debugObject1->postReloadConfigCalled);
- CHECK(false == debugObject1->postReloadConfigSuccess);
+ CHECK(TSREMAP_CONFIG_RELOAD_FAILURE == debugObject1->postReloadConfigStatus);
CHECK(0 == debugObject2->deleteInstanceCalled);
CHECK(0 == debugObject2->doneCalled);
CHECK(1 == debugObject2->postReloadConfigCalled);
- CHECK(false == debugObject2->postReloadConfigSuccess);
+ CHECK(TSREMAP_CONFIG_RELOAD_FAILURE == debugObject2->postReloadConfigStatus);
/* ... swap the new and the old config ... */
@@ -691,7 +691,7 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
{
WHEN("indicating de-activation of the factories")
{
- /* Simulate configuration without plugins - an unused factory */
+ /* Simulate configuration with 2 factories and 1 plugin */
setupConfigPathTest(configName1, buildPath, uuid_t1, effectivePath1, runtimePath1, 1556825556);
PluginFactoryUnitTest *factory1 = getFactory(uuid_t1);
PluginFactoryUnitTest *factory2 = getFactory(uuid_t2);
@@ -724,4 +724,63 @@ SCENARIO("notifying plugins of config reload", "[plugin][core]")
clean();
}
}
+
+ GIVEN("configuration with 2 plugin loaded by 2 factories")
+ {
+ WHEN("2 plugins are loaded by the 1st factory and only one of them loaded by the 2nd factory")
+ {
+ /* Simulate configuration with 2 factories and 2 different plugins */
+ setupConfigPathTest(configName1, buildPath, uuid_t1, effectivePath1, runtimePath1, 1556825556, /* append */ false);
+ setupConfigPathTest(configName2, buildPath, uuid_t1, effectivePath2, runtimePath2, 1556825556, /* append */ true);
+ PluginFactoryUnitTest *factory1 = getFactory(uuid_t1);
+ PluginFactoryUnitTest *factory2 = getFactory(uuid_t2);
+
+ /* 2 plugins loaded by the 1st factory */
+ RemapPluginInst *pluginInst1 = factory1->getRemapPlugin(configName1, 0, nullptr, error);
+ RemapPluginInst *pluginInst2 = factory1->getRemapPlugin(configName2, 0, nullptr, error);
+
+ /* only 1 plugin loaded by the 2st factory */
+ RemapPluginInst *pluginInst3 = factory2->getRemapPlugin(configName1, 0, nullptr, error);
+
+ /* pluginInst1 and pluginInst3 should be using the same plugin DSO named configName1
+ * pluginInst2 should be using plugin DSO named configName 2*/
+ CHECK_FALSE(nullptr == pluginInst1);
+ CHECK_FALSE(nullptr == pluginInst2);
+ CHECK_FALSE(nullptr == pluginInst3);
+ CHECK(&pluginInst1->_plugin == &pluginInst3->_plugin);
+
+ /* Get test objects for the 2 plugins used by the 3 instances from the 2 factories */
+ PluginDebugObject *debugObject1 = getDebugObject(pluginInst1->_plugin);
+ PluginDebugObject *debugObject2 = getDebugObject(pluginInst2->_plugin);
+
+ THEN(
+ "expect the plugin that is not loaded by the second factory to receive 'plugin unused' notification from the 2nd factory")
+ {
+ /* Factory 1: reload was OK and both plugins were part of the configuration that used/instantiated that factory */
+ debugObject1->clear();
+ debugObject2->clear();
+
+ factory1->indicatePostReload(/* reload succeeded */ true);
+ CHECK(1 == debugObject1->postReloadConfigCalled);
+ CHECK(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED == debugObject1->postReloadConfigStatus);
+ CHECK(1 == debugObject2->postReloadConfigCalled);
+ CHECK(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED == debugObject2->postReloadConfigStatus);
+
+ /* Factory 2: (re)load was OK and only 1 plugin was part of the configuration that used/instantiated that factory */
+ debugObject1->clear();
+ debugObject2->clear();
+
+ factory2->indicatePostReload(/* reload succeeded */ true);
+ CHECK(1 == debugObject1->postReloadConfigCalled);
+ CHECK(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED == debugObject1->postReloadConfigStatus);
+ CHECK(1 == debugObject2->postReloadConfigCalled);
+ CHECK(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_UNUSED == debugObject2->postReloadConfigStatus);
+
+ delete factory1;
+ delete factory2;
+ }
+
+ clean();
+ }
+ }
}
diff --git a/proxy/http/remap/unit-tests/test_RemapPlugin.cc b/proxy/http/remap/unit-tests/test_RemapPlugin.cc
index 49be30f..0184ab2 100644
--- a/proxy/http/remap/unit-tests/test_RemapPlugin.cc
+++ b/proxy/http/remap/unit-tests/test_RemapPlugin.cc
@@ -422,17 +422,50 @@ SCENARIO("config reload", "[plugin][core]")
bool result = loadPlugin(plugin, error, debugObject);
CHECK(true == result);
- WHEN("'config reload' is called")
+ WHEN("'config reload' failed")
{
debugObject->clear();
plugin->indicatePreReload();
- plugin->indicatePostReload(TS_SUCCESS);
+ plugin->indicatePostReload(TSREMAP_CONFIG_RELOAD_FAILURE);
THEN("expect it to run")
{
CHECK(1 == debugObject->preReloadConfigCalled);
CHECK(1 == debugObject->postReloadConfigCalled);
+ CHECK(TSREMAP_CONFIG_RELOAD_FAILURE == debugObject->postReloadConfigStatus);
+ }
+ cleanupSandBox(plugin);
+ }
+
+ WHEN("'config reload' is successful and the plugin is part of the new configuration")
+ {
+ debugObject->clear();
+
+ plugin->indicatePreReload();
+ plugin->indicatePostReload(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED);
+
+ THEN("expect it to run")
+ {
+ CHECK(1 == debugObject->preReloadConfigCalled);
+ CHECK(1 == debugObject->postReloadConfigCalled);
+ CHECK(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_USED == debugObject->postReloadConfigStatus);
+ }
+ cleanupSandBox(plugin);
+ }
+
+ WHEN("'config reload' is successful and the plugin is part of the new configuration")
+ {
+ debugObject->clear();
+
+ plugin->indicatePreReload();
+ plugin->indicatePostReload(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_UNUSED);
+
+ THEN("expect it to run")
+ {
+ CHECK(1 == debugObject->preReloadConfigCalled);
+ CHECK(1 == debugObject->postReloadConfigCalled);
+ CHECK(TSREMAP_CONFIG_RELOAD_SUCCESS_PLUGIN_UNUSED == debugObject->postReloadConfigStatus);
}
cleanupSandBox(plugin);
}