Merge "Add CLI support for collectd plugins"
diff --git a/collectd/files/plugin/collectd_base.py b/collectd/files/plugin/collectd_base.py
index 393a585..7959e75 100644
--- a/collectd/files/plugin/collectd_base.py
+++ b/collectd/files/plugin/collectd_base.py
@@ -102,6 +102,7 @@
 
     def dispatch_check_metric(self, value, failure=None):
         """Send a check metric reporting whether or not the plugin succeeded
+
         """
         if self.disable_check_metric:
             return
@@ -268,6 +269,8 @@
                                    (self.__class__.__name__, do_collect_data))
             self.do_collect_data = do_collect_data
 
+    def shutdown_callback(self):
+        pass
 
 class CephBase(Base):
 
@@ -305,20 +308,22 @@
         self.interval = interval
         self._results = []
         self._reset_on_read = reset_on_read
+        self._stop_flag = threading.Event()
 
     def run(self):
         self.collectd.info('Starting thread {}'.format(self.name))
-        while True:
+        while self.should_run:
             try:
                 started_at = time.time()
 
                 self.results = self.polling_function()
                 tosleep = self.interval - (time.time() - started_at)
                 if tosleep > 0:
+                    self.collectd.debug('Sleeping for {}s'.format(tosleep))
                     time.sleep(tosleep)
                 else:
                     self.collectd.warning(
-                        'Polling took more than {}s for {}'.format(
+                        'Polling task lasted longer than {}s for {}'.format(
                             self.interval, self.name
                         )
                     )
@@ -341,3 +346,10 @@
             self._results.extend(value)
         else:
             self._results = value
+
+    def stop(self):
+        self._stop_flag.set()
+
+    @property
+    def should_run(self):
+        return not self._stop_flag.isSet()
diff --git a/collectd/files/plugin/collectd_contrail_apis.py b/collectd/files/plugin/collectd_contrail_apis.py
index ad2260e..792b92c 100644
--- a/collectd/files/plugin/collectd_contrail_apis.py
+++ b/collectd/files/plugin/collectd_contrail_apis.py
@@ -15,7 +15,10 @@
 # limitations under the License.
 #
 
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 import requests
 import xml.dom.minidom
 import xml
@@ -129,6 +132,10 @@
 def read_callback():
     plugin.conditional_read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_notification(notification_callback)
-collectd.register_read(read_callback, INTERVAL)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_notification(notification_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/collectd_elasticsearch_cluster.py b/collectd/files/plugin/collectd_elasticsearch_cluster.py
index 5db5a67..50de5ab 100644
--- a/collectd/files/plugin/collectd_elasticsearch_cluster.py
+++ b/collectd/files/plugin/collectd_elasticsearch_cluster.py
@@ -13,7 +13,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 
 import collectd_elasticsearch_base as base
 
@@ -66,5 +69,9 @@
 def read_callback():
     plugin.read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_read(read_callback)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_read(read_callback)
diff --git a/collectd/files/plugin/collectd_elasticsearch_node.py b/collectd/files/plugin/collectd_elasticsearch_node.py
index ef6bfb2..1ce23fa 100644
--- a/collectd/files/plugin/collectd_elasticsearch_node.py
+++ b/collectd/files/plugin/collectd_elasticsearch_node.py
@@ -13,7 +13,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 
 import collectd_elasticsearch_base as base
 
@@ -51,5 +54,9 @@
 def read_callback():
     plugin.read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_read(read_callback)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_read(read_callback)
diff --git a/collectd/files/plugin/collectd_fake.py b/collectd/files/plugin/collectd_fake.py
index 2f96747..318e830 100644
--- a/collectd/files/plugin/collectd_fake.py
+++ b/collectd/files/plugin/collectd_fake.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from collections import namedtuple
 import logging
 import os
 
@@ -20,7 +21,10 @@
 log_level = logging.INFO
 if os.getenv('COLLECTD_DEBUG', '') == '1':
     log_level = logging.DEBUG
-logging.basicConfig(level=log_level)
+logging.basicConfig(
+    level=log_level,
+    format='%(asctime)s [%(threadName)s] %(levelname)s: %(message)s'
+)
 
 
 class Values(object):
@@ -41,8 +45,8 @@
     def dispatch(self, type=None, values=None, plugin_instance=None,
                  type_instance=None, plugin=None, host=None, time=None,
                  meta=None, interval=None):
-        info("plugin={plugin} plugin_instance={plugin_instance} " \
-             "type={type} type_instance={type_instance} " \
+        info("dispatch: plugin={plugin} plugin_instance={plugin_instance} "
+             "type={type} type_instance={type_instance} "
              "values={values} meta={meta}".format(
                  plugin=plugin or self._plugin,
                  plugin_instance=plugin_instance or self._plugin_instance,
@@ -53,6 +57,18 @@
              ))
 
 
+def load_configuration(plugin):
+    collectd_vars = {
+        e: os.environ[e]
+        for e in os.environ.keys() if e.startswith('COLLECTD_')}
+    for varname, value in collectd_vars.iteritems():
+        debug("configuration: {}={}".format(varname, value))
+        setattr(plugin, varname[9:].lower(), value)
+
+    FakeConfig = namedtuple('FakeConfig', ['children'])
+    plugin.config_callback(FakeConfig(children=[]))
+
+
 def error(msg):
     logging.error(msg)
 
@@ -62,11 +78,11 @@
 
 
 def notice(msg):
-    logging.notice(msg)
+    logging.info(msg)
 
 
 def info(msg):
-    logging.error(msg)
+    logging.info(msg)
 
 
 def debug(msg):
diff --git a/collectd/files/plugin/collectd_glusterfs.py b/collectd/files/plugin/collectd_glusterfs.py
index 9b03e8f..75daf4b 100644
--- a/collectd/files/plugin/collectd_glusterfs.py
+++ b/collectd/files/plugin/collectd_glusterfs.py
@@ -13,7 +13,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 import re
 
 import collectd_base as base
@@ -228,7 +231,10 @@
 def read_callback():
     plugin.read_callback()
 
-
-collectd.register_init(init_callback)
-collectd.register_config(config_callback)
-collectd.register_read(read_callback)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_init(init_callback)
+    collectd.register_config(config_callback)
+    collectd.register_read(read_callback)
diff --git a/collectd/files/plugin/collectd_openstack.py b/collectd/files/plugin/collectd_openstack.py
index 2da8670..f0ecbfc 100644
--- a/collectd/files/plugin/collectd_openstack.py
+++ b/collectd/files/plugin/collectd_openstack.py
@@ -33,6 +33,10 @@
     pass
 
 
+class PluginConfigurationException(Exception):
+    pass
+
+
 class OSClient(object):
     """ Base class for querying the OpenStack API endpoints.
 
@@ -161,6 +165,10 @@
         # 200 nodes environments with 600 VMs. See #1554502 for details.
         self.timeout = 20
         self.max_retries = 2
+        self.username = None
+        self.password = None
+        self.tenant_name = None
+        self.keystone_url = None
         self.os_client = None
         self.extra_config = {}
         self._threads = {}
@@ -272,21 +280,30 @@
         super(CollectdPlugin, self).config_callback(config)
         for node in config.children:
             if node.key == 'Username':
-                username = node.values[0]
+                self.username = node.values[0]
             elif node.key == 'Password':
-                password = node.values[0]
+                self.password = node.values[0]
             elif node.key == 'Tenant':
-                tenant_name = node.values[0]
+                self.tenant_name = node.values[0]
             elif node.key == 'KeystoneUrl':
-                keystone_url = node.values[0]
+                self.keystone_url = node.values[0]
             elif node.key == 'PaginationLimit':
                 self.pagination_limit = int(node.values[0])
             elif node.key == 'PollingInterval':
                 self.polling_interval = int(node.values[0])
 
-        self.os_client = OSClient(username, password, tenant_name,
-                                  keystone_url, self.timeout, self.logger,
-                                  self.max_retries)
+        if self.username is None:
+            raise PluginConfigurationException('Username parameter is missing')
+        if self.password is None:
+            raise PluginConfigurationException('Password parameter is missing')
+        if self.tenant_name is None:
+            raise PluginConfigurationException('Tenant parameter is missing')
+        if self.keystone_url is None:
+            raise PluginConfigurationException('KeystoneUrl parameter is missing')
+
+        self.os_client = OSClient(self.username, self.password,
+                                  self.tenant_name, self.keystone_url,
+                                  self.timeout, self.logger, self.max_retries)
 
     def get_objects(self, project, object_name, api_version='',
                     params=None, detail=False, since=False):
@@ -405,3 +422,10 @@
                 # Ignore when count_func() doesn't return a number
                 pass
         return counts
+
+    def shutdown_callback(self):
+        for tid, t in self._threads.items():
+            if t.is_alive():
+                self.logger.info('Waiting for {} thread to finish'.format(tid))
+                t.stop()
+                t.join()
diff --git a/collectd/files/plugin/collectd_vrrp.py b/collectd/files/plugin/collectd_vrrp.py
index 6c10ae1..b6f06d0 100644
--- a/collectd/files/plugin/collectd_vrrp.py
+++ b/collectd/files/plugin/collectd_vrrp.py
@@ -13,7 +13,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 from pyroute2 import IPRoute
 import socket
 
@@ -82,5 +85,9 @@
 def read_callback():
     plugin.read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_read(read_callback)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_read(read_callback)
diff --git a/collectd/files/plugin/haproxy.py b/collectd/files/plugin/haproxy.py
index 2299d6e..bff43ae 100644
--- a/collectd/files/plugin/haproxy.py
+++ b/collectd/files/plugin/haproxy.py
@@ -29,7 +29,10 @@
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 import csv
 import itertools
 import socket
@@ -314,5 +317,9 @@
 def read_callback():
     plugin.read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_read(read_callback)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_read(read_callback)
diff --git a/collectd/files/plugin/http_check.py b/collectd/files/plugin/http_check.py
index 62dcbce..9009801 100644
--- a/collectd/files/plugin/http_check.py
+++ b/collectd/files/plugin/http_check.py
@@ -13,15 +13,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-try:
-    import collectd
-except ImportError:
+if __name__ == '__main__':
     import collectd_fake as collectd
-
-import requests
+else:
+    import collectd
 
 import collectd_base as base
-
+import requests
 
 NAME = 'http_check'
 
@@ -79,6 +77,18 @@
 plugin = HTTPCheckPlugin(collectd, disable_check_metric=True)
 
 
+def config_callback(conf):
+    plugin.config_callback(conf)
+
+
+def notification_callback(notification):
+    plugin.notification_callback(notification)
+
+
+def read_callback():
+    plugin.conditional_read_callback()
+
+
 if __name__ == '__main__':
     plugin.urls['google_ok'] = 'https://www.google.com'
     plugin.urls['google_fail'] = 'https://www.google.com/not_found'
@@ -86,17 +96,6 @@
     plugin.expected_codes['github_fail'] = 200
     plugin.read_callback()
 else:
-    def config_callback(conf):
-        plugin.config_callback(conf)
-
-
-    def notification_callback(notification):
-        plugin.notification_callback(notification)
-
-
-    def read_callback():
-        plugin.conditional_read_callback()
-
     collectd.register_config(config_callback)
     collectd.register_notification(notification_callback)
     collectd.register_read(read_callback, base.INTERVAL)
diff --git a/collectd/files/plugin/hypervisor_stats.py b/collectd/files/plugin/hypervisor_stats.py
index 3e8b8fa..84f735e 100644
--- a/collectd/files/plugin/hypervisor_stats.py
+++ b/collectd/files/plugin/hypervisor_stats.py
@@ -14,7 +14,10 @@
 # limitations under the License.
 #
 # Collectd plugin for getting hypervisor statistics from Nova
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 
 import collectd_openstack as openstack
 
@@ -153,6 +156,10 @@
 def read_callback():
     plugin.conditional_read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_notification(notification_callback)
-collectd.register_read(read_callback, INTERVAL)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_notification(notification_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/influxdb.py b/collectd/files/plugin/influxdb.py
index 4b7426b..6d48f05 100644
--- a/collectd/files/plugin/influxdb.py
+++ b/collectd/files/plugin/influxdb.py
@@ -13,7 +13,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 import requests
 
 import collectd_base as base
@@ -67,6 +70,8 @@
         self.session = requests.Session()
         self.address = "localhost"
         self.port = "8086"
+        self.username = None
+        self.password = None
         self.session.mount(
             'http://',
             requests.adapters.HTTPAdapter(max_retries=3)
@@ -77,18 +82,18 @@
 
         for node in conf.children:
             if node.key == 'Username':
-                username = node.values[0]
+                self.username = node.values[0]
             elif node.key == 'Password':
-                password = node.values[0]
+                self.password = node.values[0]
             elif node.key == 'Address':
                 self.address = node.values[0]
             elif node.key == 'Port':
                 self.port = node.values[0]
 
-        if username is None or password is None:
+        if self.username is None or self.password is None:
             self.logger.error("Username and Password parameters are required")
         else:
-            self.session.auth = (username, password)
+            self.session.auth = (self.username, self.password)
 
     def itermetrics(self):
 
@@ -136,5 +141,9 @@
 def read_callback():
     plugin.read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_read(read_callback)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_read(read_callback)
diff --git a/collectd/files/plugin/openstack_cinder.py b/collectd/files/plugin/openstack_cinder.py
index 38ebab4..96a92c6 100644
--- a/collectd/files/plugin/openstack_cinder.py
+++ b/collectd/files/plugin/openstack_cinder.py
@@ -14,7 +14,10 @@
 # limitations under the License.
 #
 # Collectd plugin for getting statistics from Cinder
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 
 import collectd_openstack as openstack
 
@@ -102,6 +105,15 @@
 def read_callback():
     plugin.conditional_read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_notification(notification_callback)
-collectd.register_read(read_callback, INTERVAL)
+if __name__ == '__main__':
+    import time
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+    collectd.info('Sleeping for {}s'.format(INTERVAL))
+    time.sleep(INTERVAL)
+    plugin.read_callback()
+    plugin.shutdown_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_notification(notification_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/openstack_cinder_services.py b/collectd/files/plugin/openstack_cinder_services.py
index 56d5ad7..b37dad2 100644
--- a/collectd/files/plugin/openstack_cinder_services.py
+++ b/collectd/files/plugin/openstack_cinder_services.py
@@ -14,7 +14,10 @@
 # limitations under the License.
 #
 # Collectd plugin for getting statistics from Cinder
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 from collections import Counter
 from collections import defaultdict
 import re
@@ -89,6 +92,10 @@
 def read_callback():
     plugin.conditional_read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_notification(notification_callback)
-collectd.register_read(read_callback, INTERVAL)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_notification(notification_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/openstack_glance.py b/collectd/files/plugin/openstack_glance.py
index 4886967..da9c469 100644
--- a/collectd/files/plugin/openstack_glance.py
+++ b/collectd/files/plugin/openstack_glance.py
@@ -14,7 +14,10 @@
 # limitations under the License.
 #
 # Collectd plugin for getting resource statistics from Glance
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 
 import collectd_openstack as openstack
 
@@ -97,6 +100,15 @@
 def read_callback():
     plugin.conditional_read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_notification(notification_callback)
-collectd.register_read(read_callback, INTERVAL)
+if __name__ == '__main__':
+    import time
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+    collectd.info('Sleeping for {}s'.format(INTERVAL))
+    time.sleep(INTERVAL)
+    plugin.read_callback()
+    plugin.shutdown_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_notification(notification_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/openstack_keystone.py b/collectd/files/plugin/openstack_keystone.py
index cbd4e4d..4ad4611 100644
--- a/collectd/files/plugin/openstack_keystone.py
+++ b/collectd/files/plugin/openstack_keystone.py
@@ -14,7 +14,10 @@
 # limitations under the License.
 #
 # Collectd plugin for getting statistics from Keystone
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 
 import collectd_openstack as openstack
 
@@ -95,6 +98,10 @@
 def read_callback():
     plugin.conditional_read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_notification(notification_callback)
-collectd.register_read(read_callback, INTERVAL)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_notification(notification_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/openstack_neutron.py b/collectd/files/plugin/openstack_neutron.py
index a9ccff0..f1b72af 100644
--- a/collectd/files/plugin/openstack_neutron.py
+++ b/collectd/files/plugin/openstack_neutron.py
@@ -14,7 +14,10 @@
 # limitations under the License.
 #
 # Collectd plugin for getting resource statistics from Neutron
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 
 import collectd_openstack as openstack
 
@@ -124,6 +127,15 @@
 def read_callback():
     plugin.conditional_read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_notification(notification_callback)
-collectd.register_read(read_callback, INTERVAL)
+if __name__ == '__main__':
+    import time
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+    collectd.info('Sleeping for {}s'.format(INTERVAL))
+    time.sleep(INTERVAL)
+    plugin.read_callback()
+    plugin.shutdown_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_notification(notification_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/openstack_neutron_agents.py b/collectd/files/plugin/openstack_neutron_agents.py
index 3ae5ed7..0f060a3 100644
--- a/collectd/files/plugin/openstack_neutron_agents.py
+++ b/collectd/files/plugin/openstack_neutron_agents.py
@@ -14,7 +14,10 @@
 # limitations under the License.
 #
 # Collectd plugin for getting resource statistics from Neutron
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 from collections import Counter
 from collections import defaultdict
 import re
@@ -92,6 +95,10 @@
 def read_callback():
     plugin.conditional_read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_notification(notification_callback)
-collectd.register_read(read_callback, INTERVAL)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_notification(notification_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/openstack_nova.py b/collectd/files/plugin/openstack_nova.py
index 084e7b1..ea2bd77 100644
--- a/collectd/files/plugin/openstack_nova.py
+++ b/collectd/files/plugin/openstack_nova.py
@@ -14,7 +14,10 @@
 # limitations under the License.
 #
 # Collectd plugin for getting statistics from Nova
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 
 import collectd_openstack as openstack
 from itertools import groupby
@@ -79,6 +82,15 @@
 def read_callback():
     plugin.conditional_read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_notification(notification_callback)
-collectd.register_read(read_callback, INTERVAL)
+if __name__ == '__main__':
+    import time
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+    collectd.info('Sleeping for {}s'.format(INTERVAL))
+    time.sleep(INTERVAL)
+    plugin.read_callback()
+    plugin.shutdown_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_notification(notification_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/openstack_nova_services.py b/collectd/files/plugin/openstack_nova_services.py
index c9f84eb..51b0df4 100644
--- a/collectd/files/plugin/openstack_nova_services.py
+++ b/collectd/files/plugin/openstack_nova_services.py
@@ -14,7 +14,11 @@
 # limitations under the License.
 #
 # Collectd plugin for getting statistics from Nova
-import collectd
+
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 from collections import Counter
 from collections import defaultdict
 import re
@@ -40,7 +44,6 @@
         self.interval = INTERVAL
 
     def itermetrics(self):
-
         # Get information of the state per service
         # State can be: 'up', 'down' or 'disabled'
         aggregated_workers = defaultdict(Counter)
@@ -94,6 +97,10 @@
 def read_callback():
     plugin.conditional_read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_notification(notification_callback)
-collectd.register_read(read_callback, INTERVAL)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_notification(notification_callback)
+    collectd.register_read(read_callback, INTERVAL)
diff --git a/collectd/files/plugin/rabbitmq_info.py b/collectd/files/plugin/rabbitmq_info.py
index d78b6cb..3504ae4 100644
--- a/collectd/files/plugin/rabbitmq_info.py
+++ b/collectd/files/plugin/rabbitmq_info.py
@@ -16,7 +16,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import collectd
+if __name__ == '__main__':
+    import collectd_fake as collectd
+else:
+    import collectd
 
 import collectd_base as base
 import requests
@@ -129,5 +132,9 @@
 def read_callback():
     plugin.read_callback()
 
-collectd.register_config(config_callback)
-collectd.register_read(read_callback)
+if __name__ == '__main__':
+    collectd.load_configuration(plugin)
+    plugin.read_callback()
+else:
+    collectd.register_config(config_callback)
+    collectd.register_read(read_callback)