524 lines
23 KiB
Python
Executable File
524 lines
23 KiB
Python
Executable File
#!/usr/bin/python
|
|
# -*- encoding: utf-8; py-indent-offset: 4 -*-
|
|
# +------------------------------------------------------------------+
|
|
# | ____ _ _ __ __ _ __ |
|
|
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
|
|
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
|
|
# | | |___| | | | __/ (__| < | | | | . \ |
|
|
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
|
|
# | |
|
|
# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
|
|
# +------------------------------------------------------------------+
|
|
#
|
|
# This file is part of Check_MK.
|
|
# The official homepage is at http://mathias-kettner.de/check_mk.
|
|
#
|
|
# check_mk is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation in version 2. check_mk is distributed
|
|
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
|
|
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
|
|
# tails. You should have received a copy of the GNU General Public
|
|
# License along with GNU Make; see the file COPYING. If not, write
|
|
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
# Boston, MA 02110-1301 USA.
|
|
|
|
import urllib2, sys, os, socket, base64, ssl
|
|
from httplib import HTTPConnection, HTTPSConnection
|
|
|
|
try:
|
|
from simplejson import json
|
|
except ImportError:
|
|
try:
|
|
import json
|
|
except ImportError:
|
|
sys.stdout.write("<<<jolokia_info>>>\n")
|
|
sys.stdout.write("Error: Missing JSON library for Agent Plugin mk_jolokia\n")
|
|
exit()
|
|
|
|
opt_verbose = '--verbose' in sys.argv
|
|
opt_debug = '--debug' in sys.argv
|
|
|
|
class PreemptiveBasicAuthHandler(urllib2.HTTPBasicAuthHandler):
|
|
"""
|
|
sends basic authentication with the first request,
|
|
before the server even asks for it
|
|
"""
|
|
|
|
def http_request(self, req):
|
|
url = req.get_full_url()
|
|
realm = None
|
|
user, pw = self.passwd.find_user_password(realm, url)
|
|
if pw:
|
|
raw = "%s:%s" % (user, pw)
|
|
auth = 'Basic %s' % base64.b64encode(raw).strip()
|
|
req.add_unredirected_header(self.auth_header, auth)
|
|
return req
|
|
|
|
https_request = http_request
|
|
|
|
class HTTPSValidatingConnection(HTTPSConnection):
|
|
def __init__(self, host, ca_file, key_file, cert_file):
|
|
HTTPSConnection.__init__(self, host, key_file=key_file, cert_file=cert_file)
|
|
self.__ca_file = ca_file
|
|
self.__key_file = key_file
|
|
self.__cert_file = cert_file
|
|
|
|
def connect(self):
|
|
HTTPConnection.connect(self)
|
|
if self.__ca_file:
|
|
self.sock = ssl.wrap_socket(self.sock, keyfile=self.key_file, certfile=self.cert_file,
|
|
ca_certs=self.__ca_file, cert_reqs=ssl.CERT_REQUIRED)
|
|
else:
|
|
self.sock = ssl.wrap_socket(self.sock, keyfile=self.key_file, certfile=self.cert_file,
|
|
ca_certs=self.__ca_file, cert_reqs=ssl.CERT_NONE)
|
|
|
|
|
|
class HTTPSAuthHandler(urllib2.HTTPSHandler):
|
|
def __init__(self, ca_file, key, cert):
|
|
urllib2.HTTPSHandler.__init__(self)
|
|
self.__ca_file = ca_file
|
|
self.__key = key
|
|
self.__cert = cert
|
|
|
|
def https_open(self, req):
|
|
# do_open expects a class as the first parameter but getConnection will act
|
|
# as a facotry function
|
|
return self.do_open(self.getConnection, req)
|
|
|
|
def getConnection(self, host, timeout):
|
|
return HTTPSValidatingConnection(host, ca_file=self.__ca_file,
|
|
key_file=self.__key, cert_file=self.__cert)
|
|
|
|
def fetch_url_get(base_url, path, function):
|
|
if path:
|
|
url = "%s/%s/%s" % (base_url, function, path)
|
|
else:
|
|
url = base_url + "/"
|
|
|
|
if opt_verbose:
|
|
sys.stderr.write("DEBUG: Fetching: %s\n" % url)
|
|
try:
|
|
json_data = urllib2.urlopen(url).read()
|
|
if opt_verbose:
|
|
sys.stderr.write("DEBUG: Result: %s\n\n" % json_data)
|
|
except Exception, e:
|
|
if opt_debug:
|
|
raise
|
|
sys.stderr.write("ERROR: %s\n" % e)
|
|
return []
|
|
return json_data
|
|
|
|
|
|
def fetch_url_post(base_url, path, service_url, service_user, service_password, function):
|
|
segments = path.split("/")
|
|
|
|
data = {
|
|
"type": function.upper(),
|
|
"mbean": segments[0],
|
|
"attribute": segments[1],
|
|
"target": {
|
|
"url": service_url,
|
|
},
|
|
}
|
|
if len(segments) > 2:
|
|
data["path"] = segments[2]
|
|
|
|
if service_user:
|
|
data["target"]["user"] = service_user
|
|
data["target"]["password"] = service_password
|
|
|
|
if opt_verbose:
|
|
sys.stderr.write("DEBUG: Fetching: %s\n" % base_url)
|
|
try:
|
|
json_data = urllib2.urlopen(base_url, data=json.dumps(data)).read()
|
|
if opt_verbose:
|
|
sys.stderr.write("DEBUG: Result: %s\n\n" % json_data)
|
|
except Exception, e:
|
|
if opt_debug:
|
|
raise
|
|
sys.stderr.write("ERROR: %s\n" % e)
|
|
return []
|
|
return json_data
|
|
|
|
def fetch_var(protocol, server, port, path, suburi, itemspec, service_url, service_user,
|
|
service_password, function="read"):
|
|
base_url = "%s://%s:%d/%s" % (protocol, server, port, suburi)
|
|
|
|
if service_url is not None:
|
|
json_data = fetch_url_post(base_url, path,
|
|
service_url, service_user, service_password, function)
|
|
else:
|
|
json_data = fetch_url_get(base_url, path, function)
|
|
|
|
try:
|
|
obj = json.loads(json_data)
|
|
except Exception, e:
|
|
sys.stderr.write('ERROR: Invalid json code (%s)\n' % e)
|
|
sys.stderr.write(' Response %s\n' % json_data)
|
|
return []
|
|
|
|
if obj.get('status', 200) != 200:
|
|
sys.stderr.write('ERROR: Invalid response when fetching url %s\n' % base_url)
|
|
sys.stderr.write(' Response: %s\n' % json_data)
|
|
return []
|
|
|
|
# Only take the value of the object. If the value is an object
|
|
# take the first items first value.
|
|
# {'Catalina:host=localhost,path=\\/test,type=Manager': {'activeSessions': 0}}
|
|
if 'value' not in obj:
|
|
if opt_verbose:
|
|
sys.stderr.write("ERROR: not found: %s\n" % path)
|
|
return []
|
|
val = obj.get('value', None)
|
|
return make_item_list((), val, itemspec)
|
|
|
|
# convert single values into lists of items in
|
|
# case value is a 1-levelled or 2-levelled dict
|
|
def make_item_list(path, value, itemspec):
|
|
if type(value) != dict:
|
|
if type(value) == str:
|
|
value = value.replace(r'\/', '/')
|
|
return [(path, value)]
|
|
else:
|
|
result = []
|
|
for key, subvalue in value.items():
|
|
# Handle filtering via itemspec
|
|
miss = False
|
|
while itemspec and '=' in itemspec[0]:
|
|
if itemspec[0] not in key:
|
|
miss = True
|
|
break
|
|
itemspec = itemspec[1:]
|
|
if miss:
|
|
continue
|
|
item = extract_item(key, itemspec)
|
|
if not item:
|
|
item = (key,)
|
|
result += make_item_list(path + item, subvalue, [])
|
|
return result
|
|
|
|
# Example:
|
|
# key = 'Catalina:host=localhost,path=\\/,type=Manager'
|
|
# itemsepc = [ "path" ]
|
|
# --> "/"
|
|
|
|
def extract_item(key, itemspec):
|
|
path = key.split(":", 1)[-1]
|
|
components = path.split(",")
|
|
item = ()
|
|
comp_dict = {}
|
|
for comp in components:
|
|
parts = comp.split("=")
|
|
if len(parts) == 2:
|
|
left, right = parts
|
|
comp_dict[left] = right
|
|
for pathkey in itemspec:
|
|
if pathkey in comp_dict:
|
|
right = comp_dict[pathkey]
|
|
right = right.replace(r'\/', '/')
|
|
if '/' in right:
|
|
right = '/' + right.split('/')[-1]
|
|
item = item + (right,)
|
|
return item
|
|
|
|
|
|
def fetch_metric(inst, path, title, itemspec, inst_add=None):
|
|
values = fetch_var(inst["protocol"], inst["server"], inst["port"], path,
|
|
inst["suburi"], itemspec,
|
|
inst["service_url"], inst["service_user"], inst["service_password"])
|
|
|
|
for subinstance, value in values:
|
|
if not subinstance and not title:
|
|
sys.stdout.write("INTERNAL ERROR: %s\n" % value)
|
|
continue
|
|
|
|
if "threadStatus" in subinstance or "threadParam" in subinstance:
|
|
continue
|
|
|
|
if len(subinstance) > 1:
|
|
item = ",".join((inst["instance"],) + subinstance[:-1])
|
|
elif inst_add is not None:
|
|
item = inst["instance"] + "," + inst_add
|
|
else:
|
|
item = inst["instance"]
|
|
if title:
|
|
if subinstance:
|
|
tit = title + "." + subinstance[-1]
|
|
else:
|
|
tit = title
|
|
else:
|
|
tit = subinstance[-1]
|
|
|
|
yield (item.replace(" ", "_"), tit, value)
|
|
|
|
|
|
def query_instance(inst):
|
|
# Prepare user/password authentication via HTTP Auth
|
|
password_mngr = urllib2.HTTPPasswordMgrWithDefaultRealm()
|
|
if inst.get("password"):
|
|
password_mngr.add_password(None, "%s://%s:%d/" %
|
|
(inst["protocol"], inst["server"], inst["port"]), inst["user"], inst["password"])
|
|
|
|
handlers = []
|
|
if inst["protocol"] == "https":
|
|
if inst["mode"] == 'https' and (inst["client_key"] is None or
|
|
inst["client_cert"] is None):
|
|
sys.stdout.write('<<<jolokia_info>>>\n')
|
|
sys.stderr.write("ERROR: https set up as authentication method but certificate "
|
|
"wasn't provided\n")
|
|
return
|
|
handlers.append(HTTPSAuthHandler(inst["cert_path"],
|
|
inst["client_key"], inst["client_cert"]))
|
|
if inst["mode"] == 'digest':
|
|
handlers.append(urllib2.HTTPDigestAuthHandler(password_mngr))
|
|
elif inst["mode"] == "basic_preemptive":
|
|
handlers.append(PreemptiveBasicAuthHandler(password_mngr))
|
|
elif inst["mode"] == "basic" and inst["protocol"] != "https":
|
|
handlers.append(urllib2.HTTPBasicAuthHandler(password_mngr))
|
|
|
|
if handlers:
|
|
opener = urllib2.build_opener(*handlers)
|
|
urllib2.install_opener(opener)
|
|
|
|
# Determine type of server
|
|
server_info = fetch_var(inst["protocol"], inst["server"], inst["port"], "", inst["suburi"],
|
|
"", None, None, None)
|
|
|
|
sys.stdout.write('<<<jolokia_info>>>\n')
|
|
if server_info:
|
|
d = dict(server_info)
|
|
version = d.get(('info', 'version'), "unknown")
|
|
product = d.get(('info', 'product'), "unknown")
|
|
if inst.get("product"):
|
|
product = inst["product"]
|
|
agentversion = d.get(('agent',), "unknown")
|
|
sys.stdout.write("%s %s %s %s\n" % (inst["instance"], product, version, agentversion))
|
|
else:
|
|
sys.stdout.write("%s ERROR\n" % (inst["instance"],))
|
|
sys.stdout.write('<<<jolokia_metrics>>>\n')
|
|
sys.stdout.write("%s ERROR\n" % (inst["instance"],))
|
|
return
|
|
|
|
|
|
mbean_search_results = {}
|
|
|
|
sys.stdout.write('<<<jolokia_metrics>>>\n')
|
|
# Fetch the general information first
|
|
for var in global_vars + specific_vars.get(product, []):
|
|
# support old and new configuration format so we stay compatible with older
|
|
# configuration files
|
|
if len(var) == 3:
|
|
path, title, itemspec = var
|
|
mbean, path = path.split("/", 1)
|
|
do_search = False
|
|
else:
|
|
mbean, path, title, itemspec, do_search = var
|
|
|
|
queries = []
|
|
if do_search:
|
|
if mbean in mbean_search_results:
|
|
paths = mbean_search_results[mbean]
|
|
else:
|
|
paths = fetch_var(inst["protocol"], inst["server"], inst["port"], mbean,
|
|
inst["suburi"], "", None, None, None, function="search")[0][1]
|
|
mbean_search_results[mbean] = paths
|
|
|
|
for mbean_exp in paths:
|
|
queries.append( (inst, "%s/%s" % (urllib2.quote(mbean_exp), path), path,
|
|
itemspec, mbean_exp) )
|
|
else:
|
|
queries.append( (inst, mbean + "/" + path, title, itemspec) )
|
|
|
|
for inst, mbean_path, title, itemspec in queries:
|
|
try:
|
|
for out_item, out_title, out_value in fetch_metric(inst, mbean_path, title, itemspec):
|
|
sys.stdout.write("%s %s %s\n" % (out_item, out_title, out_value) )
|
|
except IOError:
|
|
return
|
|
except socket.timeout:
|
|
return
|
|
except:
|
|
if opt_debug:
|
|
raise
|
|
# Simply ignore exceptions. Need to be removed for debugging
|
|
continue
|
|
|
|
if custom_vars:
|
|
sys.stdout.write('<<<jolokia_generic>>>\n')
|
|
for var in custom_vars:
|
|
mbean, path, title, itemspec, do_search, value_type = var
|
|
queries = []
|
|
if do_search:
|
|
if mbean in mbean_search_results:
|
|
paths = mbean_search_results[mbean]
|
|
else:
|
|
paths = fetch_var(inst["protocol"], inst["server"], inst["port"], mbean,
|
|
inst["suburi"], "", None, None, None, function="search")[0][1]
|
|
mbean_search_results[mbean] = paths
|
|
|
|
for mbean_exp in paths:
|
|
queries.append( (inst, "%s/%s" % (urllib2.quote(mbean_exp), path), path,
|
|
itemspec, mbean_exp) )
|
|
else:
|
|
queries.append( (inst, mbean + "/" + path, title, itemspec) )
|
|
|
|
for inst, mbean_path, title, itemspec in queries:
|
|
try:
|
|
for out_item, out_title, out_value in fetch_metric(inst, mbean_path, title, itemspec):
|
|
sys.stdout.write("%s %s %s %s\n" % (out_item, out_title, out_value, value_type) )
|
|
except IOError:
|
|
return
|
|
except socket.timeout:
|
|
return
|
|
except:
|
|
if opt_debug:
|
|
raise
|
|
# Simply ignore exceptions. Need to be removed for debugging
|
|
continue
|
|
|
|
|
|
# Default configuration for all instances
|
|
protocol = "http"
|
|
server = "localhost"
|
|
port = 8080
|
|
user = "monitoring"
|
|
password = None
|
|
mode = "digest"
|
|
suburi = "jolokia"
|
|
instance = None
|
|
cert_path = "_default"
|
|
client_cert = None
|
|
client_key = None
|
|
service_url = None
|
|
service_user = None
|
|
service_password = None
|
|
product = None
|
|
|
|
global_vars = [
|
|
( "java.lang:type=Memory", "NonHeapMemoryUsage/used", "NonHeapMemoryUsage", [], False),
|
|
( "java.lang:type=Memory", "NonHeapMemoryUsage/max", "NonHeapMemoryMax", [], False),
|
|
( "java.lang:type=Memory", "HeapMemoryUsage/used", "HeapMemoryUsage", [], False),
|
|
( "java.lang:type=Memory", "HeapMemoryUsage/max", "HeapMemoryMax", [], False),
|
|
( "java.lang:type=Threading", "ThreadCount", "ThreadCount", [], False),
|
|
( "java.lang:type=Threading", "DaemonThreadCount", "DeamonThreadCount", [], False),
|
|
( "java.lang:type=Threading", "PeakThreadCount", "PeakThreadCount", [], False),
|
|
( "java.lang:type=Threading", "TotalStartedThreadCount", "TotalStartedThreadCount", [], False),
|
|
( "java.lang:type=Runtime", "Uptime", "Uptime", [], False),
|
|
( "java.lang:type=GarbageCollector,name=*", "CollectionCount", "", [], False),
|
|
( "java.lang:type=GarbageCollector,name=*", "CollectionTime", "", [], False),
|
|
( "java.lang:name=CMS%20Perm%20Gen,type=MemoryPool", "Usage/used", "PermGenUsage", [], False),
|
|
( "java.lang:name=CMS%20Perm%20Gen,type=MemoryPool", "Usage/max", "PermGenMax", [], False),
|
|
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "OffHeapHits", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "OnDiskHits", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "InMemoryHitPercentage", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "CacheMisses", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "OnDiskHitPercentage", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "MemoryStoreObjectCount", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "DiskStoreObjectCount", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "CacheMissPercentage", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "CacheHitPercentage", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "OffHeapHitPercentage", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "InMemoryMisses", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "OffHeapStoreObjectCount", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "WriterQueueLength", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "WriterMaxQueueSize", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "OffHeapMisses", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "InMemoryHits", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "AssociatedCacheName", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "ObjectCount", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "OnDiskMisses", "", [], True),
|
|
( "net.sf.ehcache:CacheManager=CacheManagerApplication*,*,type=CacheStatistics", "CacheHits", "", [], True),
|
|
]
|
|
|
|
|
|
specific_vars = {
|
|
"weblogic" : [
|
|
( "*:*", "CompletedRequestCount", None, [ "ServerRuntime" ] , False),
|
|
( "*:*", "QueueLength", None, [ "ServerRuntime" ] , False),
|
|
( "*:*", "StandbyThreadCount", None, [ "ServerRuntime" ] , False),
|
|
( "*:*", "PendingUserRequestCount", None, [ "ServerRuntime" ] , False),
|
|
( "*:Name=ThreadPoolRuntime,*", "ExecuteThreadTotalCount", None, [ "ServerRuntime" ] , False),
|
|
( "*:*", "ExecuteThreadIdleCount", None, [ "ServerRuntime" ] , False),
|
|
( "*:*", "HoggingThreadCount", None, [ "ServerRuntime" ] , False),
|
|
( "*:Type=WebAppComponentRuntime,*", "OpenSessionsCurrentCount", None, [ "ServerRuntime", "ApplicationRuntime" ] , False),
|
|
],
|
|
"tomcat" : [
|
|
( "*:type=Manager,*", "activeSessions,maxActiveSessions", None, [ "path", "context" ] , False),
|
|
( "*:j2eeType=Servlet,name=default,*", "stateName", None, [ "WebModule" ] , False),
|
|
# Check not yet working
|
|
( "*:j2eeType=Servlet,name=default,*", "requestCount", None, [ "WebModule" ], False),
|
|
( "*:name=*,type=ThreadPool", "maxThreads", None, [], False),
|
|
( "*:name=*,type=ThreadPool", "currentThreadCount", None, [], False),
|
|
( "*:name=*,type=ThreadPool", "currentThreadsBusy", None, [], False),
|
|
# too wide location for addressing the right info
|
|
# ( "*:j2eeType=Servlet,*", "requestCount", None, [ "WebModule" ] , False),
|
|
],
|
|
"jboss" : [
|
|
( "*:type=Manager,*", "activeSessions,maxActiveSessions", None, [ "path", "context" ] , False),
|
|
],
|
|
}
|
|
|
|
|
|
# ( '*:j2eeType=WebModule,name=/--/localhost/-/%(app)s,*/state', None, [ "name" ]),
|
|
# ( '*:j2eeType=Servlet,WebModule=/--/localhost/-/%(app)s,name=%(servlet)s,*/requestCount', None, [ "WebModule", "name" ]),
|
|
# ( "Catalina:J2EEApplication=none,J2EEServer=none,WebModule=*,j2eeType=Servlet,name=*", None, [ "WebModule", "name" ]),
|
|
|
|
|
|
# List of instances to monitor. Each instance is a dict where
|
|
# the global configuration values can be overridden.
|
|
instances = [{}]
|
|
|
|
custom_vars = []
|
|
|
|
conffile = os.getenv("MK_CONFDIR", "/etc/check_mk") + "/jolokia.cfg"
|
|
|
|
if os.path.exists(conffile):
|
|
execfile(conffile)
|
|
|
|
if server == "use fqdn":
|
|
server = socket.getfqdn()
|
|
|
|
if instance == None:
|
|
instance = str(port)
|
|
|
|
# We have to deal with socket timeouts. Python > 2.6
|
|
# supports timeout parameter for the urllib2.urlopen method
|
|
# but we are on a python 2.5 system here which seem to use the
|
|
# default socket timeout. We are local here so set it to 1 second.
|
|
socket.setdefaulttimeout(1.0)
|
|
|
|
# Compute list of instances to monitor. If the user has defined
|
|
# instances in his configuration, we will use this (a list
|
|
# of dicts).
|
|
for inst in instances:
|
|
for varname, value in [
|
|
("protocol", protocol),
|
|
("server", server),
|
|
("port", port),
|
|
("user", user),
|
|
("password", password),
|
|
("mode", mode),
|
|
("suburi", suburi),
|
|
("instance", instance),
|
|
("cert_path", cert_path),
|
|
("client_cert", client_cert),
|
|
("client_key", client_key),
|
|
("service_url", service_url),
|
|
("service_user", service_user),
|
|
("service_password", service_password),
|
|
( "product", product ),
|
|
]:
|
|
if varname not in inst:
|
|
inst[varname] = value
|
|
if not inst["instance"]:
|
|
inst["instance"] = str(inst["port"])
|
|
inst["instance"] = inst["instance"].replace(" ", "_")
|
|
|
|
if inst.get("server") == "use fqdn":
|
|
inst["server"] = socket.getfqdn()
|
|
|
|
query_instance(inst)
|