You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1212 lines
56 KiB
1212 lines
56 KiB
# Copyright (C) 2005-2021 Splunk Inc. All Rights Reserved.
|
|
# Core Python Imports
|
|
import sys
|
|
import logging
|
|
import logging.handlers
|
|
import re
|
|
from httplib2 import ServerNotFoundError
|
|
import socket
|
|
import time
|
|
import json
|
|
import datetime
|
|
|
|
# Splunkd imports
|
|
import splunk
|
|
import splunk.rest as rest
|
|
import splunk.util as util
|
|
import lxml.etree as et
|
|
from splunk.clilib.bundle_paths import make_splunkhome_path
|
|
|
|
# TA and SA Imports
|
|
sys.path.append(make_splunkhome_path(['etc', 'apps', 'SA-Hydra-inframon', 'bin']))
|
|
sys.path.append(make_splunkhome_path(['etc', 'apps', 'Splunk_TA_vmware_inframon', 'bin']))
|
|
from hydra_inframon.six import iteritems
|
|
import ta_vmware_inframon.simple_vsphere_utils as vsu
|
|
from ta_vmware_inframon.models import TAVMwareCollectionStanza, TAVMwareVCenterForwarderStanza, \
|
|
SSLCertificate, PoolStanza, TemplateStanza
|
|
from hydra_inframon.models import SplunkStoredCredential, HydraNodeStanza, HydraCacheStanza, HydraSessionStanza
|
|
|
|
# defining global constants
|
|
REST_ROOT_PATH = '/services'
|
|
local_host_path = splunk.mergeHostPath()
|
|
max_worker_process = 30
|
|
|
|
STATUS_CODES = {
|
|
400: 'Bad Request',
|
|
401: 'Unauthorized',
|
|
402: 'Payment Required',
|
|
403: 'Forbidden',
|
|
404: 'Not Found',
|
|
405: 'Method Not Allowed',
|
|
406: 'Not Acceptable',
|
|
407: 'Proxy Authentication Required',
|
|
408: 'Request Timeout',
|
|
409: 'Conflict',
|
|
411: 'Length Required',
|
|
500: 'Internal Server Error',
|
|
503: 'Service Unavailable'
|
|
}
|
|
|
|
|
|
class RestError(Exception):
|
|
"""
|
|
REST Error.
|
|
"""
|
|
|
|
def __init__(self, status, message):
|
|
self.status = status
|
|
self.reason = STATUS_CODES.get(
|
|
status,
|
|
'Unknown Error',
|
|
)
|
|
self.message = message
|
|
err_msg = 'REST Error [%(status)s]: %(reason)s -- %(message)s' % {
|
|
'status': self.status,
|
|
'reason': self.reason,
|
|
'message': self.message
|
|
}
|
|
super(RestError, self).__init__(err_msg)
|
|
|
|
|
|
def setup_logger(logger=None, log_format='%(asctime)s %(levelname)s [ConfigSetUp] %(message)s',
|
|
level=logging.INFO, log_name="splunk_for_vmware_setup.log", logger_name="splunk_for_vmware_setup"):
|
|
"""
|
|
Setup a logger suitable for splunkd consumption
|
|
"""
|
|
if logger is None:
|
|
logger = logging.getLogger(logger_name)
|
|
|
|
# Prevent the log messages from being duplicated in the python.log file
|
|
logger.propagate = False
|
|
logger.setLevel(level)
|
|
|
|
file_handler = logging.handlers.RotatingFileHandler(make_splunkhome_path(
|
|
['var', 'log', 'splunk', log_name]), maxBytes=2500000, backupCount=5)
|
|
formatter = logging.Formatter(log_format)
|
|
file_handler.setFormatter(formatter)
|
|
|
|
logger.handlers = []
|
|
logger.addHandler(file_handler)
|
|
|
|
logger.debug("Init splunk for vmware setup logger")
|
|
|
|
return logger
|
|
|
|
|
|
def splunk_rest_request(path, logger, local_session_key=None, session_key=None, getargs=None, postargs=None,
|
|
method='GET',
|
|
raise_all_errors=False, raw_result=False, timeout=30, jsonargs=None):
|
|
"""
|
|
This is mostly a shameful copy of splunk.rest.simpleRequest.
|
|
The difference lies in the automagic header/cert attachment that
|
|
happens in splunkweb and messes with the splunkweb cherrypy.session.
|
|
Also we don't auto magic any session keys
|
|
|
|
Makes an HTTP call to the main splunk REST endpoint
|
|
|
|
path: the URI to fetch
|
|
If given a relative URI, then the method will normalize to the splunkd
|
|
default of "/services/...".
|
|
If given an absolute HTTP(S) URI, then the method will use as-is.
|
|
If given a 'file://' URI, then the method will attempt to read the file
|
|
from the local filesystem. Only files under $SPLUNK_HOME are supported,
|
|
so paths are 'chrooted' from $SPLUNK_HOME.
|
|
|
|
getargs: dict of k/v pairs that are always appended to the URL
|
|
|
|
postargs: dict of k/v pairs that get placed into the body of the
|
|
request. If postargs is provided, then the HTTP method is auto
|
|
assigned to POST.
|
|
|
|
method: the HTTP verb - [GET | POST | DELETE | PUT]
|
|
|
|
raise_all_errors: indicates if the method should raise an exception
|
|
if the server HTTP response code is >= 400
|
|
|
|
raw_result: don't raise an exception if a non 200 response is received;
|
|
return the actual response
|
|
|
|
Return:
|
|
|
|
This method will return a tuple of (server_response, server_content)
|
|
|
|
server_response: a dict of HTTP status information
|
|
server_content: the body content
|
|
"""
|
|
logger.debug("Called splunk_rest_request method of rest_utility()")
|
|
# strip spaces
|
|
path = path.strip(' ')
|
|
# if absolute URI, pass along as-is
|
|
if path.startswith('http'):
|
|
uri = path
|
|
|
|
# if file:// protocol, try to read file and return
|
|
# the serverStatus is just an empty dict; file contents are in server_response
|
|
elif path.startswith('file://'):
|
|
raise Exception(
|
|
"Not supported for this method, use splunk.rest.simpleRequest instead")
|
|
|
|
else:
|
|
# prepend convenience root path
|
|
if not path.startswith(REST_ROOT_PATH):
|
|
path = REST_ROOT_PATH + '/' + path.strip('/')
|
|
|
|
# setup args
|
|
host = splunk.getDefault('host')
|
|
if ':' in host:
|
|
host = '[%s]' % host
|
|
|
|
uri = '%s://%s:%s/%s' % \
|
|
(splunk.getDefault('protocol'), host,
|
|
splunk.getDefault('port'), path.strip('/'))
|
|
|
|
if getargs:
|
|
getargs = dict([(k, v) for (k, v) in iteritems(getargs) if v is not None])
|
|
uri += '?' + util.urlencodeDict(getargs)
|
|
|
|
# proxy mode bypasses all header passing
|
|
headers = {}
|
|
session_source = 'direct'
|
|
|
|
if session_key:
|
|
headers['Authorization'] = 'Splunk %s' % session_key
|
|
|
|
payload = ''
|
|
if postargs or jsonargs and method in ('GET', 'POST', 'PUT'):
|
|
if method == 'GET':
|
|
method = 'POST'
|
|
if jsonargs:
|
|
# if a JSON body was given, use it for the payload and ignore the postargs
|
|
payload = jsonargs
|
|
else:
|
|
payload = util.urlencodeDict(postargs)
|
|
#
|
|
# make request
|
|
#
|
|
t1 = None
|
|
if logger.level <= logging.DEBUG:
|
|
if uri.lower().find('login') > -1:
|
|
logpayload = '[REDACTED]'
|
|
else:
|
|
logpayload = payload
|
|
logger.debug(
|
|
'splunk_rest_request >>>\n\tmethod=%s\n\turi=%s\n\tbody=%s', method, uri, logpayload)
|
|
logger.debug('splunk_rest_request > %s %s [%s] session_source=%s' % (
|
|
method, uri, logpayload, session_source))
|
|
t1 = time.time()
|
|
|
|
# Certificate validation status from inframon_ta_vmware_config_ssl.conf
|
|
|
|
stanzas = SSLCertificate.all(sessionKey=local_session_key)
|
|
cert_validation = not stanzas[0].validate_ssl_certificate
|
|
|
|
if cert_validation:
|
|
logger.info(
|
|
"SSL certificate validation disabled for collection configuration")
|
|
else:
|
|
logger.info(
|
|
"SSL certificate validation enabled for collection configuration")
|
|
|
|
# Add wait and tries to check if the HTTP server is up and running
|
|
tries = 4
|
|
wait = 10
|
|
server_response = None
|
|
server_content = None
|
|
try:
|
|
import httplib2
|
|
for a_try in range(tries):
|
|
h = httplib2.Http(
|
|
timeout=timeout, disable_ssl_certificate_validation=cert_validation)
|
|
server_response, server_content = h.request(
|
|
uri, method, headers=headers, body=payload)
|
|
if server_response is None:
|
|
if a_try < tries:
|
|
time.sleep(wait)
|
|
else:
|
|
break
|
|
except socket.error as e:
|
|
raise splunk.SplunkdConnectionException(str(e))
|
|
except socket.timeout as e:
|
|
raise splunk.SplunkdConnectionException('Timed out while waiting for splunkd daemon to respond. Splunkd may be hung. (timeout=30)')
|
|
except AttributeError as e:
|
|
raise splunk.SplunkdConnectionException('Unable to establish connection with splunkd deamon. (%s)' % e)
|
|
|
|
server_response.messages = []
|
|
|
|
if logger.level <= logging.DEBUG:
|
|
logger.debug('simpleRequest < server responded status=%s responseTime=%.4fs',
|
|
server_response.status, time.time() - t1)
|
|
|
|
# Don't raise exceptions for different status codes or try and parse the response
|
|
if raw_result:
|
|
return server_response, server_content
|
|
|
|
#
|
|
# we only throw exceptions in limited cases; for most HTTP errors, splunkd
|
|
# will return messages in the body, which we parse, so we don't want to
|
|
# halt everything and raise exceptions; it is up to the client to figure
|
|
# out the best course of action
|
|
#
|
|
if server_response.status == 401:
|
|
# SPL-20915
|
|
logger.debug(
|
|
'splunk_rest_request - Authentication failed; session_key=%s', session_key)
|
|
raise splunk.AuthenticationFailed
|
|
|
|
elif server_response.status == 402:
|
|
raise splunk.LicenseRestriction
|
|
|
|
elif server_response.status == 403:
|
|
raise splunk.AuthorizationFailed(extendedMessages=uri)
|
|
|
|
elif server_response.status == 404:
|
|
|
|
# Some 404 responses, such as those for expired jobs which were originally
|
|
# run by the scheduler return extra data about the original resource.
|
|
# In this case we add that additional info into the exception object
|
|
# as the resource_info parameter so others might use it.
|
|
try:
|
|
body = et.fromstring(server_content)
|
|
resource_info = body.find('dict')
|
|
if resource_info is not None:
|
|
raise splunk.ResourceNotFound(
|
|
uri, format.nodeToPrimitive(resource_info))
|
|
else:
|
|
raise splunk.ResourceNotFound(
|
|
uri, extendedMessages=rest.extractMessages(body))
|
|
except et.XMLSyntaxError:
|
|
pass
|
|
|
|
raise splunk.ResourceNotFound(uri)
|
|
|
|
elif server_response.status == 201:
|
|
try:
|
|
body = et.fromstring(server_content)
|
|
server_response.messages = rest.extractMessages(body)
|
|
except et.XMLSyntaxError as e:
|
|
# do nothing, just continue, no messages to extract if there is no xml
|
|
pass
|
|
except Exception as e:
|
|
# warn if some other type of error occurred.
|
|
logger.warn(
|
|
"exception trying to parse server_content returned from a 201 response.")
|
|
|
|
elif server_response.status < 200 or server_response.status > 299:
|
|
|
|
# service may return messages in the body; try to parse them
|
|
try:
|
|
body = et.fromstring(server_content)
|
|
server_response.messages = rest.extractMessages(body)
|
|
except:
|
|
pass
|
|
|
|
if raise_all_errors and server_response.status > 399:
|
|
|
|
if server_response.status == 500:
|
|
raise splunk.InternalServerError((None,
|
|
server_response.messages))
|
|
elif server_response.status == 400:
|
|
raise splunk.BadRequest((None, server_response.messages))
|
|
else:
|
|
raise splunk.RESTException((server_response.status,
|
|
server_response.messages))
|
|
|
|
# return the headers and body content
|
|
return server_response, server_content
|
|
|
|
|
|
def get_remote_session_key(username, password, local_session_key, host_path, logger):
|
|
"""
|
|
Get a remote session key from the auth system
|
|
If fails return None
|
|
"""
|
|
|
|
uri = splunk.mergeHostPath(host_path) + '/services/auth/login'
|
|
args = {'username': username, 'password': password}
|
|
server_response = None
|
|
server_content = None
|
|
try:
|
|
server_response, server_content = splunk_rest_request(
|
|
uri, logger, local_session_key=local_session_key, postargs=args)
|
|
|
|
except splunk.AuthenticationFailed:
|
|
return None
|
|
|
|
if server_response and server_response.status != 200:
|
|
logger.error(
|
|
'get_remote_session_key - unable to login; check credentials')
|
|
rest.extractMessages(et.fromstring(server_content))
|
|
return None
|
|
|
|
root = et.fromstring(server_content)
|
|
session_key = root.findtext('sessionKey')
|
|
|
|
return session_key
|
|
|
|
|
|
def validate_dcn(node_path, username, password, heads, pool_name, local_session_key, logger):
|
|
"""
|
|
|
|
:param node_path: dcn managment port url
|
|
:param username: dcn splunk username
|
|
:param password: dcn splunk password
|
|
:param heads: dcn worker process
|
|
:param pool_name: pool name in which dcn belongs
|
|
:param local_session_key:
|
|
:param logger:
|
|
:return: result of validation as a response
|
|
"""
|
|
|
|
credential_validation = False
|
|
last_connectivity_checked = datetime.datetime.utcnow()
|
|
# addon_validation checking condition will be changed latter (as package structure is not decided yet.)
|
|
addon_validation = False
|
|
|
|
if not pool_name == [None]:
|
|
if isinstance(pool_name, list):
|
|
pool_name = pool_name[0]
|
|
|
|
pool_name = pool_name.strip()
|
|
if len(pool_name) == 0:
|
|
logger.error("Pool name cannot be empty for node:{0}.".format(node_path))
|
|
response = {"status": "invalid", "message": "Pool name cannot be empty.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
pool_stanza = PoolStanza.from_name(pool_name, "Splunk_TA_vmware_inframon", host_path=local_host_path,
|
|
session_key=local_session_key)
|
|
if not pool_stanza:
|
|
logger.error("[pool={0}]Given pool for node:{1} doesn't exist.".format(pool_name, node_path))
|
|
response = {"status": "invalid", "message": "Given pool doesn't exist.",
|
|
"addon_validation": addon_validation,
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
else:
|
|
logger.error("pool name is not passed for node:{0}".format(node_path))
|
|
response = {"status": "invalid", "message": "Empty pool name is not allowed.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
if not node_path == [None]:
|
|
# node_path could be list or string (list in case of coming in args , string if coming as target).
|
|
if isinstance(node_path, list):
|
|
node_path = node_path[0]
|
|
|
|
validated_node_path = re.search(
|
|
"^\s*https?:\/\/[A-Za-z0-9\.\-_]+:\d+\/?\s*$", node_path)
|
|
if validated_node_path is None:
|
|
logger.error("[pool={0}]Node name passed is not valid.".format(pool_name))
|
|
response = {"status": "invalid", "message": "Node name passed is not valid.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
else:
|
|
logger.error("[pool={0}]No node name passed in data, cannot save nothing!".format(pool_name))
|
|
response = {"status": "invalid", "message": "Empty node name is not allowed.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
if not username == [None]:
|
|
if isinstance(username, list):
|
|
username = username[0]
|
|
username = username.strip()
|
|
validated_node_username = re.search("^[^\r\n\t\/\s]+$", username)
|
|
if validated_node_username is None:
|
|
logger.error(
|
|
"[pool={0}]Node username passed for node:{1} is not valid.".format(pool_name, node_path))
|
|
response = {"status": "invalid", "message": "Username is not valid.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
else:
|
|
logger.error(
|
|
"[pool={0}]No username passed for node:{1}".format(pool_name, node_path))
|
|
response = {"status": "invalid", "message": "Empty username is not allowed.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
if not heads == [None]:
|
|
if isinstance(heads, list):
|
|
heads = heads[0]
|
|
validated_heads = re.search("^(([1-2][0-9])|[1-9]|30)$", heads)
|
|
if validated_heads is None:
|
|
logger.error("[pool={0}]Heads is not valid for node:{1}.".format(pool_name, node_path))
|
|
response = {"status": "invalid", "message": "Heads is not valid.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
else:
|
|
logger.error(
|
|
"[pool={0}]No heads passed for node:{1}".format(pool_name, node_path))
|
|
response = {"status": "invalid", "message": "Empty heads is not allowed.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
if not password == [None]:
|
|
if isinstance(password, list):
|
|
password = password[0]
|
|
password = password.strip()
|
|
if len(password) == 0:
|
|
logger.error("[pool={0}]Password is not valid for node:{1}.".format(pool_name, node_path))
|
|
response = {"status": "invalid", "message": "Password is not valid.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
else:
|
|
logger.error("[pool={0}]No password passed for node:{1}.".format(pool_name, node_path))
|
|
response = {"status": "invalid", "message": "Empty password is not allowed.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
last_connectivity_checked = datetime.datetime.utcnow()
|
|
try:
|
|
remote_session_key = get_remote_session_key(
|
|
username, password, local_session_key, node_path, logger)
|
|
|
|
if remote_session_key is None:
|
|
response = {"status": "valid", "message": "Could reach host, but login failed",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
|
|
else:
|
|
# Okay credentials are good, now we can check that the apps are there
|
|
server_response, server_content = splunk_rest_request(
|
|
path=node_path + '/services/apps/local', logger=logger, local_session_key=local_session_key,
|
|
session_key=remote_session_key, getargs={'count': '0'})
|
|
apps = rest.format.parseFeedDocument(server_content)
|
|
# required_apps is to be changed latter.
|
|
required_apps = ["SA-Hydra-inframon", "Splunk_TA_vmware_inframon"]
|
|
|
|
installed_count = 0
|
|
installed_apps = []
|
|
for app in apps:
|
|
contents = app.toPrimitive()
|
|
if 'label' in contents:
|
|
installed_apps.append(contents['label'])
|
|
if app.title in required_apps:
|
|
installed_count += 1
|
|
|
|
credential_validation = True
|
|
if installed_count == len(required_apps):
|
|
addon_validation = True
|
|
response = {"status": "valid", "message": "Everything is valid",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
else:
|
|
logger.error(
|
|
"[pool={2}]Username/password are good for node:{0}, but apps are not there, it had installed_apps='{1}'".
|
|
format(node_path, str(installed_apps), pool_name))
|
|
addon_validation = False
|
|
response = {"status": "badapps", "message": "Username/password are good but apps are not there",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
|
|
except ServerNotFoundError:
|
|
logger.error("[pool=%s]Could not reach host=%s", pool_name, node_path)
|
|
response = {"status": "unreachable", "message": "Could not reach host",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
except splunk.SplunkdConnectionException:
|
|
logger.error("[pool=%s]Could not find splunkd on node=%s", pool_name, node_path)
|
|
response = {"status": "unreachable", "message": "Could not reach host",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
except splunk.AuthenticationFailed:
|
|
logger.error(
|
|
"[pool=%s]Could not log into splunkd on node=%s, credentials are definitely bad", pool_name, node_path)
|
|
response = {"status": "invalid_creds", "message": "Could not authenticate with remote splunkd",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
except Exception:
|
|
logger.exception("[pool={1}]Could not reach host={0}.".format(node_path, pool_name))
|
|
response = {"status": "unreachable", "message": "Could not reach host",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
|
|
return response
|
|
|
|
|
|
def validate_vcenter(vc_path, username, password, pool_name, local_session_key, logger, check_connection_only=False):
|
|
"""
|
|
|
|
:param vc_path: vCenter path
|
|
:param username: vCenter username
|
|
:param password: vCenter password
|
|
:param pool_name: vCenter pool_name
|
|
:param local_session_key: local session key of current Splunk session
|
|
:param check_connection_only: flag denoting whether to validate vc using stanzas from conf or check connection using the provided credentials
|
|
:return: returns the result of validation as a response
|
|
"""
|
|
credential_validation = False
|
|
last_connectivity_checked = datetime.datetime.utcnow()
|
|
|
|
if check_connection_only:
|
|
dbg_info = 'Check_connection_only'
|
|
else:
|
|
if not pool_name == [None]:
|
|
if isinstance(pool_name, list):
|
|
pool_name = pool_name[0]
|
|
pool_name = pool_name.strip()
|
|
|
|
if len(pool_name) == 0:
|
|
logger.error("for vCenter:{0} Pool name cannot be empty.".format(vc_path))
|
|
response = {"status": "invalid", "message": "Pool name cannot be empty.",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
pool_stanza = PoolStanza.from_name(pool_name, "Splunk_TA_vmware_inframon", host_path=local_host_path,
|
|
session_key=local_session_key)
|
|
if not pool_stanza:
|
|
logger.error("for vCenter:{0} Given pool doesn't exist.".format(vc_path))
|
|
response = {"status": "invalid", "message": "Given pool doesn't exist.",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
else:
|
|
logger.error("for vCenter:{0} No pool_name passed".format(vc_path))
|
|
response = {"status": "invalid", "message": "Empty pool name is not allowed.",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
dbg_info = 'pool={0}'.format(pool_name)
|
|
|
|
if not vc_path == [None]:
|
|
# vc_path could be list or string based on from where is comming
|
|
if isinstance(vc_path, list):
|
|
vc_path = vc_path[0]
|
|
validate_vc_domain = re.search("^[A-Za-z0-9\.\-_]+$", vc_path)
|
|
if validate_vc_domain is None:
|
|
logger.error("[{0}]vCenter domain passed is not valid.".format(dbg_info))
|
|
response = {"status": "invalid", "message": "vCenter domain passed is not valid.",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
else:
|
|
logger.error("[{0}]No vCenter domain passed".format(dbg_info))
|
|
response = {"status": "invalid", "message": "No vCenter domain passed , cannot validate nothing!",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
if not username == [None] and not username == None:
|
|
if isinstance(username, list):
|
|
username = username[0]
|
|
username = username.strip()
|
|
validated_username = re.search("^[^\r\n\t\/\s]+$", username)
|
|
if validated_username is None:
|
|
logger.error("[{0}] for vCenter:{1} username passed is not valid.".format(dbg_info, vc_path))
|
|
response = {"status": "invalid", "message": "vCenter username passed is not valid.",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
else:
|
|
logger.error("[{0}] for vCenter:{1} Username is not passed".format(dbg_info, vc_path))
|
|
response = {"status": "invalid", "message": "Username is not passed to validate_vcenter, cannot validate!",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
if not password == [None] and not password == None:
|
|
if isinstance(password, list):
|
|
password = password[0]
|
|
password = password.strip()
|
|
if len(password) == 0:
|
|
logger.error("[{0}] for vCenter:{1} Password is not valid.".format(dbg_info, vc_path))
|
|
response = {"status": "invalid", "message": "Password is not valid.",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
else:
|
|
logger.error("[{0}] for vCenter:{1} Password is not passed".format(dbg_info, vc_path))
|
|
response = {"status": "invalid", "message": "Password is not passed, cannot validate!",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
return response
|
|
|
|
logger.info("Checking vc={0} with username={1}".format(vc_path, username))
|
|
last_connectivity_checked = datetime.datetime.utcnow()
|
|
try:
|
|
vs = vsu.vSphereService(vc_path, username, password)
|
|
credential_validation = True
|
|
response = {"status": "valid", "message": "Everyting is valid.",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
if vs.logout():
|
|
logger.debug("User={0} successfully logout from {1}.".format(username, vc_path))
|
|
else:
|
|
logger.warn("User={0} failed to logout from {1}.".format(username, vc_path))
|
|
except vsu.ConnectionFailure:
|
|
credential_validation = False
|
|
logger.error("[{1}]Could not reach the vc:{0} to test credentials".format(vc_path, dbg_info))
|
|
response = {"status": "unreachable", "message": "Could not reach the vc to test credentials",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
except vsu.LoginFailure:
|
|
credential_validation = False
|
|
logger.error("[{1}]Could reach vc:{0}, but login failed.".format(vc_path, dbg_info))
|
|
response = {"status": "loginFailed", "message": "Could reach vc, but login failed",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
except Exception:
|
|
logger.exception("[{1}]Exception occurred while validating vc:{0}".format(vc_path, dbg_info))
|
|
credential_validation = False
|
|
response = {"status": "unreachable", "message": "Could not reach the vc to test creds",
|
|
"credential_validation": credential_validation,
|
|
"last_connectivity_checked": last_connectivity_checked}
|
|
|
|
return response
|
|
|
|
|
|
def validate_vcenter_forwarder(vc_path, username, password, local_session_key, logger):
|
|
"""
|
|
|
|
:param vc_path: path of vCenter
|
|
:param username: username of Splunk forwarder on vCenter
|
|
:param password: password of Splunk forwarder on vCenter
|
|
:param local_session_key: local session key of current session.
|
|
:return: It returns the validation result as a s response
|
|
"""
|
|
credential_validation = False
|
|
addon_validation = False
|
|
|
|
if not vc_path == [None]:
|
|
# vc_path could be list or string based on from where is comming
|
|
if isinstance(vc_path, list):
|
|
vc_path = vc_path[0]
|
|
validate_vc_domain = re.search("^\s*https?:\/\/[A-Za-z0-9\.\-_]+:\d+\/?\s*$", vc_path)
|
|
if validate_vc_domain is None:
|
|
logger.error("vCenter domain passed is not valid.")
|
|
response = {"status": "invalid", "message": "vc forwarder uri passed to validate_vcenter is not valid.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation}
|
|
return response
|
|
else:
|
|
logger.error("No vc domain passed, cannot validate nothing!")
|
|
response = {"status": "invalid", "message": "No vc domain passed to validate_vcenter, cannot validate nothing!",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation}
|
|
return response
|
|
|
|
if not username == [None]:
|
|
if isinstance(username, list):
|
|
username = username[0]
|
|
username = username.strip()
|
|
validated_username = re.search("^[^\r\n\t\/\s]+$", username)
|
|
if validated_username is None:
|
|
logger.error("vCenter forwarder username is not valid.")
|
|
response = {"status": "invalid", "message": "vCenter forwarder username is not valid.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation}
|
|
return response
|
|
else:
|
|
logger.error("Username is not passed , cannot validate!")
|
|
response = {"status": "invalid", "message": "Username is not passed to validate_vcenter, cannot validate!",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation}
|
|
return response
|
|
|
|
if not password == [None]:
|
|
if isinstance(password, list):
|
|
password = password[0]
|
|
password = password.strip()
|
|
if len(password) == 0:
|
|
logger.error("Password is not valid.")
|
|
response = {"status": "invalid", "message": "Password is not valid.",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation}
|
|
return response
|
|
else:
|
|
logger.error("Password is not passed, cannot validate!")
|
|
response = {"status": "invalid",
|
|
"message": "Password is not passed to validate_vcenter_forwrder,cannot validate!",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation}
|
|
return response
|
|
|
|
logger.info("Checking vc=%s forwarder with username=%s", vc_path, username)
|
|
|
|
# validating credentials.
|
|
try:
|
|
remote_session_key = get_remote_session_key(username, password, local_session_key, host_path=vc_path,
|
|
logger=logger)
|
|
if remote_session_key is None:
|
|
credential_validation = False
|
|
addon_validation = False
|
|
response = {"status": "LoginFailed", "message": "Could reach host, but login failed",
|
|
"credential_validation": credential_validation, "addon_validation": addon_validation}
|
|
else:
|
|
# Okay credentials are good, now we can check that the apps are there
|
|
server_response, server_content = splunk_rest_request(path=vc_path + '/services/apps/local', logger=logger,
|
|
local_session_key=local_session_key,
|
|
session_key=remote_session_key,
|
|
getargs={'count': '0'})
|
|
apps = rest.format.parseFeedDocument(server_content)
|
|
logger.info("Accessing apps")
|
|
required_apps = ["Splunk_TA_vcenter"]
|
|
installed_count = 0
|
|
installed_apps = []
|
|
for app in apps:
|
|
contents = app.toPrimitive()
|
|
if 'label' in contents:
|
|
installed_apps.append(contents['label'])
|
|
if app.title in required_apps:
|
|
installed_count += 1
|
|
|
|
credential_validation = True
|
|
if installed_count == len(required_apps):
|
|
addon_validation = True
|
|
response = {"status": "valid", "message": "Everything is valid",
|
|
"credential_validation": credential_validation,
|
|
"addon_validation": addon_validation}
|
|
else:
|
|
logger.warning("vc forwarder did not have the required app- Splunk_TA_vcenter.")
|
|
addon_validation = False
|
|
response = {"status": "badapps", "message": "Username/password are good but app is not there",
|
|
"credential_validation": credential_validation,
|
|
"addon_validation": addon_validation}
|
|
except ServerNotFoundError:
|
|
response = {"status": "unreachable", "message": "Could not reach host",
|
|
"credential_validation": credential_validation,
|
|
"addon_validation": addon_validation}
|
|
except splunk.SplunkdConnectionException:
|
|
logger.error("Could not find splunkd on host=%s", vc_path)
|
|
response = {"status": "unreachable", "message": "Could not reach host",
|
|
"credential_validation": credential_validation,
|
|
"addon_validation": addon_validation}
|
|
except splunk.AuthenticationFailed:
|
|
logger.error("Could not log into splunkd on host=%s, credentials are definitely bad", vc_path)
|
|
response = {"status": "LoginFailed", "message": "Could not authenticate with remote splunkd",
|
|
"credential_validation": credential_validation,
|
|
"addon_validation": addon_validation}
|
|
except Exception:
|
|
logger.error("Could not log into splunkd on host=%s, due to an exception", vc_path)
|
|
response = {"status": "LoginFailed", "message": "Could not reach host",
|
|
"credential_validation": credential_validation,
|
|
"addon_validation": addon_validation}
|
|
|
|
return response
|
|
|
|
|
|
def toggle_vc_inputs(host_path, username, password, vc, local_session_key, pool_name, logger, disable=True):
|
|
"""
|
|
toggle on or off all of the inputs in Splunk TA vCenter, default is disable
|
|
|
|
RETURNS nothing
|
|
"""
|
|
|
|
status = True
|
|
try:
|
|
remote_session_key = get_remote_session_key(username, password, local_session_key, host_path, logger)
|
|
except ServerNotFoundError:
|
|
logger.error("Could not find vc_splunk_forwarder=%s", host_path)
|
|
remote_session_key = None
|
|
except splunk.SplunkdConnectionException:
|
|
logger.error("Could not find splunkd on vc_splunk_forwarder=%s", host_path)
|
|
remote_session_key = None
|
|
except splunk.AuthenticationFailed:
|
|
logger.error("Could not log into splunkd on vc_splunk_forwarder=%s, credentials are definitely bad", host_path)
|
|
remote_session_key = None
|
|
except Exception as e:
|
|
remote_session_key = None
|
|
logger.error("Exception occured:{0}".format(e))
|
|
|
|
if remote_session_key is None:
|
|
logger.error(
|
|
"[pool=%s]Could not log into vc_splunk_forwarder=%s with the credentials provided, cannot manage the inputs on that instance",
|
|
pool_name, host_path)
|
|
status = False
|
|
else:
|
|
|
|
uri = '/services/server/info?output_mode=json'
|
|
info_path = host_path.rstrip("/") + uri
|
|
server_response, server_content = splunk_rest_request(
|
|
info_path, logger, local_session_key=local_session_key, session_key=remote_session_key)
|
|
|
|
server_content_dict = json.loads(server_content)
|
|
os = ""
|
|
input_uris = [
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%24ALLUSERSPROFILE%5CVMware%5CvCenterServer%5Clogs%5Cvws',
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%24ALLUSERSPROFILE%5CVMware%5CvCenterServer%5Clogs%5Cvmware-vpx',
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%24ALLUSERSPROFILE%5CVMware%5CvCenterServer%5Clogs%5Cperfcharts',
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%2Fvar%2Flog%2Fvmware%2Fvws',
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%2Fvar%2Flog%2Fvmware%2Fvpxd',
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%2Fvar%2Flog%2Fvmware%2Fperfcharts'
|
|
]
|
|
|
|
try:
|
|
if server_content_dict:
|
|
os = server_content_dict['entry'][0]['content']['os_name']
|
|
logger.info("Splunk Machine OS:{0}".format(os))
|
|
except Exception as e:
|
|
logger.exception(
|
|
"[pool={1}]Exception occurred while determining OS of the machine: {0}".format(e, pool_name))
|
|
|
|
if os == "Windows":
|
|
input_uris = [
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%24ALLUSERSPROFILE%5CVMware%5CvCenterServer%5Clogs%5Cvws',
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%24ALLUSERSPROFILE%5CVMware%5CvCenterServer%5Clogs%5Cvmware-vpx',
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%24ALLUSERSPROFILE%5CVMware%5CvCenterServer%5Clogs%5Cperfcharts']
|
|
elif os == "Linux":
|
|
input_uris = ['/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%2Fvar%2Flog%2Fvmware%2Fvws',
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%2Fvar%2Flog%2Fvmware%2Fvpxd',
|
|
'/servicesNS/nobody/Splunk_TA_vcenter/data/inputs/monitor/%2Fvar%2Flog%2Fvmware%2Fperfcharts']
|
|
|
|
for uri in input_uris:
|
|
path = host_path.rstrip("/") + uri
|
|
if disable:
|
|
postargs = {"host": vc}
|
|
action = "disable"
|
|
else:
|
|
postargs = {"host": vc}
|
|
action = "enable"
|
|
try:
|
|
logger.info(
|
|
"Adjusting input with rest request on path={0} with postargs={1} and secondary action={2}".format(
|
|
path, postargs, action))
|
|
splunk_rest_request(path, logger, local_session_key=local_session_key, session_key=remote_session_key,
|
|
method="POST", postargs=postargs,
|
|
raise_all_errors=True)
|
|
path = path + "/" + action
|
|
splunk_rest_request(path, logger, local_session_key=local_session_key, session_key=remote_session_key,
|
|
method="POST", raise_all_errors=True)
|
|
except ServerNotFoundError:
|
|
logger.exception("[pool={1}]Could not reach vc_splunk_forwarder={0}", host_path, pool_name)
|
|
status = False
|
|
except Exception as e:
|
|
message = "[pool={1}]Problem editing inputs on the remote vc_splunk_forwarder={0}: ".format(host_path,
|
|
pool_name) + str(e)
|
|
logger.exception(message)
|
|
status = False
|
|
return status
|
|
|
|
|
|
def delete_vcenter_stanza(vc_path, local_session_key, logger):
|
|
"""This function deletes vCenter stanza for given @vc_path.
|
|
@vc_path - url of vCenter to delete."""
|
|
# getting stanza to delete
|
|
vc_stanza = TAVMwareCollectionStanza.from_name(vc_path, "Splunk_TA_vmware_inframon", host_path=local_host_path,
|
|
session_key=local_session_key)
|
|
|
|
if not vc_stanza:
|
|
logger.error("Could not find stanza for stanza_name={0} cannot delete".format(vc_path))
|
|
raise RestError(404, "Could not find stanza for stanza_name={0} cannot delete".format(vc_path))
|
|
else:
|
|
vc = vc_stanza.target[0]
|
|
username = vc_stanza.username
|
|
logger.info("Deleting vc stanza_name=%s credentials for username=%s", vc_path, vc_stanza.username)
|
|
|
|
pool_name = vc_stanza.pool_name
|
|
|
|
if not vc_stanza.passive_delete():
|
|
logger.exception("[pool={1}]Failed to delete vc collection stanza={0}".format(vc_path, pool_name))
|
|
raise RestError(500, "Failed to delete vc collection stanza={0}".format(vc_path))
|
|
|
|
stored_cred = SplunkStoredCredential.from_name(SplunkStoredCredential.build_name(vc, username),
|
|
app="Splunk_TA_vmware_inframon", owner="nobody",
|
|
host_path=local_host_path, session_key=local_session_key)
|
|
if not stored_cred or not stored_cred.passive_delete():
|
|
logger.error("Could not delete obsolete credential it may linger")
|
|
|
|
return True
|
|
|
|
|
|
def delete_vcenter_forwarder_stanza(vc_path, local_session_key, pool_name, logger):
|
|
"""This function deletes forwarder stanza of given @vc_path
|
|
@vc_path - url of vCenter to delete."""
|
|
vc_forwarder_stanza = TAVMwareVCenterForwarderStanza.from_name(vc_path, "Splunk_TA_vmware_inframon", "nobody",
|
|
session_key=local_session_key,
|
|
host_path=local_host_path)
|
|
if vc_forwarder_stanza:
|
|
logger.info("Deleting vCenter forwarder stanza for the vc: {0}".format(vc_path))
|
|
|
|
vc_splunk_uri = vc_forwarder_stanza.host
|
|
vc_splunk_username = vc_forwarder_stanza.user
|
|
|
|
logger.info("vc_splunk_uri: {0}, vc_splunk_username: {1}".format(vc_splunk_uri, vc_splunk_username))
|
|
|
|
spl_stored_cred = SplunkStoredCredential.from_name(
|
|
SplunkStoredCredential.build_name(vc_splunk_uri, vc_splunk_username), app="Splunk_TA_vmware_inframon",
|
|
owner="nobody", host_path=local_host_path, session_key=local_session_key)
|
|
|
|
vc_splunk_password = ""
|
|
if spl_stored_cred:
|
|
vc_splunk_password = spl_stored_cred.clear_password
|
|
|
|
toggle_vc_inputs(vc_splunk_uri, vc_splunk_username, vc_splunk_password, vc_path,
|
|
local_session_key, pool_name, logger, disable=True)
|
|
|
|
logger.info("Deleting forwarder Credentials.")
|
|
|
|
if not vc_forwarder_stanza.passive_delete():
|
|
logger.error(
|
|
"[pool={2}]Failed to delete vCenter forwarder stanza:{0} for vc: {1}".format(vc_splunk_uri, vc_path,
|
|
pool_name))
|
|
else:
|
|
logger.info("[pool={2}]Forwarder stanza:{0} deleted for vc: {1}.".format(vc_splunk_uri, vc_path, pool_name))
|
|
|
|
if not spl_stored_cred:
|
|
logger.error("Credential Stanza of Forwarder for vc:{0} not found".format(vc_path))
|
|
return False
|
|
|
|
if not spl_stored_cred.passive_delete():
|
|
logger.error(
|
|
"Could not delete obsolete credential for vCenter forwarder:{0} it may linger".format(vc_splunk_uri))
|
|
else:
|
|
logger.info("Credential deleted for vCenter forwarder:{0}".format(vc_splunk_uri))
|
|
|
|
else:
|
|
logger.debug("No vCenter forwarder stanza found for vc: {0}.".format(vc_path))
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def delete_dcn_stanza(node_path, local_session_key, logger):
|
|
"""
|
|
|
|
:param node_path:
|
|
:param local_session_key:
|
|
:param logger:
|
|
:return: It will return true in case of successful deletion of dcn stanza
|
|
"""
|
|
node_stanza = HydraNodeStanza.from_name(node_path, "Splunk_TA_vmware_inframon", host_path=local_host_path,
|
|
session_key=local_session_key)
|
|
|
|
if node_stanza:
|
|
node_username = node_stanza.user
|
|
pool_name = node_stanza.pool_name
|
|
stored_cred = SplunkStoredCredential.from_name(
|
|
SplunkStoredCredential.build_name(node_stanza.host, node_username), app="Splunk_TA_vmware_inframon",
|
|
owner="nobody", host_path=local_host_path,
|
|
session_key=local_session_key)
|
|
|
|
if stored_cred:
|
|
node_password = stored_cred.clear_password
|
|
logger.info("Deleting obsolete credential for node:{0}".format(node_stanza.host))
|
|
if not stored_cred.passive_delete():
|
|
logger.error(
|
|
"Could not delete obsolete credential it may linger")
|
|
else:
|
|
logger.info(
|
|
"Credentials deleted successfully of node {0}:".format(node_stanza.host))
|
|
else:
|
|
node_password = None
|
|
|
|
if not node_stanza.passive_delete():
|
|
logger.error("[pool={1}]Failed to delete node {0}".format(node_path, pool_name))
|
|
raise RestError(500, "Failed to delete node {0}".format(node_path))
|
|
else:
|
|
logger.info("[pool={1}]Successfully deleted node: {0}".format(node_path, pool_name))
|
|
# disabling of inputs only takes place when node is successfully deleted.
|
|
# It will change after adding exceptions.
|
|
# for disabling all the inputs(heads), heads is given as Zero.
|
|
logger.info("Disabling inputs of deleted stanza: {0}".format(node_path))
|
|
enable_heads_on_dcn(node_username, node_password, 0, local_session_key, node_path, pool_name, logger)
|
|
|
|
return True
|
|
else:
|
|
logger.error(
|
|
"Failed to find node {0}, cannot delete it".format(node_path))
|
|
raise RestError(404, "Failed to find node {0}".format(node_path))
|
|
|
|
|
|
def set_conf_modification_time(pool_name, entity_type, local_session_key, logger):
|
|
""""""
|
|
pool_stanza = PoolStanza.from_name(pool_name, "Splunk_TA_vmware_inframon", host_path=local_host_path,
|
|
session_key=local_session_key)
|
|
if pool_stanza:
|
|
if entity_type == "node":
|
|
pool_stanza.node_modification_time = datetime.datetime.utcnow()
|
|
elif entity_type == "collection":
|
|
pool_stanza.collection_modification_time = datetime.datetime.utcnow()
|
|
if not pool_stanza.passive_save():
|
|
logger.error(
|
|
"[pool={1}]Couldn't set the conf modification time property for type:{0} of the pool:{1}".format(
|
|
entity_type,
|
|
pool_name))
|
|
else:
|
|
logger.info(
|
|
"[pool={1}]Updated the conf modification time property for type: {0} and pool: {1} ".format(entity_type,
|
|
pool_name))
|
|
|
|
else:
|
|
logger.error("Could not find pool stanza for given pool name:{0}".format(pool_name))
|
|
|
|
|
|
def enable_heads_on_dcn(username, password, heads, local_session_key, node_path, pool_name, logger):
|
|
"""
|
|
This function enables the head on dcn using given username, password, and local session key.
|
|
It will enable the number of heads given in @heads parameter and disable the rest of the heads.
|
|
So, when heads is given as zero, it will disable all the heads on that dcn.
|
|
:param username: splunk username
|
|
:param password: splunk password
|
|
:param heads: no. of heads to enable on dcn (if heads is given as Zero, then it will disable all the heads on dcn.)
|
|
:param local_session_key: session key of current session.
|
|
:param node_path: management port url of a dcn.
|
|
:return: it returns nothing.
|
|
|
|
"""
|
|
try:
|
|
remote_session_key = get_remote_session_key(username, password, local_session_key, node_path, logger)
|
|
except ServerNotFoundError:
|
|
logger.error("Could not find node=%s", node_path)
|
|
remote_session_key = None
|
|
except splunk.SplunkdConnectionException:
|
|
logger.error("Could not find splunkd on node=%s", node_path)
|
|
remote_session_key = None
|
|
except splunk.AuthenticationFailed:
|
|
logger.error("Could not log into splunkd on node=%s, credentials are definitely bad", node_path)
|
|
remote_session_key = None
|
|
except Exception as e:
|
|
logger.exception(
|
|
"could not log in to the node: {0} Exception occurred: {1} ".format(node_path, str(e)))
|
|
remote_session_key = None
|
|
|
|
if remote_session_key is None:
|
|
logger.error(
|
|
"[pool=%s]Could not log into node=%s with the credentials provided, cannot manage the heads on that node",
|
|
pool_name, node_path)
|
|
else:
|
|
enable_head_status = True
|
|
for counter in range(1, max_worker_process + 1):
|
|
input_name = "worker_process{0}".format(counter)
|
|
|
|
if counter <= int(heads):
|
|
action = "enable"
|
|
else:
|
|
action = "disable"
|
|
path = node_path.rstrip(
|
|
"/") + "/servicesNS/nobody/Splunk_TA_vmware_inframon/data/inputs/ta_vmware_collection_worker_inframon/" + input_name + "/" + action
|
|
try:
|
|
logger.info("Adjusting input with rest request on path=%s with session_key=%s", path,
|
|
remote_session_key)
|
|
splunk_rest_request(path, logger, local_session_key=local_session_key,
|
|
session_key=remote_session_key, method="POST",
|
|
raise_all_errors=True)
|
|
except ServerNotFoundError:
|
|
enable_head_status = False
|
|
logger.exception(
|
|
"Problem editing the number of worker inputs on the remote node={0}, Could not reach node.".format(
|
|
node_path))
|
|
except Exception as e:
|
|
enable_head_status = False
|
|
message = "Problem editing the number of worker inputs on the remote node={0}: ".format(
|
|
node_path) + str(e)
|
|
logger.exception(message)
|
|
|
|
if enable_head_status:
|
|
logger.info("[pool={0}]Successfully adjusted input on node:{1}".format(pool_name, node_path))
|
|
else:
|
|
logger.error("[pool={0}]Problem editing the number of worker inputs on the remote node={1}.".format(
|
|
pool_name, node_path))
|
|
|
|
|
|
def delete_template_stanza(template_name, local_session_key, logger):
|
|
"""
|
|
:param template_name: name of the template to be deleted.
|
|
:param local_session_key: session key of the current session
|
|
:return: returns true if everything goes fine, It will delete the template stanza from inframon_ta_vmware_template.conf, if failed then it will throw an exception.
|
|
"""
|
|
template_stanza = TemplateStanza.from_name(template_name, "Splunk_TA_vmware_inframon", host_path=local_host_path,
|
|
session_key=local_session_key)
|
|
|
|
if template_stanza:
|
|
if not template_stanza.passive_delete():
|
|
logger.error("[pool={0}]Failed to delete the template stanza={0}".format(template_name))
|
|
raise RestError(500, "Failed to delete the template stanza={0}".format(template_name))
|
|
else:
|
|
logger.info("[pool={0}]template stanza successfully deleted for: {0}".format(template_name))
|
|
else:
|
|
logger.error("[Delete Pool] Failed to find the template stanza={0}, cannot delete it", template_name)
|
|
raise RestError(404, "Failed to find the template stanza={0}".format(template_name))
|
|
|
|
return True
|
|
|
|
|
|
def clear_session(node_path, username, password, local_session_key, logger):
|
|
"""
|
|
It clears all the stanzas of inframon_hydra_session.conf for given node_path(uri of Node/DCN)
|
|
:param node_path: node uri for clearing cache and session
|
|
:param username: username of node
|
|
:param password: password of node
|
|
:param local_session_key: session key of current session
|
|
:param logger:
|
|
:return: it returns nothing
|
|
"""
|
|
try:
|
|
remote_session_key = get_remote_session_key(username, password, local_session_key, node_path, logger)
|
|
except ServerNotFoundError:
|
|
logger.error("Could not find node=%s", node_path)
|
|
remote_session_key = None
|
|
except splunk.SplunkdConnectionException:
|
|
logger.error("Could not find splunkd on node=%s", node_path)
|
|
remote_session_key = None
|
|
except splunk.AuthenticationFailed:
|
|
logger.error("Could not log into splunkd on node=%s, credentials are definitely bad", node_path)
|
|
remote_session_key = None
|
|
except Exception as e:
|
|
remote_session_key = None
|
|
logger.exception(e)
|
|
|
|
if remote_session_key is None:
|
|
logger.error(
|
|
"Could not log into node=%s with the credentials provided, cannot clear session on a node.",
|
|
node_path)
|
|
else:
|
|
session_stanzas = HydraSessionStanza.all(host_path=node_path, sessionKey=remote_session_key)
|
|
session_stanzas = session_stanzas.filter_by_app("Splunk_TA_vmware_inframon")
|
|
session_stanzas._owner = "nobody"
|
|
logger.info("No. of session:{0} on Node:{1}".format(len(session_stanzas), node_path))
|
|
for session_stanza in session_stanzas:
|
|
session_name = session_stanza.name
|
|
if not session_stanza.passive_delete():
|
|
logger.error("Could not able to delete session_stanza={0}".format(str(session_stanza)))
|
|
else:
|
|
logger.info("session of: {0} for node: {1} successfully deleted.".format(session_name, node_path))
|
|
|
|
|
|
def get_node_password(node_stanza, local_session_key, logger):
|
|
"""
|
|
|
|
:param node_stanza: stanza of node
|
|
:param local_session_key:
|
|
:return: it returns the credentials for the node of given node stanza
|
|
"""
|
|
|
|
stored_cred = SplunkStoredCredential.from_name(
|
|
SplunkStoredCredential.build_name(node_stanza.host, node_stanza.user), app="Splunk_TA_vmware_inframon",
|
|
owner="nobody", host_path=local_host_path, session_key=local_session_key)
|
|
|
|
password = ""
|
|
if stored_cred:
|
|
password = stored_cred.clear_password
|
|
else:
|
|
logger.error("Failed to find password for: {0} ".format(node_stanza.host))
|
|
|
|
return password
|
|
|
|
|
|
def prepare_field_list(field_dict, ui_fields, field_type, logger):
|
|
"""
|
|
|
|
:param field_dict: dictionary of field mapping
|
|
:param ui_fields: List of UI fields
|
|
:param field_type: Type of field
|
|
:return: it maps the ui field with appropriate backend inv fields, and will return the backend names of
|
|
corresponding UI fields.
|
|
"""
|
|
inv_fields_set = set()
|
|
|
|
for field in ui_fields:
|
|
field_detail = field_dict[field_type][field]
|
|
if field_detail["type"] == "inv":
|
|
inv_fields_set.update(field_detail["req_metrics"])
|
|
|
|
inv_fields = sorted(inv_fields_set)
|
|
|
|
return inv_fields
|