Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[windows] new service and packaging #2417

Merged
merged 56 commits into from
Feb 13, 2017
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
8db437f
[windows] Refactor Windows service layer
Aug 10, 2015
d04fbda
Created a process-based supervisor on windows
Aug 19, 2015
58d2751
[flare][windows] Add new windows logs to flare
Aug 20, 2015
1c449ff
[windows] Use the path of the final package
Aug 21, 2015
f20306f
[windows] Use sockets in our supervisor + path fix
Sep 4, 2015
ef0a7c2
[windows] Create a Thread-based watchdog
Sep 8, 2015
723c5df
[windows] Use same path as on Linux for jmxfetch
Sep 8, 2015
4146514
[windows] Removed embedded python shell + cleanup
Sep 16, 2015
22b5786
[windows] Code cleanup to be flake8 compliant
Sep 16, 2015
d6bc863
[windows] Bump down pywin32 version to 217
Sep 16, 2015
7506c39
[windows] Fixed service layer once and for all
Sep 16, 2015
fee135b
[windows] Better logging in service layer
Sep 16, 2015
5840f8c
[windows] Accurate error messages in supervisor
Sep 16, 2015
bdc971d
[windows] Add new logs to GUI and flare
Sep 16, 2015
90cf16e
Don't fetch service and supervisor logs on OSX
Sep 16, 2015
b24ef68
[windows] Add new logs to windows GUI
Sep 17, 2015
d0ca5f8
[windows] Add service log file to the menu
Sep 17, 2015
21fcfa0
[core] Different Watchdog classes for OS
degemer Feb 22, 2016
c66ea26
[agent] remove SIGHUP signal register on windows
degemer Mar 1, 2016
befec72
[watchdog] catch ImportError of resource on Windows
degemer Mar 1, 2016
df5c60b
[windows] add logfile for GUI
degemer Mar 1, 2016
f075565
[windows] put gohai and python in path for Popen
degemer Mar 1, 2016
34f551a
[windows] remove Guidata compatibility warnings
degemer Mar 13, 2016
9c4fa7a
[windows] rename service and supervisor
degemer Apr 1, 2016
711f8bb
[util] flake8 :fire:
degemer May 10, 2016
485b81c
Merge branch 'master' into quentin/windows-omnibus-5.0
degemer May 23, 2016
bbe9119
[windows] properly configure checksd path
degemer Jun 3, 2016
f30225a
Merge branch 'master' into quentin/windows-omnibus-5.0
degemer Jun 7, 2016
f003b19
[windows] query Registry if api_key is default
degemer Jun 28, 2016
bde7c15
Merge branch 'master' into quentin/windows-omnibus-5.0
degemer Jul 28, 2016
ec26883
[windows] 💚 CI
degemer Jul 28, 2016
6f60943
[windows] Windows Service rework
degemer Aug 2, 2016
4b1d0e2
Revert "[windows] Windows Service rework"
degemer Aug 4, 2016
369be52
Merge branch 'master' into quentin/windows-omnibus-5.0
degemer Nov 15, 2016
bc82757
fix flake8 errors
degemer Nov 16, 2016
d0f4ca8
Merge branch 'master' into quentin/windows-omnibus-5.0
degemer Dec 21, 2016
a1c2823
[config] do not fail _windows_extra_checksd_path
degemer Dec 21, 2016
8d23019
[agent] catch supervisor.xmlrpc import errors
degemer Jan 3, 2017
c94b27b
[windows] refactor Watchdog and config
degemer Jan 10, 2017
e9e4eb2
[windows] create new service
degemer Jan 11, 2017
5ad43e8
[windows] merge service and supervisor
degemer Jan 12, 2017
5fb54f2
[windows] remove files from previous build system
degemer Jan 13, 2017
b653adc
[windows] do not run jmxfetch if not enabled
degemer Jan 13, 2017
4f95aca
Merge branch 'master' into quentin/windows-omnibus-5.0
degemer Jan 13, 2017
6f6cfb4
[windows] remove test of old service
degemer Jan 13, 2017
a8a2f91
[windows] let the service handle the conf update
degemer Jan 18, 2017
35e8898
[agent] remove unused can_write_conf arg
degemer Jan 19, 2017
768519d
[windows] add more logs for the config write
degemer Jan 19, 2017
3a8eaed
[windows] fix config write
degemer Jan 19, 2017
dda342e
[windows] address review comments
degemer Jan 25, 2017
4ce664e
[windows] read from registry if default apikey
degemer Jan 25, 2017
46fb184
[windows] re-add shell.py
degemer Jan 25, 2017
63d6b21
[windows] Call DDProcess functions in JMXFetchP
degemer Feb 3, 2017
5993b75
[windows] address review comments
degemer Feb 7, 2017
068c4b4
Merge branch 'master' into quentin/windows-omnibus-5.0
degemer Feb 7, 2017
af04f0b
[service] properly exit or kill JMXFetch
degemer Feb 7, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ dummy-variables-rgx=_|dummy

# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
additional-builtins=WindowsError


[CLASSES]
Expand Down
22 changes: 12 additions & 10 deletions agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@
from util import (
EC2,
get_hostname,
Watchdog,
)
from utils.flare import Flare
from utils.configcheck import configcheck, sd_configcheck
from utils.jmx import jmx_command
from utils.pidfile import PidFile
from utils.platform import Platform
from utils.profile import AgentProfiler
from utils.service_discovery.config_stores import get_config_store
from utils.service_discovery.sd_backend import get_sd_backend
from utils.watchdog import new_watchdog

# Constants
PID_NAME = "dd-agent"
Expand Down Expand Up @@ -129,21 +130,22 @@ def run(self, config=None):
# Gracefully exit on sigterm.
signal.signal(signal.SIGTERM, self._handle_sigterm)

# A SIGUSR1 signals an exit with an autorestart
signal.signal(signal.SIGUSR1, self._handle_sigusr1)
if not Platform.is_windows():
# A SIGUSR1 signals an exit with an autorestart
signal.signal(signal.SIGUSR1, self._handle_sigusr1)

# Handle Keyboard Interrupt
signal.signal(signal.SIGINT, self._handle_sigterm)
# Handle Keyboard Interrupt
signal.signal(signal.SIGINT, self._handle_sigterm)

# A SIGHUP signals a configuration reload
signal.signal(signal.SIGHUP, self._handle_sighup)
# A SIGHUP signals a configuration reload
signal.signal(signal.SIGHUP, self._handle_sighup)

# Save the agent start-up stats.
CollectorStatus().persist()

# Intialize the collector.
if not config:
config = get_config(parse_args=True)
config = get_config(parse_args=True, can_write_conf=True)

self._agentConfig = self._set_agent_config_hostname(config)
hostname = get_hostname(self._agentConfig)
Expand Down Expand Up @@ -256,8 +258,8 @@ def _get_emitters(self):
def _get_watchdog(self, check_freq):
watchdog = None
if self._agentConfig.get("watchdog", True):
watchdog = Watchdog(check_freq * WATCHDOG_MULTIPLIER,
max_mem_mb=self._agentConfig.get('limit_memory_consumption', None))
watchdog = new_watchdog(check_freq * WATCHDOG_MULTIPLIER,
max_mem_mb=self._agentConfig.get('limit_memory_consumption', None))
watchdog.reset()
return watchdog

Expand Down
6 changes: 1 addition & 5 deletions checks/collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,11 +764,7 @@ def _run_gohai_processes(self):
def _run_gohai(self, options):
output = None
try:
if not Platform.is_windows():
command = "gohai"
else:
command = "gohai\gohai.exe"
output, err, _ = get_subprocess_output([command] + options, log)
output, err, _ = get_subprocess_output(["gohai"] + options, log)
if err:
log.warning("GOHAI LOG | {0}".format(err))
except OSError as e:
Expand Down
75 changes: 66 additions & 9 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,15 @@ def _windows_confd_path():
common_data = _windows_commondata_path()
return _confd_path(os.path.join(common_data, 'Datadog'))

def _windows_extra_checksd_path():
common_data = _windows_commondata_path()
return _checksd_path(os.path.join(common_data, 'Datadog'))

def _windows_checksd_path():
if hasattr(sys, 'frozen'):
# we're frozen - from py2exe
prog_path = os.path.dirname(sys.executable)
return _checksd_path(os.path.join(prog_path, '..'))
return _checksd_path(os.path.normpath(os.path.join(prog_path, '..', 'agent')))
else:
cur_path = os.path.dirname(__file__)
return _checksd_path(cur_path)
Expand Down Expand Up @@ -325,7 +328,7 @@ def clean_dd_url(url):
return url[:-1] if url.endswith('/') else url


def get_config(parse_args=True, cfg_path=None, options=None):
def get_config(parse_args=True, cfg_path=None, options=None, can_write_conf=False):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this new arg ?

if parse_args:
options, _ = get_parsed_args()

Expand All @@ -349,6 +352,8 @@ def get_config(parse_args=True, cfg_path=None, options=None):

if Platform.is_mac():
agentConfig['additional_checksd'] = '/opt/datadog-agent/etc/checks.d'
elif Platform.is_windows():
agentConfig['additional_checksd'] = _windows_extra_checksd_path()

# Config handling
try:
Expand Down Expand Up @@ -438,10 +443,6 @@ def get_config(parse_args=True, cfg_path=None, options=None):
# the linux directory is set by default
if config.has_option('Main', 'additional_checksd'):
agentConfig['additional_checksd'] = config.get('Main', 'additional_checksd')
elif get_os() == 'windows':
# default windows location
common_path = _windows_commondata_path()
agentConfig['additional_checksd'] = os.path.join(common_path, 'Datadog', 'checks.d')

if config.has_option('Main', 'use_dogstatsd'):
agentConfig['use_dogstatsd'] = config.get('Main', 'use_dogstatsd').lower() in ("yes", "true")
Expand Down Expand Up @@ -620,9 +621,62 @@ def get_config(parse_args=True, cfg_path=None, options=None):
else:
agentConfig['ssl_certificate'] = agentConfig['ca_certs']

if agentConfig['api_key'] == 'APIKEYHERE' and Platform.is_windows():
log.debug('Querying registry to get missing config options')
registry_conf = get_registry_conf(agentConfig)
agentConfig.update(registry_conf)
# If it's the collector, conf is updated
if can_write_conf and registry_conf:
log.debug('Updating conf file options: %s', registry_conf.keys())
update_conf_file(registry_conf, config_path)

return agentConfig


def get_registry_conf(agentConfig):
registry_conf = {}
try:
import _winreg
with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Datadog\\Datadog Agent") as reg_key:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's create a constant for the registry key

for attribute in ['api_key', 'tags', 'hostname']:
option = _winreg.QueryValueEx(reg_key, attribute)[0]
if option != '':
registry_conf[attribute] = option
except (ImportError, WindowsError) as e:
log.error('Unable to get config keys from Registry: %s', e)

return registry_conf


def update_conf_file(registry_conf, config_path):
Copy link

@remh remh Dec 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like

def update_conf_file(registry_conf, config_path):
    new_config = ""
    with open(config_path, 'r') as f:
        for line in f:
            for k, v in registry_conf.iteritems():
                if k + ":" in line:
                    line = '{}: {}{}'.format(k, v,os.linesep)
            new_config += line
    with open(config_path, 'w') as f:
        f.write(new_config)

is easier to read.

That being said, we should move that somewhere else.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conf file uses \n as eol even on Windows.
I'll move it to its own utils/windows_configuration.

buffer = ''
try:
with open(config_path, 'r') as config_file:
for line in config_file:
matched = False
for attribute in registry_conf:
# Is it the line configuring the attribute ?
if conf_match(line, attribute):
buffer += '{}: {}\n'.format(attribute, registry_conf[attribute])
matched = True
if not matched:
buffer += line
except Exception as e:
log.error('An exception happened while updating the conf file. No change has been done.'
' Error: %s', e)
else:
with open(config_path, 'w') as config_file:
config_file.write(buffer)


def conf_match(line, attribute):
attribute += ':'
return (line.startswith(attribute) or
line.startswith('#' + attribute) or
line.startswith('# ' + attribute))


def get_system_stats(proc_path=None):
systemStats = {
'machine': platform.machine(),
Expand Down Expand Up @@ -1104,10 +1158,13 @@ def get_logging_config(cfg_path=None):
'syslog_port': None,
}
if system_os == 'windows':
logging_config['windows_collector_log_file'] = os.path.join(_windows_commondata_path(), 'Datadog', 'logs', 'collector.log')
logging_config['windows_forwarder_log_file'] = os.path.join(_windows_commondata_path(), 'Datadog', 'logs', 'forwarder.log')
logging_config['windows_dogstatsd_log_file'] = os.path.join(_windows_commondata_path(), 'Datadog', 'logs', 'dogstatsd.log')
logging_config['collector_log_file'] = os.path.join(_windows_commondata_path(), 'Datadog', 'logs', 'collector.log')
logging_config['forwarder_log_file'] = os.path.join(_windows_commondata_path(), 'Datadog', 'logs', 'forwarder.log')
logging_config['dogstatsd_log_file'] = os.path.join(_windows_commondata_path(), 'Datadog', 'logs', 'dogstatsd.log')
logging_config['jmxfetch_log_file'] = os.path.join(_windows_commondata_path(), 'Datadog', 'logs', 'jmxfetch.log')
logging_config['supervisor_log_file'] = os.path.join(_windows_commondata_path(), 'Datadog', 'logs', 'supervisor.log')
logging_config['service_log_file'] = os.path.join(_windows_commondata_path(), 'Datadog', 'logs', 'service.log')
logging_config['log_to_syslog'] = False
else:
logging_config['collector_log_file'] = '/var/log/datadog/collector.log'
logging_config['forwarder_log_file'] = '/var/log/datadog/forwarder.log'
Expand Down
11 changes: 4 additions & 7 deletions ddagent.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@
get_tornado_ioloop,
get_uuid,
json,
Watchdog,
)
from utils.logger import RedactedLogRecord

from utils.watchdog import new_watchdog

logging.LogRecord = RedactedLogRecord
log = logging.getLogger('forwarder')
Expand Down Expand Up @@ -419,11 +418,9 @@ def __init__(self, port, agentConfig, watchdog=True,
# Monitor activity
if watchdog:
watchdog_timeout = TRANSACTION_FLUSH_INTERVAL * WATCHDOG_INTERVAL_MULTIPLIER / 1000
self._watchdog = Watchdog(
watchdog_timeout,
max_mem_mb=agentConfig.get('limit_memory_consumption', None),
max_resets=WATCHDOG_HIGH_ACTIVITY_THRESHOLD
)
self._watchdog = new_watchdog(watchdog_timeout,
max_mem_mb=agentConfig.get('limit_memory_consumption', None),
max_resets=WATCHDOG_HIGH_ACTIVITY_THRESHOLD)

def log_request(self, handler):
""" Override the tornado logging method.
Expand Down
9 changes: 4 additions & 5 deletions dogstatsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"""
A Python Statsd implementation with some datadog special sauce.
"""

# set up logging before importing any other components
from config import initialize_logging # noqa
initialize_logging('dogstatsd')
Expand All @@ -17,9 +16,9 @@
set_no_proxy_settings()

# stdlib
import os
import logging
import optparse
import os
import select
import signal
import socket
Expand All @@ -43,9 +42,10 @@
from config import get_config, get_version
from daemon import AgentSupervisor, Daemon
from util import chunks, get_hostname, get_uuid, plural
from utils.pidfile import PidFile
from utils.net import inet_pton
from utils.net import IPV6_V6ONLY, IPPROTO_IPV6
from utils.pidfile import PidFile
from utils.watchdog import new_watchdog

# urllib3 logs a bunch of stuff at the info level
requests_log = logging.getLogger("requests.packages.urllib3")
Expand Down Expand Up @@ -193,8 +193,7 @@ def __init__(self, interval, metrics_aggregator, api_host, api_key=None,

self.watchdog = None
if use_watchdog:
from util import Watchdog
self.watchdog = Watchdog(WATCHDOG_TIMEOUT)
self.watchdog = new_watchdog(WATCHDOG_TIMEOUT)

self.api_key = api_key
self.api_host = api_host
Expand Down
8 changes: 3 additions & 5 deletions jmxfetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,11 +443,9 @@ def _is_jmx_check(check_config, check_name, checks_list):
return is_jmx, java_bin_path, java_options, tools_jar_path, custom_jar_paths

def _get_path_to_jmxfetch(self):
if not Platform.is_windows():
return os.path.realpath(os.path.join(os.path.abspath(__file__), "..", "checks",
"libs", JMX_FETCH_JAR_NAME))
return os.path.realpath(os.path.join(os.path.abspath(__file__), "..", "..",
"jmxfetch", JMX_FETCH_JAR_NAME))
return os.path.realpath(os.path.join(os.path.abspath(__file__), "..", "checks",
"libs", JMX_FETCH_JAR_NAME))



def init(config_path=None):
Expand Down
Loading