Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 1512 lines (1323 sloc) 55.3 KB
#!/usr/bin/env python
######################################################################
# Loggly Syslog configuration script.
#
# This script automatically configures a syslog-ng or rsyslog
# setup such that it sends all logs from this system to Loggly.
#
# For this to work you must have an account on the Loggly system. Sign
# up for one at http://www.loggly.com.
#
# For best results the script should be run with superuser privileges.
#
# (c) Copyright Loggly 2013.
######################################################################
from __future__ import with_statement
import os, os.path
import platform
import re
import sys
import getpass
from distutils.version import StrictVersion
import time
from datetime import datetime
import tempfile
try:
import urllib.request as urllib_request
except ImportError:
import urllib2 as urllib_request
try:
import json
except ImportError:
json = None
import uuid
import base64
import socket
import subprocess
from optparse import OptionParser, SUPPRESS_HELP
import traceback
#Constants
TEMP_PREFIX = 'temp'
ROOT_USER = 1
NON_ROOT_USER = 2
MINIMUM_SUPPORTED_PYTHON_VERSION = '2.6'
VERIFICATION_SLEEP_INTERVAL = 240
VERIFICATION_SLEEP_INTERVAL_PER_ITERATION = 5
OS_UBUNTU = 1
OS_FEDORA = 2
OS_RHEL = 3
OS_CENTOS = 4
OS_UNSUPPORTED = -1
PROD_SYSLOG_NG = 1
PROD_RSYSLOG = 2
PROD_UNSUPPORTED = -1
LOGGLY_DOMAIN = "gen2.loggly.com"
LOGGLY_SYSLOG_SERVER = "logs-01.loggly.com"
LOGGLY_SYSLOG_PORT = 514
DISTRIBUTION_ID = "41058"
LOGGLY_CONFIG_FILE = "22-loggly.conf"
LOGGLY_ENV_DETAILS_FILE = "env_details.txt"
LOGGLY_BASH_SCRIPT = 'configure-syslog.%s.sh' % os.getpid()
PROCESS_ID = -1
STR_PYTHON_FAIL_MESSAGE = '''
Python version check fails: Installed version is "%s. \
Minimum required version is %s.
'''.strip()
STR_MULTIPLE_SYSLOG_MESSAGE = "Multiple syslogd are running."
STR_AUTHTOKEN_NOTFOUND_MESSAGE = "No Customer Tokens were found."
STR_AUTHENTICATION_FAIL_MESSAGE = "Authentication fail for user %s"
VERIFICATION_FAIL_MESSAGE = '''
Loggly verification failed. Please visit \
http://loggly.com/docs/sending-logs-unixlinux-system-setup/ for more information.
'''.strip()
STR_EXIT_MESSAGE = '''
This environment (OS : %s) is not supported by the Loggly Syslog \
Configuration Script. Please visit \
http://loggly.com/docs/sending-logs-unixlinux-system-setup/ \
for more information.
'''
STR_NO_SYSLOG_MESSAGE = "\nSupported syslog type/version not found."
STR_ERROR_MESSAGE = '''
Can not automatically re-configure syslog for this Linux distribution.
Use the help option for instructions to manually re-configure syslog for Loggly.
'''.strip()
STR_SYSLOG_DAEMON_MESSAGE = '''
Syslog daemon (%s) is not running. Please start %s daemon and try again.
'''
REST_URL_GET_AUTH_TOKEN = "http://%s.%s/apiv2/customer"
REST_URL_GET_SEARCH_ID = "http://%s.%s/apiv2/search?q=%s&from=-2h&until=now&size=10"
REST_URL_GET_SEARCH_RESULT = "http://%s.%s/apiv2/events?rsid=%s"
USER_NAME_TEXT = "Enter the username that you use to log into your loggly account."
ACCOUNT_NAME_TEXT = '''
Enter your Loggly account name. This is your subdomain. For example if \
you login at mycompany.loggly.com,
your account name is mycompany.
'''.lstrip()
INSTALLATION_COMPLETED_TEXT = "Configuration script completed."
_LOG_SOCKET = None
OUR_PROGNAME = "configure-syslog"
OUR_VERSION = 1
LOGGLY_AUTH_TOKEN = "1ec4e8e1-fbb2-47e7-929b-75a1bff5ffe0"
RSYSLOG_PROCESS = "rsyslogd"
SYSLOG_NG_PROCESS = "syslog-ng"
min_supported_syslog_versions = {
PROD_SYSLOG_NG: "1.6",
PROD_RSYSLOG: "1.19",
}
default_config_file_name = {
PROD_SYSLOG_NG: "/etc/syslog-ng/syslog-ng.conf",
PROD_RSYSLOG: "/etc/rsyslog.conf",
}
configuration_text = {
PROD_SYSLOG_NG:
'''
# -------------------------------------------------------
# Syslog Logging Directives for Loggly (%s.loggly.com)
# -------------------------------------------------------
%s
template LogglyFormat { template("<${PRI}>1 ${ISODATE} ${HOST} ${PROGRAM} \
${PID} ${MSGID} [%s@%s] $MSG\\n");};
destination d_loggly { tcp("%s" port(%s) template(LogglyFormat) flush_timeout(1000) frac_digits(3)); };
log { source(%s); destination(d_loggly); };
# -------------------------------------------------------
# End of Syslog Logging Directives for Loggly
# -------------------------------------------------------
''',
PROD_RSYSLOG:
'''
# -------------------------------------------------------
# Syslog Logging Directives for Loggly (%s.loggly.com)
# -------------------------------------------------------
# Define the template used for sending logs to Loggly. Do not change this format.
$template LogglyFormat,"<%%pri%%>%%protocol-version%% %%timestamp:::date-rfc3339%% \
%%HOSTNAME%% %%app-name%% %%procid%% %%msgid%% [%s@%s] %%msg%%"
# Send messages to Loggly over TCP using the template.
*.* @@%s:%s;LogglyFormat
# -------------------------------------------------------
# End of Syslog Logging Directives for Loggly
# -------------------------------------------------------
'''
}
USER = None
SUBDOMAIN = None
SYSLOG_NG_SOURCE = 's_loggly'
SYSLOG_NG_SOURCE_TEXT_3_2 = '''
source %s {
\tunix-stream("/dev/log");
\tinternal();
\tfile("/proc/kmsg" program_override("kernel: "));
};
'''.strip()
SYSLOG_NG_SOURCE_TEXT_ABOVE_3_2 = '''
source %s {
\tsystem();
\tinternal();
};
'''.strip()
LOGGLY_HELP = '''
Instructions to manually re-configure syslog for Loggly
=======================================================
1. Configure the version of syslog you're running. More details are available http://www.loggly.com/docs/sending-logs-unixlinux-system-setup/
rsyslog
-------
-Edit your rsyslog.conf file, usually found in /etc/rsyslog.conf, \
and add following lines at bottom of the configuration file:
### Syslog Logging Directives for Loggly (%(subdomain)s.loggly.com) ###
$template LogglyFormat,"<%%pri%%>%%protocol-version%% \
%%timestamp:::date-rfc3339%% %%HOSTNAME%% %%app-name%% %%procid%% %%msgid%% \
[%(token)s@%(dist_id)s] %%msg%%"
*.* @@%(syslog_server)s:%(syslog_port)s;LogglyFormat
### END Syslog Logging Directives for Loggly (%(subdomain)s.loggly.com) ###
syslog-ng
---------
-Edit your syslog-ng.conf file, usually found in /etc/syslog-ng/syslog-ng.conf:
- Instructions for syslog-ng version above 3.2
-- Look for source with internal() directive. If no source found with \
internal() directive then add following lines at bottom of the file:
### Syslog Logging Directives for Loggly (%(subdomain)s.loggly.com) ###
\tsource %(syslog_source)s {
\t\tsystem();
\t\tinternal();
\t\tfile("/path/to/your/file" follow_freq(1) flags(no-parse));
\t};
-If version of syslog-ng is 3.2 or below and source with internal() is not \
present then add the following lines at the bottom of the file
### Syslog Logging Directives for Loggly (%(subdomain)s.loggly.com) ###
\tsource %(syslog_source)s {
\t\tinternal();
\t\tunix-stream("/dev/log");
\t\tfile("/path/to/your/file" follow_freq(1) flags(no-parse));
\t};
-All versions: Append the following lines at the end of configuration file. The \
source_name must match the name of the source with internal() e.g. %(syslog_source)s.
template LogglyFormat { template("<${PRI}>1 ${ISODATE} ${HOST} ${PROGRAM} \
${PID} ${MSGID} [%(token)s@%(dist_id)s] $MSG\\n");};
destination d_loggly { tcp("%(syslog_server)s" port(%(syslog_port)s) template(LogglyFormat) flush_timeout(1000) frac_digits(3)); };
log { source(%(syslog_source)s); destination(d_loggly); };
### END Syslog Logging Directives for Loggly (%(subdomain)s.loggly.com) ###
-WARNING: if a source with internal() is already present then do not add the new \
source. The new source will break configurations.
2. Once you are done configuring syslog-ng or rsyslog, restart it
Example: /etc/init.d/syslog-ng restart
3. Send some data through syslog-ng or rsyslog to have it forwarded to your Loggly account
logger "loggly is better than a bee in your aunt\'s bonnet"
'''.strip()
# log priorities...
LOG_PRIORITIES = {
"emerg": 0, "alert": 1, "crit": 2, "error": 3,
"warning": 4, "notice": 5, "info": 6, "debug": 7
}
# log facilities...
# (avoiding a dict comprehension for Python 2.6 compat)
LOG_FACILITIES = dict([(k, v << 3) for k, v in {
"kern": 0, "user": 1, "mail": 2, "daemon": 3,
"auth": 4, "syslog": 5, "lpr": 6, "news": 7,
"uucp": 8, "cron": 9, "security": 10, "ftp": 11,
"ntp": 12, "logaudit": 13, "logalert": 14, "clock": 15,
"local0": 16, "local1": 17, "local2": 18, "local3": 19,
"local4": 20, "local5": 21, "local6": 22, "local7": 23
}.items()])
PYTHON_FAIL = "pythonfail"
PS_FAIL = "psfail"
OS_FAIL = "osfail"
SYSLOG_FAIL = "syslogfail"
MULTPLE_SYSLOG_RUNNING = "multiple_syslog_running"
AUTH_TOKEN_FAIL = "authtoken_fail"
VERIFICATION_FAIL = "verification_fail"
AUTHENTICATION_FAIL = "authentication_fail"
LOGGLY_QA = []
# Available options for LOGGLY_QA are...
# "pythonfail" --> Python version check fail
# "psfail" --> Syslog daemon is not running
# "osfail" --> Unsupported os
# "syslogfail" --> Supported_syslog_versions not found
# "multiple_syslog_running" --> Multiple Syslog Running
# "authtoken_fail" --> Authtoken not found
# "verification_fail" --> Syslog configuration fail
# "authentication_fail" --> Invalid username or password
def printLog(message):
print(message)
def printMessage(message):
printLog("\n****************************"
"*********************************")
printLog("****** %s "
"Loggly Syslog Configuration Script ******" % message)
printLog("**********************************"
"***************************\n")
def printEnvironment(current_environment):
"""
Print environment details on console
"""
printLog("Operating System: %s-%s(%s)" %
(current_environment['distro_name'],
current_environment['version'],
current_environment['id']))
printLog("Syslog versions:")
if current_environment['syslog_versions']:
for i, version in enumerate(current_environment['syslog_versions'], 1):
line = "\t%d. %s(%s)" % (i, version[0], version[1])
printLog(line)
else:
printLog("\tNo Syslog Version Found......")
def sendEnvironment(data):
printLog("Sending environment details to Loggly Server.")
log(data)
def get_python_version_string():
return ".".join(map(str, sys.version_info))
def sys_exit(reason = None):
"""
If script fails, send environment details with reason for failure to loggly
"""
current_environment = get_environment_details()
data = {
"operating_system": current_environment['operating_system'],
"syslog_versions": current_environment['syslog_versions'],
"python_version": get_python_version_string(),
"reason":reason,
"username":USER,
"subdomain": SUBDOMAIN
}
sendEnvironment(data)
printMessage("Aborting")
sys.exit(-1)
def usr_input(st):
"""
Take user input
"""
sys.stdin = open("/dev/tty")
get_input = ''
try:
get_input = raw_input
except NameError:
get_input = input
st = get_input(st)
return st
def version_compare(version1, version2):
"""
Function will return following values.
-1 : version1 is less than version2
0 : version1 equals to version2
1 : version1 is greater than version2
"""
cmp_ex = lambda x, y: StrictVersion(x).__cmp__(y)
return cmp_ex(version1, version2)
def get_os_id(os_name):
"""
Get OS ID for corresponding OS present on machine
"""
return {
'ubuntu': OS_UBUNTU,
'fedora': OS_FEDORA,
'red hat enterprise linux server': OS_RHEL,
'centos': OS_CENTOS,
'debian': OS_UBUNTU,
}.get(os_name.lower(), OS_UNSUPPORTED)
def get_syslog_id(product_name):
"""
Get syslog id from installed syslog product
"""
return {
'syslog-ng': PROD_SYSLOG_NG,
'rsyslog': PROD_RSYSLOG,
}.get(product_name.lower(), PROD_UNSUPPORTED)
def get_syslog_process_name(product_name):
"""
Get syslog process name
"""
return {
'syslog-ng': SYSLOG_NG_PROCESS,
'rsyslog': RSYSLOG_PROCESS,
}.get(product_name.lower(), PROD_UNSUPPORTED)
def get_syslog_version(verify_config_paths=False):
"""
Guess the syslog daemon and version number,
returns a singleton list containing a tuple: [(daemon, version_string)]
if verify_config_paths is set, this will also verify the configuration file
and/or paths are present on this system
"""
SYSLOG_PATHS = [
# (syslog type, command, conf path, conf.d path)
("rsyslog", "rsyslogd", "-v", "/etc/rsyslog.conf", "/etc/rsyslog.d/"),
("syslog-ng", "syslog-ng", "--version", "/etc/syslog-ng/syslog-ng.conf", "/etc/syslog-ng/")
]
for s in SYSLOG_PATHS:
p = subprocess.Popen(s[1] + ' ' + s[2], shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
p.wait()
if p.returncode != 0:
continue
version_line = p.stdout.readlines()[0]
if verify_config_paths:
if not os.path.isfile(s[3]) or not os.path.isdir(s[4]):
continue
# extract the version number from the daemon's version report,
# only cares about the major and minor version numbers and ignores
# the point number.
version_pattern = r'%s (\d+\.+\d)' % s[1]
version_string = re.search(version_pattern,
version_line.decode('utf-8')).group(1)
return [(s[0], version_string)]
return []
def get_user_type():
"""
Return user type
"""
if os.getuid() == 0:
return ROOT_USER
else:
printLog("Script not started as root")
return NON_ROOT_USER
def try_int(x):
try:
return int(x)
except ValueError:
return x
def version_tuple(v):
return list(map(try_int, v.split('.')))
def greater_version(minimum, version):
return version_tuple(version) >= version_tuple(minimum)
def get_environment_details():
"""
Get Distro Name, Distro ID, Version and ID.
"""
printLog("Reading environment details....")
distribution = platform.linux_distribution()
distro_name, version, version_id = distribution
distro_id = get_os_id(distro_name)
return {
'distro_name': distro_name,
'distro_id': distro_id,
'version': version,
'id': version_id,
'syslog_versions': get_syslog_version(),
'supported_syslog_versions': {},
'operating_system': "%s-%s(%s)" % distribution
}
def perform_sanity_check(current_environment):
"""
Performing quick check of OS and Syslog
"""
printLog("Performing sanity check....")
syslog_versions = {}
for (syslog_type, syslog_version)\
in current_environment['syslog_versions']:
syslog_id = get_syslog_id(syslog_type)
if greater_version(min_supported_syslog_versions.get(syslog_id),
syslog_version):
syslog_versions[syslog_type] = syslog_version
if SYSLOG_FAIL in LOGGLY_QA or not syslog_versions:
printLog(STR_NO_SYSLOG_MESSAGE)
printLog(STR_ERROR_MESSAGE)
sys_exit(reason = STR_NO_SYSLOG_MESSAGE)
#Check whether multiple syslogd running or not
if len(syslog_versions) > 1 or MULTPLE_SYSLOG_RUNNING in LOGGLY_QA:
index = 0
running_syslog_count = 0
for (syslog_name, syslog_version) in syslog_versions.items():
if check_syslog_service_status(syslog_name):
running_syslog_count += 1
index += 1
printLog("\t%d. %s(%s)" %
(index, syslog_name, syslog_version))
if running_syslog_count > 1 or MULTPLE_SYSLOG_RUNNING in LOGGLY_QA:
printLog(STR_MULTIPLE_SYSLOG_MESSAGE)
printLog(STR_ERROR_MESSAGE)
sys_exit(reason = STR_MULTIPLE_SYSLOG_MESSAGE)
current_environment['supported_syslog_versions'] = syslog_versions
printLog("Sanity Check Passed. Your environment is supported.")
def find_syslog_process():
"""
Returns the running syslog type (syslog-ng, rsyslog)
and the PID of the running process.
"""
syslog_ps_commands = [
("ps -fU syslog | grep syslog | grep -v grep"),
("ps -ef | grep -e syslog-ng -e rsyslog -e syslogd "
"| grep -v grep | grep -v supervising")
]
for ps_command in syslog_ps_commands:
errorfname = TEMP_PREFIX + ".cmdout"
errorfile = open(errorfname, 'w')
nullfile = open(os.devnull)
p = subprocess.Popen(
ps_command, shell=True,
stdin=nullfile,
stdout=subprocess.PIPE,
stderr=errorfile
)
results = p.stdout.read().strip()
p.stdout.close()
errorfile.close()
p.poll()
try:
os.remove(errorfname)
except (IOError, OSError): pass
if results:
#For python version 3 and above, reading binary data, not str,
#so we need to decode the output first:
reslines = results.split('\n')
if len(reslines) == 1:
ps_out_fields = reslines[0].split()
pid = int(ps_out_fields[1])
progname = ps_out_fields[7]
if '/' in progname:
progname = progname.split('/')[-1]
return progname, pid
return None, 0
def check_syslog_service_status(syslog_type):
"""
Checks for syslog daemon status
"""
process_name, pid = find_syslog_process()
if process_name is None:
pass
else:
global PROCESS_ID
PROCESS_ID = pid
syslog_process_name = get_syslog_process_name(syslog_type)
if syslog_process_name == PROD_UNSUPPORTED:
return False
elif syslog_process_name == process_name:
return True
return False
def product_for_configuration(current_environment,
check_syslog_service = True):
"""
Checks for multiple syslog daemon installed.
"""
user_choice = 0
supported_syslog_versions = current_environment['supported_syslog_versions']
if len(supported_syslog_versions) > 1:
printLog("Multiple versions of syslog detected on your system.")
index = 0
for (syslog_name, syslog_version)\
in supported_syslog_versions.items():
index += 1
printLog("\t%d. %s(%s)" %
(index, syslog_name, syslog_version))
for _ in range(5):
try:
str_msg = ("Please select (1-" + str(index) + ") to specify "
"which version of syslog you'd like configured. "
"(Default is 1): ")
user_choice = int(usr_input(str_msg)) - 1
break
except ValueError:
printLog ("Not a valid response. Please retry.")
if user_choice < 0 or user_choice > (index):
printLog(("Invalid choice entered. "
"Continue with default value."))
user_choice = 0
syslog_type = list( supported_syslog_versions.keys())[user_choice]
service_status = check_syslog_service_status(syslog_type)
if check_syslog_service:
if not service_status or PS_FAIL in LOGGLY_QA:
printLog(STR_SYSLOG_DAEMON_MESSAGE %
(syslog_type, syslog_type))
sys_exit(reason = STR_SYSLOG_DAEMON_MESSAGE %
(syslog_type, syslog_type))
printLog("Configuring %s-%s" %
(syslog_type, supported_syslog_versions[syslog_type]))
return syslog_type
def get_syslog_ng_source(default_config_file_path):
"""
get source[that contain internal()] from config_file of syslog-ng.
"""
source = ''
command = r"sed -n -e '/[^#]internal\(\)/p' %s" % default_config_file_path
output = os.popen(command).read()
if output and len(output) > 0:
command = (r"sed -n -e '/^\s*source\s*.*"
r"{/,/internal\(\)/p' %s" % default_config_file_path)
output = os.popen(command).read()
if output and len(output) > 0:
compiled_regex = re.compile(r'source\s+(\S+).*[^#]\s*internal',
re.MULTILINE | re.IGNORECASE)
output_list = output.split('}')
for st in output_list:
result = compiled_regex.findall(st.replace('\n',''))
if result:
return result[0]
return source
def get_installed_syslog_configuration(syslog_id):
"""
Fetching installed/configured syslog details
"""
default_directory = ''
auth_token = ''
source = ''
printLog("Reading default configuration directory path from (%s)."
% default_config_file_name.get(syslog_id))
if syslog_id == PROD_RSYSLOG:
include_pattern = r"^\s*[^#]\s*IncludeConfig\s+([\S]+/)"
auth_token_pattern = (r"^\s*[^#]*\s*template\sLogglyFormat.*"
r"\[([a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]"
r"{4}-[a-z0-9]{4}-[a-z0-9]{12}).*")
elif syslog_id == PROD_SYSLOG_NG:
include_pattern = r"^\s*[^#]\s*Include\s+([\S]+/)"
auth_token_pattern = (r"^\s*template\s+t_LogglyFormat\s*.*"
r"\[([a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]"
r"{4}-[a-z0-9]{4}-[a-z0-9]{12}).*\}")
else:
return { "path": default_directory,
"token": auth_token,
"source": source }
include_compiled_regex = re.compile(include_pattern,
re.MULTILINE | re.IGNORECASE)
auth_token_compiled_regex = re.compile(auth_token_pattern,
re.MULTILINE | re.IGNORECASE)
with open(default_config_file_name.get(syslog_id), "r") as text_file:
for line in text_file:
if not default_directory:
include_match_grp = include_compiled_regex.match(line.rstrip('\n'))
if include_match_grp:
default_directory = include_match_grp.group(1)
default_directory = default_directory.lstrip('"').rstrip('"')
if not auth_token:
auth_token_match_grp = auth_token_compiled_regex.match\
(line.rstrip('\n'))
if auth_token_match_grp:
auth_token = auth_token_match_grp.group(1)
if syslog_id == PROD_SYSLOG_NG:
source = get_syslog_ng_source(default_config_file_name.get(syslog_id))
return { "path": default_directory, "token": auth_token, "source": source }
def write_configuration(syslog_name_for_configuration,
authorization_details, user_type, noconfirm=False):
"""
Function to create/modify configuration file
"""
printLog("Reading configuration directory path....")
syslog_id = get_syslog_id(syslog_name_for_configuration)
syslog_configuration_details = get_installed_syslog_configuration(syslog_id)
config_file = default_config_file_name.get(syslog_id)
if len(syslog_configuration_details.get("path")) > 0:
config_file = os.path.join(syslog_configuration_details.get("path"),
LOGGLY_CONFIG_FILE)
printLog(("The Loggly Syslog Configuration Script will "
"create a new configuration file %s") % config_file)
#(os.path.join
# (syslog_configuration_details.get("path"),
# LOGGLY_CONFIG_FILE)))
create_loggly_config_file(syslog_id,
syslog_configuration_details,
authorization_details, user_type, noconfirm)
return config_file
else:
modify_syslog_config_file(syslog_id,
syslog_configuration_details,
authorization_details, user_type, noconfirm)
return config_file
def remove_syslog_ng_source(default_config_file):
command = (r"sed -n -e '/^\s*source\s\s*%s\s*{/,/};/p' %s" %
(SYSLOG_NG_SOURCE, default_config_file))
output = os.popen(command).read()
if output and len(output) > 0:
st = output.rstrip().replace('\n', '\\n#')
os.popen((r"sed -i '/^\s*source\s\s*%s\s*{/,/};/c #%s' %s" %
(SYSLOG_NG_SOURCE, st, default_config_file)))
def remove_configuration(syslog_name_for_configuration):
"""
Remove configuration files 22-loggly.conf and
comment configuration settings in default config file
"""
syslog_id = get_syslog_id(syslog_name_for_configuration)
syslog_configuration_details = get_installed_syslog_configuration(syslog_id)
default_config_file = default_config_file_name.get(syslog_id)
if len(syslog_configuration_details.get("path")) > 0:
loggly_file_path = os.path.join(
syslog_configuration_details.get("path"),
LOGGLY_CONFIG_FILE)
if os.path.exists(loggly_file_path):
printLog("Removing configuration file %s" % loggly_file_path)
os.remove(loggly_file_path)
printLog("Removing configuration settings from file %s for %s" % (
default_config_file, syslog_name_for_configuration))
if syslog_name_for_configuration == 'rsyslog':
os.popen((r"sed -i 's/^\s*$template\s\s*LogglyFormat/"
"#$template LogglyFormat/g' %s" % default_config_file))
pattern = (r"s/^\s*\*\.\*.*@@{0}:{1};LogglyFormat/"
r"#*.* @@{0}:{1};LogglyFormat/g").format(
LOGGLY_SYSLOG_SERVER, LOGGLY_SYSLOG_PORT)
os.popen("sed -i '%s' %s" % (pattern, default_config_file))
elif syslog_name_for_configuration == 'syslog-ng':
os.popen((r"sed -i 's/^\s*template\s\s*LogglyFormat/"
r"#template LogglyFormat/g' %s" % default_config_file))
os.popen((r"sed -i 's/^\s*destination\s\s*d_loggly/"
r"#destination d_loggly/g' %s" % default_config_file))
output = os.popen((r'grep -P "^\s*log\s*{\s*source\(.*\);'
r'\s*destination\(d_loggly\);\s*};" -o %s'
% default_config_file)).read().rstrip()
if output and len(output) > 0:
os.popen((r"sed -i 's/^\s*{0}/#{0}/g' {1}".format
(output, default_config_file)))
remove_syslog_ng_source(default_config_file)
def login():
"""
Ask for Loggly credentials
"""
printLog("Reading Loggly credentials from user....")
printLog(USER_NAME_TEXT)
user = usr_input("Loggly Username [%s]: " % getpass.getuser())
if not user:
user = getpass.getuser()
if user:
pprompt = lambda: (getpass.getpass("Password for %s: " % user))
password = pprompt()
for _ in range(2):
if not password:
password = pprompt()
else:
printLog(ACCOUNT_NAME_TEXT)
msg = "Loggly Account Name [%s]:" % user
subdomain = usr_input(msg).lower()
if len(subdomain) <= 0 :
subdomain = user
global USER
global SUBDOMAIN
USER = user
SUBDOMAIN = subdomain
return user, password, subdomain
printLog("\nLoggly credentials not provided after maximum attempts.")
printMessage("Aborting")
sys.exit()
def get_json_data(url, user, password):
"""
Retrieve Customer Token and Distribution ID from Loggly account
"""
try:
if AUTHENTICATION_FAIL in LOGGLY_QA:
raise urllib_request.HTTPError(None, 401, None, None, None)
req = urllib_request.Request(url)
req.add_header("Accept", "application/json")
req.add_header("Content-type", "application/json")
user_passwd = base64.b64encode((user + ":" + password).encode('utf-8'))
req.add_header("Authorization",
"Basic " + str(user_passwd.rstrip().decode("utf-8")))
return json.loads(urllib_request.urlopen(req).read().decode("utf-8"))
except urllib_request.HTTPError, e:
if e.code == 401:
msg = STR_AUTHENTICATION_FAIL_MESSAGE % USER
else:
msg = str(e)
printLog("%s" % msg)
sys_exit(reason = "%s" % msg)
except urllib_request.URLError, e:
printLog("%s" % e)
sys_exit(reason = "%s" % e)
except Exception, e:
printLog("Exception %s" % e)
sys_exit(reason = "%s" % e)
def get_auth(loggly_user, loggly_password, loggly_subdomain):
url = (REST_URL_GET_AUTH_TOKEN % (loggly_subdomain, LOGGLY_DOMAIN))
data = get_json_data(url, loggly_user, loggly_password)
auth_tokens = data["tokens"]
if not auth_tokens or AUTH_TOKEN_FAIL in LOGGLY_QA:
printLog(STR_AUTHTOKEN_NOTFOUND_MESSAGE)
sys_exit(reason = STR_AUTHTOKEN_NOTFOUND_MESSAGE)
return auth_tokens
def get_auth_token(loggly_user, loggly_password, loggly_subdomain):
"""
Create the request object and set some headers
"""
try:
if loggly_user and loggly_password:
auth_tokens = get_auth(loggly_user,
loggly_password,
loggly_subdomain)
# use the last token returned
token = auth_tokens[-1]
printLog('\nThis system is now configured to use '
'\"%s\" as its Customer Token.\n' % token)
return token
else:
printLog("Loggly credentials could not be verified.")
sys_exit(reason = "Loggly credentials could not be verified.")
except Exception, e:
printLog("Exception %s" % e)
sys_exit(reason = "%s" % e)
def get_selected_syslog_version(syslog_id, syslog_versions):
for (syslog_name, syslog_version) in syslog_versions:
sys_id = get_syslog_id(syslog_name)
if sys_id == syslog_id:
return float(syslog_version)
def syslog_config_file_content(syslog_id, source, authorization_details):
"""
Creating syslog content for configuring Loggly
"""
content = ""
if syslog_id == PROD_RSYSLOG:
content = configuration_text.get(syslog_id) % (SUBDOMAIN,
authorization_details.get("token"),
authorization_details.get("id"),
LOGGLY_SYSLOG_SERVER, LOGGLY_SYSLOG_PORT)
elif syslog_id == PROD_SYSLOG_NG:
printLog("Reading configured source from (%s) file."
% default_config_file_name.get(syslog_id))
configured_source = source
source_created = ''
if len(configured_source) <= 0:
syslog_version = get_selected_syslog_version(syslog_id, get_syslog_version())
if syslog_version > float(3.2):
source_created = (SYSLOG_NG_SOURCE_TEXT_ABOVE_3_2
% SYSLOG_NG_SOURCE)
else:
source_created = SYSLOG_NG_SOURCE_TEXT_3_2 % SYSLOG_NG_SOURCE
configured_source = SYSLOG_NG_SOURCE
content = configuration_text.get(syslog_id) % (SUBDOMAIN,
source_created,
authorization_details.get("token"),
authorization_details.get("id"),
LOGGLY_SYSLOG_SERVER,
LOGGLY_SYSLOG_PORT,
configured_source)
else:
printLog("Failed to create content for syslog id %s\n" % syslog_id)
sys_exit(reason = ("Failed to create content for syslog id %s"
% syslog_id))
return content + "\n"
def create_bash_script(content):
"""
If user is not ROOT user then create bash script
"""
file_path = os.path.join(os.getcwd(), LOGGLY_BASH_SCRIPT)
config_file = open(file_path, "w")
config_file.write(content)
config_file.close()
#Remove invalid argument
printLog(("Current user is not root user. Run script %s as root then "
"restart the syslog service"
% file_path))
def confirm(question):
for _ in range(5):
user_input = usr_input(question + ' [Yes|No]: ').lower()
if user_input in ['yes', 'ye', 'y']:
return True
elif user_input in ['no', 'n']:
return False
elif user_input:
printLog("Not a valid input. Please retry.")
def create_loggly_config_file(syslog_id, syslog_configuration_details,
authorization_details, user_type, noconfirm=False):
"""
Create Loggly configuration file
"""
file_path = os.path.join(os.getenv("HOME"), LOGGLY_CONFIG_FILE)
printLog("Creating configuration file at %s" % file_path)
command_content = ""
content = syslog_config_file_content(syslog_id,
syslog_configuration_details.get("source"),
authorization_details)
try:
config_file = open(file_path, "w")
config_file.write(content)
config_file.close()
destfile = os.path.join(syslog_configuration_details.get("path"),
LOGGLY_CONFIG_FILE)
if user_type == NON_ROOT_USER:
# print Instructions...
content = "mv -f %s %s\n%s" % (file_path, destfile, command_content)
create_bash_script(content)
else:
if os.path.isfile(destfile):
msg = ("Loggly configuration file (%s) is already present. "
"Do you want to overwrite it?" % destfile)
move = noconfirm or confirm(msg)
if move:
os.popen("mv -f %s %s" % (file_path, destfile))
return
elif move is False:
printMessage("Finished")
sys.exit(0)
elif move is None:
printLog("Invalid input received after maximum attempts.")
printMessage("Aborting")
sys.exit(-1)
else:
os.popen("mv -f %s %s" % (file_path, destfile))
return
except IOError, e:
printLog("IOError %s" % e)
def modify_syslog_config_file(syslog_id, syslog_configuration_details,
authorization_details, user_type, noconfirm=False):
"""
Modifying configuration file by adding Loggly configuration text
"""
comment = ("\n#Configuration modified by"
"Loggly Syslog Configuration Script (%s)\n#\n"
% datetime.now().strftime('%Y-%m-%dT%H:%M:%S'))
content = syslog_config_file_content(syslog_id,
syslog_configuration_details.get("source"),
authorization_details)
command_content = ''
if len(syslog_configuration_details.get("token")) <= 0:
question = ("\nThe Loggly configuration will be appended to (%s) file."
"\n\nWould you like to have the configuration file modified?"
% default_config_file_name.get(syslog_id))
modify = noconfirm or confirm(question)
if modify:
backup_file_name = ("%s_%s.bak"
% (default_config_file_name.get(syslog_id),
datetime.now().strftime('%Y-%m-%dT%H:%M:%S')))
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
temp_file.write(content.encode('utf-8'))
if user_type == ROOT_USER:
os.popen(("cp -p %s %s"
% (default_config_file_name.get(syslog_id),
backup_file_name)))
os.popen(("bash -c 'cat %s >> %s' "
% (temp_file.name,
default_config_file_name.get(syslog_id)))).read()
os.unlink(temp_file.name)
else:
bash_script_content = ("cp -p %s %s "
"\nbash -c 'cat %s >> %s'\n%s"
% (default_config_file_name.get(syslog_id),
backup_file_name, temp_file.name,
default_config_file_name.get(syslog_id),
command_content))
create_bash_script(bash_script_content)
return backup_file_name
elif modify is False:
printLog("\nPlease add the following lines to "
"the syslog configuration file (%s)."
"\n\n%s%s"
% (default_config_file_name.get(syslog_id),
comment, content))
printMessage("Finished")
sys.exit(0)
else:
question = ("\nThis configuration currently uses \"%s\" as its Customer Token. "
"Do you want to overwrite it?"
% syslog_configuration_details.get("token"))
overwrite = noconfirm or confirm(question)
if overwrite:
pattern = (r"s/[a-z0-9]\{8\}\-[a-z0-9]\{4\}\-[a-z0-9]"
r"\{4\}\-[a-z0-9]\{4\}\-[a-z0-9]\{12\}/%s/g"
% authorization_details.get("token"))
if user_type == ROOT_USER:
os.popen("sed -i '%s' %s" % (pattern,
default_config_file_name.get(syslog_id)))
else:
bash_script_content = "sed -i '%s' %s\n%s" % (pattern,
default_config_file_name.get(syslog_id),
command_content)
create_bash_script(bash_script_content)
return
elif overwrite is False:
printMessage("Finished")
sys.exit(0)
return
printLog("Invalid input received after maximum attempts.")
printMessage("Aborting")
sys.exit(-1)
def check_selinux_service_status(syslog_type):
"""
Run getenforce command and if output is 'Enforcing' then selinux is on
else it is off.
"""
selinux_status = ''
command = 'getenforce'
p = subprocess.Popen(command, shell=True, stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
p.wait()
output = p.stdout.readlines()
if output:
selinux_status = output[0].rstrip()
if selinux_status == 'Enforcing':
printLog(("SELinux is on. Please disable it "
"and restart %s daemon manually." % syslog_type))
return True
else:
return False
def run_command(command):
""" runs a command and returns 3-tuple of
exit code, list of stdout, and list of stderr
"""
p = subprocess.Popen(command, shell=True,
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
p.wait()
return_code = p.returncode
out = p.stdout.readlines()
err = p.stderr.readlines()
return (return_code, out, err)
def restart_syslog_process(syslog_type, process_id):
"""
Attempt to restart the syslog process assuming we have root priv
"""
if run_command("pgrep supervisord")[0] == 0:
printLog("Restarting with supervisorctl")
command = "supervisorctl restart %s" % syslog_type
code, out, err = run_command(command)
if code == 0: return True
printLog("Restarting with /etc/init.d/%s restart" % syslog_type)
command = "/etc/init.d/%s restart" % syslog_type
code, out, err = run_command(command)
if code == 0: return True
printLog("Restarting %s with SIGHUP" % syslog_type)
command = "kill -HUP %d" % process_id
code, out, err = run_command(command)
if code == 0: return True
return False
def confirm_syslog_restart(syslog_type, noconfirm=False):
"""
Ask the user if it's okay to restart their syslog daemon
"""
if PROCESS_ID != -1:
question = ("Do you want the Loggly Syslog Configuration Script "
"to restart (SIGHUP) the syslog daemon.")
result = noconfirm or confirm(question)
if result:
return restart_syslog_process(syslog_type, PROCESS_ID)
elif result is False:
printLog("Configuration file has been modified, "
"please restart %s daemon manually."
% syslog_type)
else:
printLog("Syslog daemon (%s) is not running. "
"Configuration file has been modified,"
"please start %s daemon manually."
% (syslog_type, syslog_type))
return False
def doverify(loggly_user, loggly_password, loggly_subdomain):
"""
Send test message to loggly server using logger and
search this message to verify whether message is received or not.
"""
printLog("Testing syslog configuration...")
printLog("Sending a test message using logger.")
unique_string = str(uuid.uuid4()).replace("-","")
dummy_message = ("Testing that your log messages can make it to Loggly! %s"
% unique_string)
printLog("Sending message (%s) to Loggly server (%s)"
% (dummy_message, LOGGLY_SYSLOG_SERVER))
os.popen("logger -p INFO '%s'" % dummy_message).read()
search_url = REST_URL_GET_SEARCH_ID % (loggly_subdomain, LOGGLY_DOMAIN, unique_string)
# Implement REST APIs to search if dummy message has been sent.
wait_time = 0
while wait_time < VERIFICATION_SLEEP_INTERVAL:
print("."),
sys.stdout.flush()
printLog("Sending search request. %s" % search_url)
data = get_json_data(search_url, loggly_user, loggly_password)
rsid = data["rsid"]["id"]
search_result_url = REST_URL_GET_SEARCH_RESULT % (loggly_subdomain, LOGGLY_DOMAIN, rsid)
printLog("Sending search result request. %s" % search_result_url)
data = get_json_data(search_result_url, loggly_user, loggly_password)
total_events = data["total_events"]
if total_events >= 1 and VERIFICATION_FAIL not in LOGGLY_QA:
print (".")
printLog("******* Congratulations! Loggly is configured successfully.")
break
wait_time += VERIFICATION_SLEEP_INTERVAL_PER_ITERATION
time.sleep(VERIFICATION_SLEEP_INTERVAL_PER_ITERATION)
if wait_time >= VERIFICATION_SLEEP_INTERVAL:
printLog(VERIFICATION_FAIL_MESSAGE)
def write_env_details(current_environment):
"""
Write environment information to a file
"""
try:
file_path = os.path.join(os.getcwd(), LOGGLY_ENV_DETAILS_FILE)
env_file = open(file_path, "w")
env_file.write(os.popen("uname -a").read())
env_file.write("Operating System: %s" %
(current_environment['operating_system']))
env_file.write("\nSyslog versions:\n")
if len(current_environment['syslog_versions']) > 0:
for i, version in enumerate(current_environment['syslog_versions'], 1):
env_file.write("\t%d. %s(%s)" %
(i, version[0], version[1]))
else:
env_file.write("\tNo Syslog version Found......")
env_file.close()
printLog("Created environment details file at %s, "
"please visit http://loggly.com/docs/sending-logs-unixlinux-system-setup/ for more information." % file_path)
printEnvironment(current_environment)
except Exception, e:
printLog("Error %s" % e)
sys_exit(reason = "Error %s" % e)
def version_compatibility_check(minimum_version):
"""
Checks for compatible Python version.
"""
sys_version = ".".join(map(str, sys.version_info[:2]))
if sys_version < minimum_version or PYTHON_FAIL in LOGGLY_QA:
printLog(STR_PYTHON_FAIL_MESSAGE %
(sys_version, minimum_version))
sys_exit(reason = STR_PYTHON_FAIL_MESSAGE %
(sys_version, minimum_version))
printLog(("Python version check successful: "
"Installed version is " + sys_version + ". "
"Minimum required version is " + str(minimum_version)))
def log(d, prio = 'info', facility = 'local0'):
"""
Send a log message to Loggly;
send a UDP datagram to Loggly rather than risk blocking.
"""
msg_dict = {"version": OUR_VERSION}
msg_dict.update(d)
log_msg(json.dumps(msg_dict))
def log_msg(msg, prio='info', facility='local0'):
global _LOG_SOCKET
try:
pri = LOG_PRIORITIES[prio] + LOG_FACILITIES[facility]
except KeyError, errmsg:
pass
vals = {
'pri': pri,
'version': 1,
'timestamp': datetime.isoformat(datetime.now()),
'hostname': socket.gethostname(),
'app-name': OUR_PROGNAME,
'procid': os.getpid(),
'msgid': '-',
'loggly-auth-token': LOGGLY_AUTH_TOKEN,
'loggly-pen': int(DISTRIBUTION_ID),
'msg': msg
}
fullmsg = ("<%(pri)s>%(version)s %(timestamp)s %(hostname)s "
"%(app-name)s %(procid)s %(msgid)s "
"[%(loggly-auth-token)s@%(loggly-pen)s] %(msg)s") % vals
if not _LOG_SOCKET: # first time only...
_LOG_SOCKET = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
_LOG_SOCKET.sendto(fullmsg.encode('utf-8'),
(LOGGLY_SYSLOG_SERVER, LOGGLY_SYSLOG_PORT))
def perform_sanity_check_and_get_product_for_configuration(current_environment,
check_syslog_service = True):
printEnvironment(current_environment)
perform_sanity_check(current_environment)
syslog_name_for_configuration = product_for_configuration(
current_environment,
check_syslog_service = check_syslog_service)
current_environment['syslog_name_for_configuration']\
= syslog_name_for_configuration
return syslog_name_for_configuration
def install(current_environment):
printLog("Setup started")
# 1. Determine user type.
user_type = get_user_type()
# 2. Determine the environment in which it was invoked
#(i.e. which distro, release, and syslog daemon has been deployed)
syslog_name_for_configuration = \
perform_sanity_check_and_get_product_for_configuration(current_environment)
options = current_environment['options']
if options.auth:
token = options.auth
else:
loggly_user, loggly_password, loggly_subdomain = login()
token = get_auth_token(loggly_user, loggly_password, loggly_subdomain)
authorization_details = {'token': token, 'id': DISTRIBUTION_ID}
# 4. If possible, determine the location of the syslog.conf file or
#the syslog.conf.d/ directory.
# Provide the location as the default and prompt the user for confirmation.
# 5. Create custom configuration file and
#place it in configuration directory path ($IncludeConfig),
#default path for rsyslog will be /etc/rsyslog.d/
modified_config_file = write_configuration(syslog_name_for_configuration,
authorization_details, user_type, options.noconfirm)
selinux_status = check_selinux_service_status(syslog_name_for_configuration)
if user_type == ROOT_USER and not selinux_status:
# 6. SIGHUP the syslog daemon.
confirm_syslog_restart(syslog_name_for_configuration, options.noconfirm)
printLog(INSTALLATION_COMPLETED_TEXT)
return syslog_name_for_configuration
def verify(current_environment):
printLog("Verification started")
perform_sanity_check_and_get_product_for_configuration(current_environment)
loggly_user, loggly_password, loggly_subdomain = login()
doverify(loggly_user, loggly_password, loggly_subdomain)
printLog("Verification completed")
def uninstall(current_environment):
printLog("Revert started")
user_type = get_user_type()
if user_type == NON_ROOT_USER:
printLog("Please become root to revert")
sys.exit()
#No need to check syslog service for uninstall
syslog_name_for_configuration = \
perform_sanity_check_and_get_product_for_configuration(current_environment,
check_syslog_service = False)
remove_configuration(syslog_name_for_configuration)
selinux_status = check_selinux_service_status(syslog_name_for_configuration)
if not selinux_status:
noconfirm = current_environment['options'].noconfirm
confirm_syslog_restart(syslog_name_for_configuration, noconfirm)
printLog("Revert completed")
def rsyslog_dryrun():
results = get_stderr_from_process('rsyslogd -N1')
errors = []
for line in results:
#Python3 and above throw error
if 'UDP' in str(line):
if 'enabled' in str(line):
print("UDP Reception: Enabled")
else:
print("UDP Reception: Disabled")
if 'error' in str(line).lower():
errors.append(line)
return errors
def get_stderr_from_process(command):
process = subprocess.Popen(command, shell=True,
stdout=subprocess.PIPE,
stdin=open(os.devnull),
stderr=subprocess.PIPE)
results = process.stderr.readlines()
process.stderr.close()
return results
def syslog_ng_dryrun():
results = get_stderr_from_process('syslog-ng -s')
errors = []
for line in results:
#Python3 and above throw error
if 'error' in str(line).lower():
errors.append(line)
return errors
def ensure_root():
user_type = get_user_type()
if user_type == NON_ROOT_USER:
printLog("Current user is not root user")
sys.exit()
def dryrun(current_environment):
ensure_root()
syslogd = perform_sanity_check_and_get_product_for_configuration(current_environment)
printLog("Dryrun started for syslog version %s" % syslogd)
token = getattr(current_environment['options'], 'auth') or 'foofey'
noconfirm = current_environment['options'].noconfirm
config_file = write_configuration(
syslogd, {'token': token, 'id': DISTRIBUTION_ID }, 1, noconfirm)
errors = []
if syslogd == 'rsyslog':
errors = rsyslog_dryrun()
elif syslogd == 'syslog-ng':
errors = syslog_ng_dryrun()
remove_configuration(syslogd)
if len(errors) > 0:
printLog('\n!Dry Run FAIL: errors in config script!\n')
for error in errors:
printLog(' %s' % error)
else:
printLog("Dryrun completed successfully!!!")
module_dict = {
'sysinfo' : write_env_details,
'setup' :install,
'revert' : uninstall,
'verify' : verify,
'dryrun' : dryrun
}
def call_module(module_name, arg):
module_dict[module_name](arg)
def loggly_help():
loggly_user, loggly_password, loggly_subdomain = login()
auth_tokens = get_auth(loggly_user, loggly_password, loggly_subdomain)
logglyhelp = LOGGLY_HELP % {
'account': loggly_subdomain,
'token': auth_tokens[-1],
'dist_id': DISTRIBUTION_ID,
'syslog_server': LOGGLY_SYSLOG_SERVER,
'syslog_port': LOGGLY_SYSLOG_PORT,
'syslog_source': SYSLOG_NG_SOURCE,
}
print(logglyhelp)
class PAOptionParser(OptionParser, object):
def __init__(self, *args, **kw):
self.posargs = []
self.usage1 = kw['usage']
super(PAOptionParser, self).__init__(*args, **kw)
def add_posarg(self, *args, **kw):
pa_help = kw.get("help", "")
kw["help"] = SUPPRESS_HELP
self.add_option("--%s" % args[0], *args[1:], **kw)
self.posargs.append((args[0], pa_help))
def get_usage(self, *args, **kwargs):
self.usage = "%s" % (self.usage1)
return super(self.__class__, self).get_usage(*args, **kwargs)
def parse_args(self, *args, **kwargs):
args = sys.argv[1:]
args0 = []
for p, v in zip(self.posargs, args):
args0.append("--%s" % p[0])
args0.append(v)
args = args0 + args
options, args = super(self.__class__, self).parse_args(args, **kwargs)
if len(args) < len(self.posargs):
msg = ('Missing value(s) for "%s"\n'
% ", ".join([arg[0] for arg in self.posargs][len(args):]))
self.error(msg)
return options, args
CMD_USAGE = '''
%prog <action> [option]
Action:
\tsetup Configure your syslog setup
\trevert Revert changes made by this syslog configuration script
\tverify Verify the configuration explicitly
\tsysinfo Print, write system information
\tloggly_help Guideline for users for each step to configure syslog
\tdryrun Perform configuration steps without modifying anything
Option:
\taccount Name of loggly account being connected to
\tauth Loggly auth token to use for logging
\tyes Skip confirmations -- assume yes
'''.lstrip()
def parse_options():
"""
Parse command line argument
"""
parser = PAOptionParser(usage=CMD_USAGE)
parser.add_posarg("action", dest='action', type="choice",
choices=('setup', 'revert', 'verify',
'sysinfo', 'loggly_help', 'dryrun'))
parser.add_option("-y", "--yes", action="store_true", dest='noconfirm')
parser.add_option("-s", "--account")
parser.add_option("-a", "--auth")
(options, args) = parser.parse_args()
return options
def assert_os():
platform = sys.platform
# maybe also allow freebsd or sunos?
if not platform.startswith('linux'):
printLog("This script is only designed to run under linux, not %s" %
platform)
log({"platform": platform})
sys.exit(1)
# Script starts here
def main():
try:
printMessage("Starting")
options = parse_options()
if json is None:
version = get_python_version_string()
log_msg('''{"python_version": "%s", "subdomain": "%s"}''' %
(version, options.subdomain))
printMessage(STR_PYTHON_FAIL_MESSAGE %
(version, MINIMUM_SUPPORTED_PYTHON_VERSION))
sys.exit(-1)
global LOGGLY_QA
LOGGLY_QA = os.environ.get('LOGGLY_QA', '').split()
log({"status":"start", "args": vars(options)})
current_environment = get_environment_details()
current_environment['options'] = options
log({
"operating_system": current_environment['operating_system'],
"syslog_versions": [ {"daemon": d, "version": v} for d,v in current_environment['syslog_versions'] ]
})
version_compatibility_check(MINIMUM_SUPPORTED_PYTHON_VERSION)
assert_os()
if options.action == 'loggly_help':
loggly_help()
sys.exit()
call_module(options.action, current_environment)
printMessage("Finished")
log({"status":"finish", "args": vars(options)})
except KeyboardInterrupt:
#Python3 and above throw error
print("\nAborting...")
log({"status":"aborted", "args": vars(options), "msg":"KeyboardInterrupt" })
except Exception, e:
try:
trace = traceback.format_exc()
printLog(trace)
log({"status":"failed", "traceback":trace, "args": vars(options)})
finally:
printLog('Configure script has errors')
sys.exit(-1)
if __name__ == "__main__":
main()