예제 #1
0
파일: config.py 프로젝트: zloeber/aws-aware
def reset():
    """
    Resets default values for any configuration element that is not an empty string by default. This includes log and job paths and could be useful for migrating a deployment between operating systems.
    """
    OUTPUT.info('Resetting configuration file with default values.')
    CFG.reset_default_values()
    CFG.save()
예제 #2
0
파일: config.py 프로젝트: zloeber/aws-aware
def upgrade():
    """
    Upgrade a global configuration file with any missing elements.
    """
    OUTPUT.info(
        'Updating configuration file with any new global config options')
    CFG.merge_default_values()
    CFG.save()
예제 #3
0
파일: config.py 프로젝트: zloeber/aws-aware
def export():
    """
    Exports configuration settings as commands.
    """
    for key, val in CFG.values.items():
        commandout = 'aws-aware -configfile {0} config change {1} {2}'.format(
            CFG.config_file, key, val)
        OUTPUT.info(commandout)
예제 #4
0
    def exit_with_exception(self, cause='General Failure'):
        """
        This will result in exiting the application and cause tasks to
        return with failure status.

        PARAMETER: cause
        """

        OUTPUT.error('Exiting with exception cause: {0}'.format(str(cause)))
        sys.exit(1)
예제 #5
0
    def send_notice(self):
        """
        Send job status update notifications if required.
        """
        if self.should_send_alert() or self.should_send_warning(
        ) or self.runargs['force']:
            # Send email notification to passed argument recipients if defined,
            #  otherwise send to stored recipients.
            recipients = self.runargs['emailrecipients']

            if recipients:
                status = 'Normal'
                if self.warningthresholdreached:
                    status = 'Warning'
                if self.alertthresholdreached:
                    status = 'Alert'
                # Jinja requires this entire data structure for the included
                # templates. recipients are automatically split by semicolon and sent to
                # individually.

                emaildata = {
                    "emailtitle":
                    "AWS Aware Status: {0}".format(status),
                    "date":
                    date.today().strftime('%m/%d/%Y'),
                    "monitors":
                    self.monitorjobs,
                    "costcenter":
                    self.eval_filter('costcenter'),
                    "environment":
                    self.eval_filter('environment'),
                    "appname":
                    self.eval_filter('appname'),
                    "instances":
                    self.get_instances(),
                    "allinstances":
                    self.get_instances(filtered=True),
                    "view":
                    self.view,
                    "additionalnotes":
                    'Please review these thresholds and take appropriate action to reduce instance counts down to the approved level. Below are all instances with tag filters matching your CostCenter, Environment, and Application Name (but grouped by Process Name). Attached is a report of all instances returned in this environment for further review.'
                }
                CFG.emailhandler.send_email_template(
                    jinjatemplate='email-html_instance_monitor',
                    jinjadata=emaildata,
                    subject="AWS Aware Status: {0}".format(status),
                    recipients=str(recipients).split(';'))
            else:
                OUTPUT.warning(
                    'There are no recipients passed or defined for this job. Exiting.'
                )
예제 #6
0
파일: config.py 프로젝트: zloeber/aws-aware
def new(filename):
    """
    Create a new global configuration file.
    """
    if filename is None:
        filename = os.path.join(os.path.abspath(os.path.curdir), 'config.yml')
    else:
        filename = os.path.abspath(filename)

    OUTPUT.info(
        'Attempting to save new configuration file to: {0}'.format(filename))
    _newconfig = Settings()
    _newconfig.set_config_default_values()
    _newconfig.save_to_file(filename=filename)
예제 #7
0
 def send_slack_notification(self, force=False):
     """Send a slack notification"""
     if force or self.should_send_warning() or self.should_send_alert():
         if ('slack_webhooks' in CFG.values) and ('slack_notifications'
                                                  in CFG.values):
             if CFG.values['slack_webhooks'] and CFG.values[
                     'slack_notifications']:
                 slk = SlackPoster(CFG.values['slack_webhooks'])
                 slackmessage = self.get_slackmessage()
                 if slackmessage:
                     slk.post_message(slackmessage)
             else:
                 OUTPUT.info(
                     'Slack notifications not enabled or there are no webhooks defined.'
                 )
예제 #8
0
def export(ctx):
    """
    Exports all raw instance data without any filtering. Useful for pre-caching.
    """
    run_args = ctx.copy()
    suppressoutput = run_args['terse'] or CFG.values.get(
        'suppressconsoleoutput')
    OUTPUT.header('Check Thresholds', suppress=suppressoutput)

    # Load up default monitors and instantiate a task object
    monitortask = MonitorTasks(runargs=run_args)

    # Pull aws information
    try:
        OUTPUT.info('Polling AWS')
        monitortask.poll_instance_data()
    except Exception as monitorclassexception:
        raise monitorclassexception
예제 #9
0
def run(ctx,
        awsprofile=None,
        awsid=None,
        awsregion=None,
        emailrecipients=None,
        terse=False,
        verbose=False,
        force=False,
        datapath=None,
        **kwargs):
    """
    Run aws-aware actions
    """
    # First get all of our common run args. If not passed in,
    #  they will be updated with global config values (if they line up)
    #  Then we look in the global config for explict mappings
    #  (name differences) that exist
    OUTPUT.info(
        'Merging common run arguments with global config file settings.',
        suppress=True)
    RUN_ARGS = RUNARGS.copy()
    for key, val in RUN_ARGS.items():
        RUN_ARGS[key] = kwargs.pop(key, val)
        # Did we get an empty (unpassed) run argument?
        if RUN_ARGS[key] is None:
            # Do we have the same argument in CFG?
            if key in CFG.values:
                # Does it have a value? Great, lets use it
                if CFG.values[key] is not None:
                    RUN_ARGS[key] = CFG.values[key]

    # Sanitize run args for Tibco's sake *sigh*
    #for key, val in RUN_ARGS.items():
    #    # if we get passed in '' or "" then convert to empty string
    #    if val == "''" or val == '""':
    #        RUN_ARGS[key] = ''
    #    # if we get passed in null or Null convert to None
    #    if val == 'null' or val == 'Null':
    #        RUN_ARGS[key] = None
    ctx = click.get_current_context()
    RUN_ARGS = UTIL.santize_arguments(RUN_ARGS)
    ctx.obj = RUN_ARGS
예제 #10
0
def test(**kwargs):
    """
    Script testing
    """
    # First get all of our common run args. If not passed in,
    #  they will be updated with global config values (if they line up)
    #  Then we look in the global config for explicit mappings (name differences) that exist

    OUTPUT.info(
        'Merging common test arguments with global config file settings.',
        suppress=True)
    for key, val in RUNARGS.items():
        TESTARGS[key] = kwargs.pop(key, val)
        # Did we get an empty (unpassed) run argument?
        if TESTARGS[key] is None:
            # Do we have the same argument in CFG?
            if key in CFG.values:
                # Does it have a value? Great, lets use it
                if CFG.values[key] is not None:
                    TESTARGS[key] = CFG.values[key]

    suppressoutput = TESTARGS['terse'] or CFG.values.get(
        'suppressconsoleoutput')
    OUTPUT.header('TESTING', suppress=suppressoutput)
예제 #11
0
 def _add_log(self, mylog, logtype='info'):
     """Add a log generated from this module"""
     if logtype == 'error':
         OUTPUT.error('{0}: {1}'.format(str(self.__class__.__name__),
                                        str(mylog)))
     elif logtype == 'warning':
         OUTPUT.warning('{0}: {1}'.format(str(self.__class__.__name__),
                                          str(mylog)))
     else:
         OUTPUT.info('{0}: {1}'.format(str(self.__class__.__name__),
                                       str(mylog)))
예제 #12
0
def aws():
    """
    Test AWS connectivity
    """
    OUTPUT.info('TEST: Validating AWS connectivity')

    try:
        monitortask = MonitorTasks(runargs=TESTARGS)
        OUTPUT.info('Testing AWS connectivity')
        monitortask.instantiate_aws()
        OUTPUT.echo('AWS Test Success!', color='green')

    except Exception as awsawareexception:
        raise awsawareexception
예제 #13
0
파일: config.py 프로젝트: zloeber/aws-aware
def change(whatif, element, value):
    """
    Set script configuration elements. These are saved for future script runs.
    """
    if element in CFG.values:
        if whatif:
            OUTPUT.info('Would have updated {0} to {1}'.format(
                CFG.values[element], value))
        else:
            OUTPUT.info('Updating {0} to {1}'.format(element, value))
            CFG.values[element] = value
            CFG.save()
    else:
        OUTPUT.error('No configuration element exists for {0}'.format(element))
예제 #14
0
    def show_monitors(self):
        """Prints information about current monitors to console"""
        try:
            OUTPUT.info('Loading and displaying monitors')

            outlines = []
            outlines.append([
                'name', 'thresholdtype', 'warn_thresh', 'alert_thresh',
                'enabled'
            ])
            for monitor in self.monitorjobs:
                outlines.append(monitor.show())

            col_width = max(len(word) for row in outlines for word in row) + 2
            # padding
            for row in outlines:
                OUTPUT.echo("".join(word.ljust(col_width) for word in row))

        except Exception as monitorexception:
            OUTPUT.error('Unable to print monitor output')
            raise monitorexception
예제 #15
0
def awsdownload(sourcefile, destpath=None):
    """
    Test aws ability to download a specific file
    """
    OUTPUT.info('TEST: Validating aws file download ability')
    if destpath is None:
        destpath = os.path.join(os.path.abspath(os.path.curdir), sourcefile)
        OUTPUT.info(
            'Using current directory and source file name as destination file path: {0}'
            .format(destpath))
    else:
        destpath = os.path.abspath(destpath)

    try:
        monitortask = MonitorTasks(runargs=TESTARGS)
        OUTPUT.info('Connecting to aws')
        monitortask.instantiate_aws()
        OUTPUT.echo('..Connected to AWS', color='green')
    except Exception as awsawareexception:
        raise awsawareexception

    s3fullfilepath = '{0}/{1}'.format(TESTARGS['s3path'], sourcefile)
    OUTPUT.info('Attempting to download file - {0}'.format(s3fullfilepath))
    s3url = urlparse(s3fullfilepath)
    downloaded = monitortask.aws.download_s3_file(bucket=s3url.netloc,
                                                  path=s3url.path.lstrip('/'),
                                                  destpath=destpath)

    if downloaded:
        OUTPUT.echo('..SUCCESS!', color='green')
    else:
        OUTPUT.echo('..FAILED!', color='red')
예제 #16
0
파일: config.py 프로젝트: zloeber/aws-aware
def get(element):
    """
    Show a single configuration element.
    """
    if element in CFG.values:
        OUTPUT.configelement(name=element, value=CFG.values[element])
예제 #17
0
파일: config.py 프로젝트: zloeber/aws-aware
def logpath():
    """
    Output the current configuration log file path
    """
    OUTPUT.configelement(name='Path', value=CFG.get_logpath())
예제 #18
0
파일: config.py 프로젝트: zloeber/aws-aware
def path():
    """
    Display configuration file path
    """
    OUTPUT.configelement(name='Path', value=CFG.config_file)
예제 #19
0
파일: config.py 프로젝트: zloeber/aws-aware
def show():
    """
    Show script configuration
    """
    for key, val in CFG.values.items():
        OUTPUT.configelement(name=key, value=val)
예제 #20
0
    def send_notice_with_report(self):
        """
        Send job status update notifications if required.
        """
        if self.should_send_alert() or self.should_send_warning(
        ) or self.runargs['force']:
            # Send email notification to passed argument recipients if defined,
            #  otherwise send to stored recipients.
            recipients = self.runargs['emailrecipients']

            if recipients:
                status = 'Normal'
                if self.warningthresholdreached:
                    status = 'Warning'
                if self.alertthresholdreached:
                    status = 'Alert'
                # Jinja requires this entire data structure for the included
                # templates. recipients are automatically split by semicolon and sent to
                # individually.

                reportdata = {
                    "title": 'All Instances',
                    "date": date.today().strftime('%m/%d/%Y'),
                    "monitors": self.monitorjobs,
                    "costcenter": '*',
                    "environment": '*',
                    "appname": '*',
                    "instances": self.get_instances(),
                    "allinstances": self.get_instances(filtered=True),
                    "additionalnotes": 'Includes running instances only.'
                }
                CFG.emailhandler.save_html_report(
                    jinjatemplate='report-html_instance_details',
                    jinjadata=reportdata)

                emaildata = {
                    "emailtitle":
                    "AWS Aware Status: {0}".format(status),
                    "date":
                    date.today().strftime('%m/%d/%Y'),
                    "monitors":
                    self.monitorjobs,
                    "costcenter":
                    self.eval_filter('costcenter'),
                    "environment":
                    self.eval_filter('environment'),
                    "appname":
                    self.eval_filter('appname'),
                    "instances":
                    self.get_instances(),
                    "view":
                    self.view,
                    "additionalnotes":
                    'Please review these thresholds and take appropriate action to reduce instance counts to the approved level. (Save, then open the attached report for further instance details grouped by the ProcessName tag)'
                }
                CFG.emailhandler.send_email_template(
                    jinjatemplate='email-html_instance_monitor',
                    jinjadata=emaildata,
                    subject="AWS Aware Status: {0}".format(status),
                    recipients=str(recipients).split(';'),
                    attachments=['./aws-instance-report.html'])
            else:
                OUTPUT.warning(
                    'There are no recipients passed or defined for this job. Exiting.'
                )
예제 #21
0
파일: config.py 프로젝트: zloeber/aws-aware
def config(terse):
    """
    Script configuration
    """
    suppressoutput = terse or CFG.values.get('suppressconsoleoutput')
    OUTPUT.header('SCRIPT CONFIGURATION', suppress=suppressoutput)
예제 #22
0
    def send_instance_report(self, filteredinstances=False):
        """
        Send instance report.
        """
        # Send email notification to passed argument recipients if defined,
        #  otherwise send to stored recipients.
        recipients = self.runargs['emailrecipients']
        instances = self.get_instances(filtered=filteredinstances)
        instancecounts = self.get_all_instance_counts(instances=instances)
        if recipients:
            status = 'Normal'
            if self.warningthresholdreached:
                status = 'Warning'
            if self.alertthresholdreached:
                status = 'Alert'
            # Get instance counts
            # Jinja requires this entire data structure for the included
            # templates. recipients are automatically split by semicolon and sent to
            # individually.
            reportdata = {
                "title": 'Instance Report - {0}'.format(status),
                "date": date.today().strftime('%m/%d/%Y'),
                "view": self.view,
                "monitors": self.monitorjobs,
                "costcenter": self.eval_filter('costcenter'),
                "environment": self.eval_filter('environment'),
                "appname": self.eval_filter('appname'),
                "instances": instances,
                "instancecounts": instancecounts,
                "additionalnotes": '(Includes running instances only.)'
            }

            CFG.emailhandler.save_html_report(
                jinjatemplate='report-html_instance_details',
                jinjadata=reportdata)

            emaildata = {
                "emailtitle":
                "AWS Instances: Status = {0}".format(status),
                "date":
                date.today().strftime('%m/%d/%Y'),
                "view":
                self.view,
                "monitors":
                self.monitorjobs,
                "costcenter":
                self.eval_filter('costcenter'),
                "environment":
                self.eval_filter('environment'),
                "appname":
                self.eval_filter('appname'),
                "instances":
                None,
                "additionalnotes":
                'To view this report please save it locally then open in your browser. Only running instances are included. Clusters are sorted by name then instance type. Review all clusters to ensure they are aligned with your application requirements.'
            }

            emaildata['instances'] = self.get_instances(
                filtered=filteredinstances)
            emaildata['costcenter'] = self.eval_filter('costcenter')
            emaildata['environment'] = self.eval_filter('environment')
            emaildata['appname'] = self.eval_filter('appname')

            CFG.emailhandler.send_email_template(
                jinjatemplate='email-html_instance_monitor',
                jinjadata=emaildata,
                subject="AWS Aware Instance Report",
                recipients=str(recipients).split(';'),
                attachments=['./aws-instance-report.html'])
        else:
            OUTPUT.warning(
                'There are no recipients passed or defined for this job. Exiting.'
            )
예제 #23
0
    def poll_instance_data(self):
        """Poll AWS for data we need"""
        if self.skipprobe:
            # Pull prior aws information
            try:
                OUTPUT.info('Loading prior instance data: {0}'.format(
                    self.datapath))
                self.allinstances = self.load_instance_data(
                    datapath=self.datapath)
            except Exception as monitorclassexception:
                raise monitorclassexception

            self.instances = self.allinstances
            for filtername in self.filters.keys():
                if self.eval_filter(filtername) != '*':
                    results = [
                        i for i in results
                        if i[filtername] == self.eval_filter(filtername)
                    ]
            # if self.eval_filter('environment') != '*':
            #     self.instances = [i for i in self.instances if i['Environment'] == self.eval_filter('environment')]
            # if self.eval_filter('appname') != '*':
            #     self.instances = [i for i in self.instances if i['ApplicationName'] == self.eval_filter('appname')]
            # if self.eval_filter('costcenter') != '*':
            #     self.instances = [i for i in self.instances if i['CostCenter'] == self.eval_filter('costcenter')]
        else:
            self._add_log('Polling AWS for instance data')
            # Get aws going
            try:
                OUTPUT.info('Instantiating connection to AWS first...')
                self.instantiate_aws()
            except Exception as monitorclassexception:
                raise monitorclassexception

            otherfilters = []

            # Other filter definitions
            # Running instances
            otherfilters.append({
                'Name': 'instance-state-name',
                'Values': self.view['instance_state']
            })
            if len(self.filters) > 0:
                for filtername in self.filters.keys():
                    if self.eval_filter(filtername) != '*':
                        self._add_log(
                            'Other Filter Added - {0}'.format(filtername))
                        otherfilters.append({
                            'Name':
                            'tag:{0}'.format(filtername),
                            'Values': [self.eval_filter(filtername)]
                        })

            # # Particular cost center
            # tag_cc = str(self.eval_filter('costcenter'))
            # self._add_log('Other Filter - CostCenter: {0}'.format(tag_cc))
            # otherfilters.append({'Name': 'tag:CostCenter', 'Values': [tag_cc]})

            # # ApplicationName
            # tag_app = str(self.eval_filter('appname'))
            # self._add_log('Other Filter - ApplicationName: {0}'.format(tag_app))
            # otherfilters.append({'Name': 'tag:ApplicationName', 'Values': [tag_app]})

            # # Environment
            # tag_env = str(self.eval_filter('environment'))
            # self._add_log('Other Filter - Environment: {0}'.format(tag_env))
            # otherfilters.append({'Name': 'tag:Environment', 'Values': [tag_env]})

            self._add_log('Instance filters applied: {0}'.format(
                len(otherfilters)))
            # Basic instance dictionary list result with some additional tags.
            self.allinstances = self.aws.aws_instances_brief(
                otherfilters=otherfilters, tags=self.view['instance_tags'])

            self._add_log('AWS instances found: {0}'.format(
                len(self.allinstances)))

            if self.allinstances:
                self._add_log('Inferring clustername attributes...')
                for instance in self.allinstances:
                    instance['cluster'] = self.awsinstancename_to_clustername(
                        instance['name'])
            else:
                self._add_log('Zero AWS Instances found!')

            self.save_instance_data(filepath=self.runargs['datapath'])