Example #1
0
def plugin_detection(plugins,
                     template_dir,
                     detection_args,
                     skip_failed=True,
                     remove=False):
    """Runs the detection step for each plugin in the list and returns the complete detected agent config.
    :param plugins: A list of detection plugin classes
    :param template_dir: Location of plugin configuration templates
    :param detection_args: Arguments passed to each detection plugin
    :param skip_failed: When False any detection failure causes the run to halt and return None
    :return: An agent_config instance representing the total configuration from all detection plugins run.
    """
    plugin_config = agent_config.Plugins()
    for detect_class in plugins:
        # todo add option to install dependencies
        detect = detect_class(template_dir, False, detection_args)
        if detect.available:
            new_config = detect.build_config_with_name()
            if not remove:
                log.info('Configuring {0}'.format(detect.name))
            if new_config is not None:
                plugin_config.merge(new_config)
        elif not skip_failed:
            log.warn(
                'Failed detection of plugin {0}.'.format(detect.name) +
                "\n\tPossible causes: Service not found or missing arguments.")
            return None

    return plugin_config
Example #2
0
def main(argv=None):
    parser = argparse.ArgumentParser(
        description=
        'Detect running daemons then configure and start the agent.',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('-u',
                        '--username',
                        help="Username used for keystone authentication",
                        required=True)
    parser.add_argument('-p',
                        '--password',
                        help="Password used for keystone authentication",
                        required=True)
    parser.add_argument('--keystone_url', help="Keystone url", required=True)
    parser.add_argument('--monasca_url', help="Monasca API url", required=True)
    parser.add_argument(
        '--insecure',
        help="Set whether certificates are used for Keystone authentication",
        required=False,
        default=False)
    parser.add_argument('--project_name',
                        help="Project name for keystone authentication",
                        required=False,
                        default='')
    parser.add_argument('--project_domain_id',
                        help="Project domain id for keystone authentication",
                        required=False,
                        default='')
    parser.add_argument('--project_domain_name',
                        help="Project domain name for keystone authentication",
                        required=False,
                        default='')
    parser.add_argument(
        '--project_id',
        help="Keystone project id  for keystone authentication",
        required=False,
        default='')
    parser.add_argument(
        '--ca_file',
        help="Sets the path to the ca certs file if using certificates. " +
        "Required only if insecure is set to False",
        required=False,
        default='')
    parser.add_argument('--config_dir',
                        help="Configuration directory",
                        default='/etc/monasca/agent')
    parser.add_argument(
        '--dimensions',
        help=
        "Additional dimensions to set for all metrics. A comma seperated list "
        + "of name/value pairs, 'name:value,name2:value2'")
    parser.add_argument('--log_dir',
                        help="monasca-agent log directory",
                        default='/var/log/monasca/agent')
    parser.add_argument('--template_dir',
                        help="Alternative template directory",
                        default='/usr/local/share/monasca/agent')
    parser.add_argument('--headless',
                        help="Run in a non-interactive mode",
                        action="store_true")
    parser.add_argument(
        '--overwrite',
        help="Overwrite existing plugin configuration. " +
        "The default is to merge. Agent.conf is always overwritten.",
        action="store_true")
    parser.add_argument(
        '--skip_enable',
        help="By default the service is enabled, " +
        "which requires the script run as root. Set this to skip that step.",
        action="store_true")
    parser.add_argument('--user',
                        help="User name to run monasca-agent as",
                        default='monasca-agent')
    parser.add_argument(
        '-s',
        '--service',
        help="Service this node is associated with, added as a dimension.")
    parser.add_argument(
        '--amplifier',
        help="Integer for the number of additional measurements to create. " +
        "Additional measurements contain the 'amplifier' dimension. " +
        "Useful for load testing; not for production use.",
        default=0,
        required=False)
    parser.add_argument('-v',
                        '--verbose',
                        help="Verbose Output",
                        action="store_true")
    args = parser.parse_args()

    if args.verbose:
        logging.basicConfig(level=logging.DEBUG,
                            format="%(levelname)s: %(message)s")
    else:
        logging.basicConfig(level=logging.INFO,
                            format="%(levelname)s: %(message)s")

    # Detect os
    detected_os = platform.system()
    if detected_os == 'Linux':
        linux_flavor = platform.linux_distribution()[0]
        if 'Ubuntu' or 'debian' in linux_flavor:
            for package in ['coreutils', 'sysstat']:
                #Check for required dependencies for system checks
                try:
                    output = subprocess.check_output(
                        'dpkg -s {}'.format(package),
                        stderr=subprocess.STDOUT,
                        shell=True)
                except subprocess.CalledProcessError:
                    log.warn(
                        "*** {} package is not installed! ***".format(package)
                        + "\nNOTE: If you do not install the {} ".format(
                            package) +
                        "package, you will not receive all of the standard " +
                        "operating system type metrics!")
        else:
            pass
    elif detected_os == 'Darwin':
        print("Mac OS is not currently supported by the Monasca Agent")
        sys.exit()
    elif detected_os == 'Windows':
        print("Windows is not currently supported by the Monasca Agent")
        sys.exit()
    else:
        print("{0} is not currently supported by the Monasca Agent".format(
            detected_os))

    # Service enable, includes setup of users/config directories so must be
    # done before configuration
    agent_service = OS_SERVICE_MAP[detected_os](os.path.join(
        args.template_dir, 'monasca-agent.init'),
                                                args.config_dir,
                                                args.log_dir,
                                                username=args.user)
    if not args.skip_enable:
        agent_service.enable()

    gid = pwd.getpwnam(args.user).pw_gid
    # Write the main agent.conf - Note this is always overwritten
    log.info('Configuring base Agent settings.')
    agent_conf_path = os.path.join(args.config_dir, 'agent.conf')
    with open(os.path.join(args.template_dir, 'agent.conf.template'),
              'r') as agent_template:
        with open(agent_conf_path, 'w') as agent_conf:
            # Join service in with the dimensions
            if args.service is not None:
                if args.dimensions is None:
                    args.dimensions = 'service:' + args.service
                else:
                    args.dimensions = ','.join(
                        [args.dimensions, 'service:' + args.service])
            agent_conf.write(agent_template.read().format(
                args=args, hostname=socket.getfqdn()))
    os.chown(agent_conf_path, 0, gid)
    os.chmod(agent_conf_path, 0o640)
    # Link the supervisor.conf
    supervisor_path = os.path.join(args.config_dir, 'supervisor.conf')
    if os.path.exists(supervisor_path):
        os.remove(supervisor_path)
    os.symlink(os.path.join(args.template_dir, 'supervisor.conf'),
               supervisor_path)

    # Run through detection and config building for the plugins
    plugin_config = agent_config.Plugins()
    for detect_class in DETECTION_PLUGINS:
        detect = detect_class(args.template_dir, args.overwrite)
        if detect.available:
            log.info('Configuring {0}'.format(detect.name))
            new_config = detect.build_config()
            plugin_config.merge(new_config)

        # todo add option to install dependencies

    # Write out the plugin config
    for key, value in plugin_config.iteritems():
        # todo if overwrite is set I should either warn or just delete any config files not in the new config
        # todo add the ability to show a diff before overwriting or merging config
        config_path = os.path.join(args.config_dir, 'conf.d', key + '.yaml')
        # merge old and new config, new has precedence
        if (not args.overwrite) and os.path.exists(config_path):
            with open(config_path, 'r') as config_file:
                old_config = yaml.load(config_file.read())
            if old_config is not None:
                agent_config.deep_merge(old_config, value)
                value = old_config
        with open(config_path, 'w') as config_file:
            os.chmod(config_path, 0o640)
            os.chown(config_path, 0, gid)
            config_file.write(
                yaml.safe_dump(value, encoding='utf-8', allow_unicode=True))

    # Now that the config is build start the service
    try:
        agent_service.start(restart=True)
    except subprocess.CalledProcessError:
        log.error('The service did not startup correctly see %s' %
                  args.log_dir)
Example #3
0
def main(argv=None):
    parser = argparse.ArgumentParser(description='Detect running daemons then configure and start the agent.',
                                     formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument(
        '-u', '--username', help="Keystone username used to post metrics", required=True)
    parser.add_argument(
        '-p', '--password', help="Keystone password used to post metrics", required=True)
    parser.add_argument('--project_name', help="Keystone project/tenant name", required=True)
    parser.add_argument(
        '-s', '--service', help="Service this node is associated with.", required=True)
    parser.add_argument('--keystone_url', help="Keystone url", required=True)
    parser.add_argument('--monasca_url', help="Monasca API url", required=True)
    parser.add_argument('--config_dir', help="Configuration directory", default='/etc/monasca/agent')
    parser.add_argument('--log_dir', help="monasca-agent log directory", default='/var/log/monasca/agent')
    parser.add_argument(
        '--template_dir', help="Alternative template directory", default='/usr/local/share/monasca/agent')
    parser.add_argument('--headless', help="Run in a non-interactive mode", action="store_true")
    parser.add_argument('--overwrite',
                        help="Overwrite existing plugin configuration." +
                             "The default is to merge. Agent.conf is always overwritten.",
                        action="store_true")
    parser.add_argument('--skip_enable', help="By default the service is enabled," +
                                              " which requires the script run as root. Set this to skip that step.",
                        action="store_true")
    parser.add_argument('--user', help="User name to run monasca-agent as", default='monasca-agent')
    parser.add_argument('-v', '--verbose', help="Verbose Output", action="store_true")
    args = parser.parse_args()

    if args.verbose:
        logging.basicConfig(level=logging.DEBUG, format="%(levelname)s: %(message)s")
    else:
        logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")

    # Detect os
    detected_os = platform.system()
    if detected_os == 'Linux':
        pass
    elif detected_os == 'Darwin':
        print("Mac OS is not currently supported by the Monasca Agent")
        sys.exit()
    elif detected_os == 'Windows':
        print("Windows is not currently supported by the Monasca Agent")
        sys.exit()
    else:
        print("{0} is not currently supported by the Monasca Agent".format(detected_os))

    # Service enable, includes setup of users/config directories so must be
    # done before configuration
    agent_service = OS_SERVICE_MAP[detected_os](os.path.join(args.template_dir, 'monasca-agent.init'),
                                                args.config_dir,
                                                args.log_dir, username=args.user)
    if not args.skip_enable:
        agent_service.enable()

    gid = pwd.getpwnam(args.user).pw_gid
    # Write the main agent.conf - Note this is always overwritten
    log.info('Configuring base Agent settings.')
    agent_conf_path = os.path.join(args.config_dir, 'agent.conf')
    with open(os.path.join(args.template_dir, 'agent.conf.template'), 'r') as agent_template:
        with open(agent_conf_path, 'w') as agent_conf:
            agent_conf.write(agent_template.read().format(args=args, hostname=socket.getfqdn()))
    os.chown(agent_conf_path, 0, gid)
    os.chmod(agent_conf_path, 0o640)
    # Link the supervisor.conf
    supervisor_path = os.path.join(args.config_dir, 'supervisor.conf')
    if os.path.exists(supervisor_path):
        os.remove(supervisor_path)
    os.symlink(os.path.join(args.template_dir, 'supervisor.conf'), supervisor_path)

    # Run through detection and config building for the plugins
    plugin_config = agent_config.Plugins()
    for detect_class in DETECTION_PLUGINS:
        detect = detect_class(args.template_dir, args.overwrite)
        if detect.available:
            log.info('Configuring {0}'.format(detect.name))
            new_config = detect.build_config()
            plugin_config.merge(new_config)

        # todo add option to install dependencies

    # Write out the plugin config
    for key, value in plugin_config.iteritems():
        # todo if overwrite is set I should either warn or just delete any config files not in the new config
        # todo add the ability to show a diff before overwriting or merging config
        config_path = os.path.join(args.config_dir, 'conf.d', key + '.yaml')
        # merge old and new config, new has precedence
        if (not args.overwrite) and os.path.exists(config_path):
            with open(config_path, 'r') as config_file:
                old_config = yaml.load(config_file.read())
            if old_config is not None:
                agent_config.deep_merge(old_config, value)
                value = old_config
        with open(config_path, 'w') as config_file:
            os.chmod(config_path, 0o640)
            os.chown(config_path, 0, gid)
            config_file.write(yaml.safe_dump(value, encoding='utf-8', allow_unicode=True))

    # Now that the config is build start the service
    try:
        agent_service.start(restart=True)
    except subprocess.CalledProcessError:
        log.error('The service did not startup correctly see %s' % args.log_dir)