Skip to content
This repository has been archived by the owner on Sep 30, 2023. It is now read-only.

Feature: Request a one time run of a runbook #127

Open
dcs02d opened this issue Sep 11, 2018 · 1 comment
Open

Feature: Request a one time run of a runbook #127

dcs02d opened this issue Sep 11, 2018 · 1 comment

Comments

@dcs02d
Copy link

dcs02d commented Sep 11, 2018

Would it be possible to request a one time run of a runbook from a node:

ie -
[root@mynode]# curl http://automatron.server/runbooks/calc

Would force a one time run of a runbook named calc ?

Alternatively I can write a command line utility to parse the various yaml files and run the appropriate playbooks at the command line assuming the local node had a copy of ./conf/*

@dcs02d
Copy link
Author

dcs02d commented Sep 13, 2018

A script that reads ./config/runbooks/init.yml and runs appropriate runbooks by hostname.

This lets me run through a series of runbooks at the command line on a specific host for debugging.

It will run a check over and over if it fails until there are no possible actions left (by trigger count)

-- It only runs actions / checks that are specified as 'cmd' and 'target'
-- Now it runs plugins for checks and I'll update it when it runs plugins for actions.
-- Runs plugins for actions as well.

Thanks again for the software. This potentially works quite nicely for a master-less puppet environment where specific manifests can update / fix things with a puppet apply.

#!/usr/bin/python

import os
# yum install PyYAML.x86_64
import yaml
import socket
import re
import glob
import subprocess

script_path = os.path.dirname(os.path.realpath(__file__))

def run_command(cmd):
    try:
        res = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True);
        output,error = res.communicate()
        #if output:
            #print "\treturn code> ",res.returncode
            #print "\tOK> output ",output
        #if error:
        #    print "\treturn code> ",res.returncode
        #    print "\tError> error ",error.strip()
        return res.returncode
    except OSError as e:
        print "\tOSError > ",e.errno
        print "\tOSError > ",e.strerror
        print "\tOSError > ",e.filename
        return e.errno
    except:
        print "\tError > ",sys.exc_info()[0]
        return sys.exc_info()[0]

def action_lookup(this_run_dict, return_code = 0, trigger_count = 0):
    print "\t\tLooking up actions - Trigger count: ", trigger_count
    if return_code != 0 and return_code != 1 and return_code != 2:
        return_code = 3
        print "\t\tConverted return code"
    codes = {
		0 : "OK",
		1 : "WARNING",
		2 : "CRITICAL",
        3 : "UNKNOWN"
	}
    keep_trying = False
    if this_run_dict["actions"] is None:
        return False

    for this_action in this_run_dict["actions"]:
        if this_run_dict["actions"][this_action]['trigger'] is not None:
            if this_run_dict["actions"][this_action]['trigger'] >= trigger_count:
                keep_trying = True

    if keep_trying:
        for this_action in this_run_dict["actions"]:
            if (    codes[return_code] in this_run_dict["actions"][this_action]['call_on'] and
                    this_run_dict["actions"][this_action]['execute_from'].lower() == "target" and
                    ( this_run_dict["actions"][this_action]['type'].lower() == "cmd" or
                      this_run_dict["actions"][this_action]['type'].lower() == "plugin" ) and
                    this_run_dict["actions"][this_action]['trigger'] == trigger_count ):

                my_cmd = None
                if this_run_dict["actions"][this_action]['type'].lower() == "cmd":
                    my_cmd = "sleep " + str(this_run_dict["actions"][this_action]['frequency']) + " && " + this_run_dict["actions"][this_action]['cmd']
                if this_run_dict["actions"][this_action]['type'].lower() == "plugin":
                    my_cmd = "sleep " + str(this_run_dict["actions"][this_action]['frequency']) + " && " + script_path + "/plugins/actions/" + this_run_dict["actions"][this_action]['plugin'] + " " + this_run_dict["actions"][this_action]['args']

                print "\t\tRunning:" + my_cmd,

                result_code = run_command(my_cmd)
                if result_code != 0:
                    print ".....ERROR"
                else:
                    print ".....OK"
        return True
    else:
        print "No more actions to try... moving on"
        return False

hostname = socket.gethostname()
init_yml = "./config/runbooks/init.yml"
print "\n\nLooking at " + init_yml + " for matches on " + hostname + ":\n\n"
yaml_dict = yaml.load(open(init_yml))

# Begin loop for each matching hostgroup in config/runbook/init.yml
for k in yaml_dict:
    pattern = re.compile(k)
    if pattern.match(hostname):
        print "Found Matching entry " + k
        for runbook in yaml_dict[k]:
            print "\n\nExecuting Runbook(s) for: " + runbook
            # Loop through each subdirectory in runbooks looking for any yml filename
            for yml_file in glob.glob("./config/runbooks/" + runbook + "/*.yml"):
                #print "\t\t" + yml_file
                this_run_dict = yaml.load(open(yml_file))
                for this_check in this_run_dict["checks"]:
                    # if the type is command and it is set to run from the host then run it
                    # We'll use the Trigger amd Frequency as defined by automatron

                    trigger = 0
                    if (    this_run_dict["checks"][this_check]['execute_from'].lower() == "target" and
                            (this_run_dict["checks"][this_check]['type'].lower() == "cmd" or
                            this_run_dict["checks"][this_check]['type'].lower() == "plugin")
                    ):
                        my_cmd = None
                        run_cmd = True
                        if this_run_dict["checks"][this_check]['type'].lower() == "cmd":
                            my_cmd = this_run_dict["checks"][this_check]['cmd']

                        if this_run_dict["checks"][this_check]['type'].lower() == "plugin":
                            my_cmd = script_path + "/plugins/checks/" + this_run_dict["checks"][this_check]['plugin'] + " " + this_run_dict["checks"][this_check]['args']

                        while run_cmd:
                            print "\tRunning:" + my_cmd,
                            result_code = run_command(my_cmd)
                            if result_code != 0:
                                trigger += 1
                                print ".....Failed"
                                run_cmd = action_lookup(this_run_dict, result_code, trigger)
                            else:
                                print ".....Passed"
                                run_cmd = False


Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant