예제 #1
0
def create(ctx):
    try:
        run(['systemctl', 'status', 'snmptrapd'])
    except subprocess.CalledProcessError:
        raise NonRecoverableError(
            'SNMP trap checks cannot be used if snmptrapd has not been '
            'configured. trap_community should be set on the '
            'cloudify.nagios.nodes.Nagios managed nagios node.'
        )

    trap_oid = oid_lookup.get(ctx.node.properties['trap_oid'])
    instance_oid = ctx.node.properties['instance_oid']
    instance_finder = ctx.node.properties['instance_finder']
    oid_for_message = ctx.node.properties['oid_for_message']

    trap_configuration = {}

    if instance_oid:
        trap_configuration['instance'] = {
            'oid': oid_lookup.get(instance_oid),
            'finder': instance_finder,
        }

    if oid_for_message:
        trap_configuration['oid_for_message'] = oid_for_message

    ctx.logger.info('Deploying trap configuration')
    deploy_file(
        data=json.dumps(trap_configuration),
        destination=TRAP_CONFIGURATION_PATH.format(oid=trap_oid),
        sudo=True,
    )
예제 #2
0
def create(ctx):
    props = ctx.node.properties

    ctx.logger.info('Validating SSL properties')
    if bool(props['ssl_certificate']) != bool(props['ssl_key']):
        raise NonRecoverableError(
            'Either ssl_certificate and ssl_key must both be provided, '
            'or neither of them must be provided. '
            'ssl_certificate was: {ssl_certificate}; '
            'ssl_key was: {ssl_key}'.format(
                ssl_certificate=props['ssl_certificate'],
                ssl_key=props['ssl_key'],
            ))

    ctx.logger.info('Enabling EPEL (if required)')
    yum_install('epel-release')

    ctx.logger.info('Installing required packages')
    yum_install([
        'mod_ssl',
        'nagios',
        'nagios-plugins-disk',
        'nagios-plugins-load',
        'nagios-plugins-ping',
        'nagios-plugins-snmp',
        'nagios-selinux',
        'net-snmp',
        'net-snmp-utils',
        'python-flask',
        'python-gunicorn',
        'python-jinja2',
        'python-requests',
        'selinux-policy-devel',
        'incron',
    ])

    ctx.logger.info('Deploying SELinux configuration')
    # Prepare SELinux context for trap handler
    tmp_path = tempfile.mkdtemp()
    with open(
            os.path.join(tmp_path, 'cloudify-nagios-snmp-trap-handler.te'),
            'w',
    ) as policy_handle:
        policy_handle.write(
            pkgutil.get_data(
                'managed_nagios_plugin',
                'resources/selinux/cloudify_nagios_snmp_trap_handler.te',
            ))
    run(['make', '-f', '/usr/share/selinux/devel/Makefile', '-C', tmp_path],
        sudo=True)
    run([
        'semodule', '-i',
        os.path.join(tmp_path, 'cloudify-nagios-snmp-trap-handler.pp')
    ],
        sudo=True)
    run(['rm', '-rf', tmp_path], sudo=True)

    ctx.logger.info('Deploying nagios plugins and SNMP trap handler')
    for supporting_lib in ('constants.py', 'utils.py', 'snmp_utils.py',
                           'nagios_utils.py', 'rest_utils.py',
                           'resources/scripts/nagios_plugin_utils.py',
                           'resources/scripts/logging_utils.py'):
        if supporting_lib.startswith('resources/scripts/'):
            destination_filename = supporting_lib[len('resources/scripts/'):]
        else:
            destination_filename = supporting_lib
        deploy_file(
            data=pkgutil.get_data(
                'managed_nagios_plugin',
                supporting_lib,
            ),
            destination='/usr/lib64/nagios/plugins/' + destination_filename,
            ownership='root.nagios',
            permissions='440',
            sudo=True,
        )
    for script in ('check_snmp_numeric', 'check_snmp_aggregate',
                   'check_group_aggregate', 'check_group_meta_aggregate',
                   'cloudify_nagios_snmp_trap_handler', 'notify_cloudify',
                   'check_nagios_command_file', 'check_snmptrap_checks'):
        source = os.path.join('resources/scripts/', script)
        script_content = pkgutil.get_data('managed_nagios_plugin', source)
        destination = os.path.join('/usr/lib64/nagios/plugins', script)
        deploy_file(
            data=script_content,
            destination=destination,
            permissions='550',
            sudo=True,
        )

    ctx.logger.info('Deploying nagiosrest')
    run(['mkdir', '-p', '/usr/local/www/nagiosrest'], sudo=True)
    for nagiosrest_file in ('nagiosrest.py', 'nagiosrest_group.py',
                            'nagiosrest_target.py', 'nagiosrest_tenant.py',
                            'logging_utils.py'):
        deploy_file(
            data=pkgutil.get_data(
                'managed_nagios_plugin',
                'resources/scripts/' + nagiosrest_file,
            ),
            destination='/usr/local/www/nagiosrest/' + nagiosrest_file,
            ownership='root.nagios',
            permissions='440',
            sudo=True,
        )
    for supporting_lib in ('nagios_utils.py', 'utils.py', 'constants.py'):
        deploy_file(
            data=pkgutil.get_data(
                'managed_nagios_plugin',
                supporting_lib,
            ),
            destination='/usr/local/www/nagiosrest/' + supporting_lib,
            ownership='root.nagios',
            permissions='440',
            sudo=True,
        )
    for template in ('hostgroup.template', 'target.template', 'node.template',
                     'group.template', 'group_check.template',
                     'meta_group_check.template'):
        deploy_file(
            data=pkgutil.get_data(
                'managed_nagios_plugin',
                os.path.join('resources', template),
            ),
            destination='/usr/local/www/nagiosrest/' + template,
            ownership='root.nagios',
            permissions='440',
            sudo=True,
        )
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/base_configuration/systemd_nagiosrest.conf',
        ),
        destination='/usr/lib/systemd/system/nagiosrest-gunicorn.service',
        ownership='root.root',
        permissions='440',
        sudo=True,
    )

    ctx.logger.info('Deploying notification configuration script')
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/scripts/update_notify_cloudify_configuration',
        ),
        destination='/usr/local/bin/update_notify_cloudify_configuration',
        ownership='root.root',
        permissions='500',
        sudo=True,
        # Must have the group of the agent user for reconcile operation to
        # work correctly
        template_params={'group': grp.getgrgid(os.getgid()).gr_name},
    )
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'utils.py',
        ),
        destination='/usr/local/bin/utils.py',
        ownership='root.root',
        permissions='400',
        sudo=True,
    )
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'constants.py',
        ),
        destination='/usr/local/bin/constants.py',
        ownership='root.root',
        permissions='400',
        sudo=True,
    )

    ctx.logger.info(
        'Creating directory structure for storing temporary rate data')
    for rate_dir in ('nodes', 'instances'):
        rate_storage_path = os.path.join(RATE_BASE_PATH, rate_dir)
        run(['mkdir', '-p', rate_storage_path], sudo=True)
        run(['chown', 'nagios.', rate_storage_path], sudo=True)
        run(['restorecon', rate_storage_path], sudo=True)

    if props['ssl_certificate']:

        if props['ssl_certificate'].startswith("-----BEGIN CERTIFICATE-----"):
            deploy_file(
                data=props['ssl_key'],
                destination=SSL_KEY_PATH,
                ownership='root.root',
                permissions='440',
                sudo=True,
            )
            deploy_file(
                data=props['ssl_certificate'],
                destination=SSL_CERT_PATH,
                ownership='root.root',
                permissions='444',
                sudo=True,
            )
        else:
            download_and_deploy_file_from_blueprint(
                source=BLUEPRINT_SSL_KEY_PATH.format(
                    key_file=props['ssl_key'], ),
                destination=SSL_KEY_PATH,
                ownership='root.root',
                permissions='440',
                ctx=ctx,
            )
            download_and_deploy_file_from_blueprint(
                source=BLUEPRINT_SSL_CERT_PATH.format(
                    cert_file=props['ssl_certificate'], ),
                destination=SSL_CERT_PATH,
                ownership='root.root',
                permissions='444',
                ctx=ctx,
            )
    else:
        ctx.logger.info('Generating SSL certificate')
        generate_certs(SSL_KEY_PATH, SSL_CERT_PATH, ctx.logger)
    with open(SSL_CERT_PATH) as crt_handle:
        ctx.instance.runtime_properties['ssl_certificate'] = crt_handle.read()

    ctx.logger.info('Reloading systemd configuration')
    reload_systemd_configuration()
예제 #3
0
def configure(ctx):
    props = ctx.node.properties

    ctx.logger.info('Configuring nagios web user')
    username = props['nagios_web_username']
    password = props['nagios_web_password']
    tmpdir = tempfile.mkdtemp()
    tmp_htpass = os.path.join(tmpdir, 'passwd')
    run(['htpasswd', '-bc', tmp_htpass, username, password])
    run(['mv', tmp_htpass, '/etc/nagios/passwd'], sudo=True)
    run(['rm', '-rf', tmpdir])
    run(['chown', 'root.apache', '/etc/nagios/passwd'], sudo=True)
    run(['chmod', '640', '/etc/nagios/passwd'], sudo=True)
    run(['usermod', '-G', 'nagios', 'apache'], sudo=True)

    ctx.logger.info('Deploying automated reaction configuration')
    # We're using username+password because current token implementation is
    # unsuitable for this.
    reaction_configuration = {
        'username': props['cloudify_manager_username'],
        'password': props['cloudify_manager_password'],
    }
    deploy_file(
        data=json.dumps(reaction_configuration),
        destination='/etc/nagios/cloudify_manager.json',
        ownership='nagios.{group}'.format(
            # Must have the group of the agent user for reconcile operation to
            # work correctly
            group=grp.getgrgid(os.getgid()).gr_name, ),
        permissions='440',
        sudo=True,
    )
    notification_plugin_storage_dir = '/var/spool/nagios/cloudifyreaction'
    run(['mkdir', '-p', notification_plugin_storage_dir], sudo=True)
    run(['restorecon', notification_plugin_storage_dir], sudo=True)
    run(['chown', 'nagios.nagios', notification_plugin_storage_dir], sudo=True)
    run(['chmod', '750', notification_plugin_storage_dir], sudo=True)

    ctx.logger.info('Preparing object paths')
    run(['rm', '-rf', BASE_OBJECTS_DIR], sudo=True)
    object_subdirs = [
        'checks',
        'commands',
        'contacts',
        'groups/group_instances',
        'groups/tenants',
        'groups/types',
        'templates',
        'timeperiods',
        'deployments',
        'snmp_traps',
        'targets',
        'target_types',
        'tenants',
    ]
    for subdir in object_subdirs:
        subdir = os.path.join(BASE_OBJECTS_DIR, subdir)
        run(['mkdir', '-p', subdir], sudo=True)
    run(['chown', '-R', OBJECT_OWNERSHIP, BASE_OBJECTS_DIR], sudo=True)
    run(['chmod', '-R', OBJECT_DIR_PERMISSIONS, BASE_OBJECTS_DIR], sudo=True)

    ctx.logger.info('Deploying nagios object configuration')
    config_source_dest_params = (
        # Fully qualified paths because these two go outside the objects dir
        ('cgi.cfg', '/etc/nagios/cgi.cfg', {
            'user': username
        }),
        ('nagios.cfg', '/etc/nagios/nagios.cfg', {}),
        # The rest are 'normal' configuration files
        ('base_system.cfg', 'base_system.cfg', {}),
        ('command_host_icmp.cfg', 'commands/check_host_icmp.cfg', {}),
        ('command_no_check.cfg', 'commands/no_check.cfg', {}),
        ('command_local_load.cfg', 'commands/check_local_load.cfg', {}),
        ('command_local_disk.cfg', 'commands/check_local_disk.cfg', {}),
        ('command_snmp_value.cfg', 'commands/check_snmp_value.cfg', {}),
        ('command_check_nagios_command_file.cfg',
         'commands/check_nagios_command_file.cfg', {}),
        ('command_snmp_aggregate.cfg', 'commands/check_snmp_aggregate.cfg',
         {}),
        ('command_group_aggregate.cfg', 'commands/check_group_aggregate.cfg',
         {}),
        ('command_group_meta_aggregate.cfg',
         'commands/check_group_meta_aggregate.cfg', {}),
        ('command_snmptrap_checks.cfg', 'commands/check_snmptrap_checks.cfg',
         {}),
        ('notification.cfg', 'commands/notify_automation.cfg', {}),
        ('contact.cfg', 'contacts/automation.cfg', {}),
        ('template_generic_service.cfg', 'templates/generic_service.cfg', {}),
        ('template_generic_host.cfg', 'templates/generic_host.cfg', {}),
        ('template_pseudo_host.cfg', 'templates/pseudo_host.cfg', {}),
        ('timeperiod_24x7.cfg', 'timeperiods/24x7.cfg', {}),
    )
    for source, dest, params in config_source_dest_params:
        deploy_configuration_file(
            ctx.logger,
            source=os.path.join('resources/base_configuration', source),
            destination=dest,
            template_params=params,
            # We can't validate before we've put all of the configuration in
            # place as it will be invalid until it's finished
            validate=False,
            # We can't reload, it's not running yet
            reload_service=False,
            sudo=True,
        )

    ctx.logger.info('Configuring httpd for ssl')
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/base_configuration/httpd.conf',
        ),
        destination='/etc/httpd/conf/httpd.conf',
        ownership='root.apache',
        permissions='440',
        sudo=True,
    )
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/base_configuration/ssl.conf',
        ),
        destination='/etc/httpd/conf.d/ssl.conf',
        ownership='root.apache',
        permissions='440',
        sudo=True,
    )

    ctx.logger.info('Configuring httpd for nagiosrest')
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/base_configuration/httpd_nagiosrest.conf',
        ),
        destination='/etc/httpd/conf.d/nagiosrest.conf',
        ownership='root.apache',
        permissions='440',
        sudo=True,
    )

    ctx.logger.info('Allowing nagiosrest to restart nagios')
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/base_configuration/sudoers-nagiosrest',
        ),
        destination='/etc/sudoers.d/nagios-service-restart',
        ownership='root.root',
        permissions='440',
        sudo=True,
    )

    ctx.logger.info('Deploying base SNMP configuration')
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/base_configuration/snmp',
        ),
        destination='/etc/snmp/snmp.conf',
        ownership='root.root',
        permissions='440',
        sudo=True,
    )

    trap_community = ctx.node.properties['trap_community']
    if trap_community:
        ctx.logger.info('Configuring SNMP traps to use handler')
        deploy_file(
            data=pkgutil.get_data(
                'managed_nagios_plugin',
                'resources/base_configuration/snmptrapd',
            ),
            destination='/etc/snmp/snmptrapd.conf',
            ownership='root.root',
            permissions='440',
            sudo=True,
            template_params={
                'trap_community': trap_community,
            },
        )

    ctx.logger.info('Configuring notification script')
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/base_configuration/incron.allow',
        ),
        destination='/etc/incron.allow',
        ownership='root.root',
        permissions='440',
        sudo=True,
    )
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/base_configuration/incron_root_spool',
        ),
        destination='/var/spool/incron/root',
        ownership='root.root',
        permissions='400',
        template_params={
            'homedir': os.path.expanduser('~'),
        },
        sudo=True,
    )
    agent_config_dir = os.path.join(
        os.path.expanduser('~'),
        '.cfy-agent',
    )
    agent_configs = [
        os.path.join(agent_config_dir, filename)
        for filename in os.listdir(agent_config_dir)
    ]
    # We'll use the most recently updated agent config
    current_agent_config = max(agent_configs, key=os.path.getmtime)
    run(
        [
            '/usr/local/bin/update_notify_cloudify_configuration',
            current_agent_config,
        ],
        sudo=True,
    )

    ctx.logger.info('Deploying logging configuration')
    level = props['component_log_level'].upper()
    validate_level = logging.getLevelName(level)
    if not isinstance(validate_level, int):
        raise NonRecoverableError(
            '{level} is not a valid logging level. '
            'It is recommended that component_log_level be set to one of '
            'DEBUG, INFO, WARNING, ERROR'.format(level=level))
    component_logging_config = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'default': {
                'format': '%(name)s(%(process)s) [%(levelname)s]: %(message)s',
            },
        },
        'handlers': {
            'syslog': {
                'formatter': 'default',
                'level': level,
                'class': 'logging.handlers.SysLogHandler',
                'address': '/dev/log',
            },
        },
        'loggers': {
            '': {
                'handlers': ['syslog'],
                'level': level,
                'propagate': True,
            },
        },
    }
    deploy_file(
        data=json.dumps(component_logging_config),
        destination='/etc/nagios/cloudify_components_logging.cfg',
        ownership='root.nagios',
        permissions='440',
        sudo=True,
    )
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/base_configuration/logrotate_config',
        ),
        destination='/etc/logrotate.d/managed_nagios',
        ownership='root.root',
        permissions='444',
        sudo=True,
    )
    deploy_file(
        data=pkgutil.get_data(
            'managed_nagios_plugin',
            'resources/base_configuration/rsyslog_config',
        ),
        destination='/etc/rsyslog.d/managed_nagios_logging.conf',
        ownership='root.root',
        permissions='444',
        sudo=True,
    )
    stop_service('rsyslog')
    start_service('rsyslog')
def create_target_type(logger, name, description, check_relationships,
                       instance_failure_reaction, instance_health_check,
                       check_interval, retry_interval, max_check_retries):
    deploy_configuration_file(
        logger,
        source='resources/target_type.template',
        destination=get_target_type_configuration_destination(name),
        template_params={
            'name': name,
            'description': description,
        },
        reload_service=False,
        sudo=True,
    )

    deploy_configuration_file(
        logger,
        source='resources/target_type_host_template.template',
        destination=get_target_type_host_template_destination(name),
        template_params={
            'target_type': name,
            'check_command': instance_health_check,
            'check_interval': check_interval,
            'retry_interval': retry_interval,
            'max_check_retries': max_check_retries,
        },
        reload_service=False,
        sudo=True,
    )

    reactions = {'checks': {}, 'traps': {}}
    for check in check_relationships:
        props = check.node.properties
        # To avoid warnings in the logs, we'll set all notifications to 1
        # minute, or the check_interval, whichever is higher. This means that
        # notifications will be retried every minute or every check_interval
        # if health state of a check does not improve.
        # Nagios will not send notifications more often than check_interval,
        # and will leave a warning in the logs every time it reloads
        # configuration for each notification_interval that is set lower
        # than check_interval.
        notification_interval = max(1, int(props.get('check_interval', 1)))
        if check.node.type == 'cloudify.nagios.nodes.SNMPTrapReaction':
            normalised_oid = oid_lookup.get(props['trap_oid'])
            if props['reaction']:
                reactions['traps'][normalised_oid] = {
                    'workflow': make_workflow_object(
                        props['reaction'],
                    ),
                    'constraints': {
                        'min_instances': props['min_instances'],
                        'max_instances': props['max_instances'],
                    }
                }
            params = {
                'target_type': name,
                'oid': normalised_oid,
            }
            check_type = 'trap'
            disallowed = []
        elif check.node.type == 'cloudify.nagios.nodes.SNMPValueCheck':
            params = {
                'target_type': name,
                'check_description': props['check_description'],
                'snmp_oid': props['snmp_oid'],
                'low_warning_threshold': props['low_warning_threshold'],
                'low_critical_threshold': props['low_critical_threshold'],
                'high_warning_threshold': props['high_warning_threshold'],
                'high_critical_threshold': props['high_critical_threshold'],
                'max_check_retries': props['max_check_retries'],
                'check_interval': props['check_interval'],
                'retry_interval': props['retry_interval'],
                'notification_interval': notification_interval,
                'rate': '--rate' if props['rate_check'] else ''
            }
            check_type = 'snmp_poll'
            disallowed = []
        elif check.node.type == (
            'cloudify.nagios.nodes.SNMPAggregateValueCheck'
        ):
            params = {
                'target_type': name,
                'check_description': props['check_description'],
                'snmp_oids': props['snmp_oids'],
                'on_unknown': props['on_unknown'],
                'aggregation_type': props['aggregation_type'],
                'low_warning_threshold': props['low_warning_threshold'],
                'low_critical_threshold': props['low_critical_threshold'],
                'high_warning_threshold': props['high_warning_threshold'],
                'high_critical_threshold': props['high_critical_threshold'],
                'max_check_retries': props['max_check_retries'],
                'check_interval': props['check_interval'],
                'retry_interval': props['retry_interval'],
                'notification_interval': notification_interval,
                'rate': '--rate' if props['rate_check'] else ''
            }
            check_type = 'snmp_aggregate'
            disallowed = ['{{instance}}']
        else:
            raise NonRecoverableError(
                'Cannot parse check of type {node_type}'.format(
                    node_type=check.node.type,
                )
            )

        reaction = {}
        # Trap reactions are deployed separately
        if check_type != 'trap':
            for level in ('low', 'high'):
                property_name = 'action_on_{level}_threshold'.format(
                    level=level,
                )
                min_instances_limit_name = '{level}_min_instances'.format(
                    level=level,
                )
                max_instances_limit_name = '{level}_max_instances'.format(
                    level=level,
                )
                if props[property_name]:
                    action = make_workflow_object(props[property_name],
                                                  disallowed=disallowed)
                    reaction[level] = {
                        'workflow': action,
                        'constraints': {
                            'min_instances': props[min_instances_limit_name],
                            'max_instances': props[max_instances_limit_name],
                        }
                    }

        create_check(logger, check_type, name, check.node.id, params)

        if reaction:
            reactions['checks'][props['check_description']] = reaction

    host_reaction = make_workflow_object(instance_failure_reaction)
    if host_reaction:
        reactions['host'] = {'workflow': host_reaction}

    deploy_file(
        data=json.dumps(reactions),
        destination=get_reaction_configuration_destination(name),
        sudo=True,
    )

    trigger_nagios_reload(set_group=True)
def create_group(ctx):
    props = ctx.node.properties
    name = props['name']

    if ':' in name or '/' in name:
        raise NonRecoverableError('Group names must not contain : or /.')

    ctx.logger.info('Getting related checks')
    check_relationships = get_all_relationship_targets(
        ctx=ctx,
        target_relation_type='group_check',
        no_target_error=('Group types must be connected to 1+ checks with '
                         'relationship {target_relation_type}'),
    )
    allowed_check_types = ('cloudify.nagios.nodes.SNMPAggregateValueCheck', )
    for check in check_relationships:
        if check.node.type not in allowed_check_types:
            raise NonRecoverableError(
                'Group checks only support targeting checks of type: '
                '{allowed}'.format(allowed=', '.join(allowed_check_types), ))

    ctx.logger.info('Generating group configuration')
    group_checks = get_all_relationship_targets(
        ctx=ctx,
        target_relation_type='group_check',
        no_target_error=('Check groups must be associated with checks.'),
    )
    check_descriptions = [
        check.node.properties['check_description'] for check in group_checks
    ]

    configuration = {
        "services": check_descriptions,
        "reactions": {},
        "check_configuration": {
            "unknown": props["on_unknown"],
            "approach": props["aggregation_type"],
            "check_interval": props["check_interval"],
            "low_warning_threshold": props["low_warning_threshold"],
            "low_critical_threshold": props["low_critical_threshold"],
            "high_warning_threshold": props["high_warning_threshold"],
            "high_critical_threshold": props["high_critical_threshold"],
        },
    }
    for level in 'low', 'high':
        action_name = 'action_on_{level}_threshold'.format(level=level)
        if props[action_name]['workflow_id']:
            configuration['reactions'][level] = {
                'workflow': props[action_name]
            }

    ctx.logger.info('Creating group subdirectories')
    for subdir in ('groups/tenants', 'groups/types', 'groups/members',
                   'groups/checks'):
        make_config_subdir(subdir, sudo=True)

    ctx.logger.info('Creating group base configuration')
    deploy_file(
        data=json.dumps(configuration),
        destination=os.path.join(
            BASE_OBJECTS_DIR,
            'groups/types/{name}.json'.format(name=hashlib.md5(
                name.encode('utf-8')).hexdigest(), )),
        sudo=True,
    )

    ctx.logger.info('Deploying check list')
    check_list = [
        check.node.properties['check_description']
        for check in check_relationships
    ]
    deploy_file(
        data=json.dumps(check_list),
        destination=os.path.join(
            BASE_OBJECTS_DIR, 'groups/checks/{name}.json'.format(name=name, )),
        sudo=True,
    )

    ctx.logger.info('Creating hostgroup')
    deploy_configuration_file(
        ctx.logger,
        source='resources/group_type.template',
        destination=os.path.join('groups/types', name + '.cfg'),
        template_params={
            'group_name': name,
        },
        reload_service=True,
        sudo=True,
    )
def create(ctx):
    name = ctx.node.properties['name']
    description = ctx.node.properties['alias']

    ctx.logger.info('Validating instance health check command')
    available_checks = (
        'do-not-check',
        'check-host-icmp',
    )
    if ctx.node.properties['instance_health_check'] not in available_checks:
        raise NonRecoverableError(
            'Command "{cmd}" specified by instance_health_check was invalid. '
            'Valid options are: {options}'.format(
                cmd=ctx.node.properties['instance_health_check'],
                options=', '.join(available_checks),
            ))

    ctx.logger.info('Using most secure available SNMP configuration')
    connection_config = ConfigParser()
    connection_config.add_section('snmp_params')
    snmp_props = ctx.node.properties['snmp_properties']
    snmp_params = None

    # Pick the most secure snmp settings provided
    if snmp_props['v3']['username'] is not None:
        snmp_params = {
            'protocol': 3,
            'seclevel': 'authPriv',
            'authproto': 'SHA',
            'privproto': 'AES',
            'secname': snmp_props['v3']['username'],
            'authpasswd': snmp_props['v3']['auth_pass'],
            'privpasswd': snmp_props['v3']['priv_pass'],
        }
        if snmp_props['v3'].get('context'):
            snmp_params['context'] = snmp_props['v3']['context']
    elif snmp_props['v2c']['community'] is not None:
        snmp_params = {
            'protocol': '2c',
            'community': snmp_props['v2c']['community'],
        }

    if snmp_params is None:
        raise NonRecoverableError(
            'Currently checks require SNMP configuration.')
    else:
        for key, value in snmp_params.items():
            connection_config.set('snmp_params', key, text_type(value))
        connection_config_text = _FakeFile()
        connection_config.write(connection_config_text)
        deploy_file(
            data=text_type(connection_config_text),
            destination=get_connection_config_location(name),
            sudo=True,
        )

    ctx.logger.info('Getting related checks')
    check_relationships = get_all_relationship_targets(
        ctx=ctx,
        target_relation_type='target_type_checks',
        no_target_error=('Target types must be connected to 1+ checks with '
                         'relationship {target_relation_type}'),
    )

    ctx.logger.info('Deploying configuration')
    create_target_type(
        ctx.logger,
        name,
        description,
        check_relationships,
        instance_failure_reaction=ctx.node.
        properties['action_on_instance_failure'],
        instance_health_check=ctx.node.properties['instance_health_check'],
        check_interval=ctx.node.properties['check_interval'],
        retry_interval=ctx.node.properties['retry_interval'],
        max_check_retries=ctx.node.properties['max_check_retries'],
    )