Last active
September 18, 2018 22:14
-
-
Save zodman/529c6b01cc070d1e5337440adc61c1be to your computer and use it in GitHub Desktop.
rundeck tail log and project status
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# coding: utf-8 | |
from __future__ import unicode_literals | |
from __future__ import print_function | |
import logging | |
import os | |
import requests | |
import colorama | |
try: | |
# Python 2 | |
from urlparse import urljoin | |
except ModuleNotFoundError: | |
# Python 3 | |
from urllib.parse import urljoin | |
from requests.packages.urllib3.exceptions import InsecureRequestWarning | |
colorama.init() | |
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
class Rundeck(): | |
def __init__(self, rundeck_url, token=None, username=None, password=None, | |
api_version=18, verify=True): | |
self.rundeck_url = rundeck_url | |
self.API_URL = urljoin(rundeck_url, '/api/{}'.format(api_version)) | |
self.token = token | |
self.username = username | |
self.password = password | |
self.verify = verify | |
self.auth_cookie = self.auth() | |
def auth(self): | |
url = urljoin(self.rundeck_url, '/j_security_check') | |
p = {'j_username': self.username, 'j_password': self.password} | |
r = requests.post( | |
url, | |
params=p, | |
verify=self.verify, | |
# Disable redirects, otherwise we get redirected twice and need to | |
# return r.history[0].cookies['JSESSIONID'] | |
allow_redirects=False) | |
return r.cookies['JSESSIONID'] | |
def __request(self, method, url, params=None): | |
#logger.info('{} {} Params: {}'.format(method, url, params)) | |
cookies = {'JSESSIONID': self.auth_cookie} | |
h = { | |
'Accept': 'application/json', | |
'Content-Type': 'application/json', | |
'X-Rundeck-Auth-Token': self.token | |
} | |
r = requests.request( | |
method, url, cookies=cookies, headers=h, json=params, | |
verify=self.verify | |
) | |
logger.debug(r.content) | |
r.raise_for_status() | |
try: | |
return r.json() | |
except ValueError as e: | |
logger.error(e.message) | |
return r.content | |
def __get(self, url, params=None): | |
return self.__request('GET', url, params) | |
def __post(self, url, params=None): | |
return self.__request('POST', url, params) | |
def __delete(self, url, params=None): | |
return self.__request('DELETE', url, params) | |
def list_tokens(self, user=None): | |
url = '{}/tokens'.format(self.API_URL) | |
if user: | |
url += '/{}'.format(user) | |
return self.__get(url) | |
def get_token(self, token_id): | |
url = '{}/token/{}'.format(self.API_URL, token_id) | |
return self.__get(url) | |
def create_token(self, user): | |
url = '{}/tokens/{}'.format(self.API_URL, user) | |
return self.__post(url) | |
def delete_token(self, token_id): | |
url = '{}/token/{}'.format(self.API_URL, token_id) | |
return self.__delete(url) | |
def system_info(self): | |
url = '{}/system/info'.format(self.API_URL) | |
return self.__get(url) | |
def set_active_mode(self): | |
url = '{}/system/executions/enable'.format(self.API_URL) | |
return self.__post(url) | |
def set_passive_mode(self): | |
url = '{}/system/executions/disable'.format(self.API_URL) | |
return self.__post(url) | |
def list_system_acl_policies(self): | |
url = '{}/system/acl/'.format(self.API_URL) | |
return self.__get(url) | |
def get_acl_policy(self, policy): | |
url = '{}/system/acl/{}'.format(self.API_URL, policy) | |
return self.__get(url) | |
def list_projects(self): | |
url = '{}/projects'.format(self.API_URL) | |
return self.__get(url) | |
def list_jobs(self, project): | |
url = '{}/project/{}/jobs'.format(self.API_URL, project) | |
return self.__get(url) | |
def list_all_jobs(self): | |
jobs = [] | |
for p in self.list_projects(): | |
jobs += self.list_jobs(p['name']) | |
return jobs | |
def get_job(self, name, project=None): | |
if project: | |
jobs = self.list_jobs(project) | |
else: | |
jobs = [] | |
for p in self.list_projects(): | |
jobs += self.list_jobs(p['name']) | |
return next(job for job in jobs if job['name'] == name) | |
def run_job(self, job_id, args=None, options=None, log_level=None, | |
as_user=None, node_filter=None): | |
url = '{}/job/{}/run'.format(self.API_URL, job_id) | |
params = { | |
'logLevel': log_level, | |
'asUser': as_user, | |
'filter': node_filter | |
} | |
if options is None: | |
params["argString"] = args | |
else: | |
params["options"] = options | |
return self.__post(url, params=params) | |
def run_job_by_name(self, name, *args, **kwargs): | |
job = self.get_job(name) | |
return self.run_job(job['id'], *args, **kwargs) | |
def get_executions_for_job(self, job_id=None, job_name=None): | |
# http://rundeck.org/docs/api/#getting-executions-for-a-job | |
if not job_id: | |
if not job_name: | |
raise RuntimeError("Either job_name or job_id is required") | |
job_id = self.get_job(job_name).get('id') | |
url = '{}/job/{}/executions'.format(self.API_URL, job_id) | |
return self.__get(url) | |
def query_executions(self, project, name=None, group=None, status=None, | |
user=None, recent=None, adhoc=None): | |
# http://rundeck.org/docs/api/#execution-query | |
url = '{}/project/{}/executions'.format(self.API_URL, project) | |
params = { | |
'jobListFilter': name, | |
'userFilter': user, | |
'groupPath': group, | |
'statusFilter': status, | |
'adhoc': adhoc, | |
'recentFilter': recent | |
} | |
return self.__get(url, params=params) | |
def list_running_executions(self, project): | |
url = '{}/project/{}/executions/running'.format(self.API_URL, project) | |
return self.__get(url) | |
def execution_state(self, exec_id): | |
url = '{}/execution/{}/state'.format(self.API_URL, exec_id) | |
return self.__get(url) | |
def list_jobs_by_group(self, project, groupPath=None): | |
url = '{}/project/{}/jobs'.format(self.API_URL, project) | |
params = {'groupPath': groupPath} | |
return self.__post(url, params=params) | |
def execution_output_by_id(self, exec_id): | |
url = '{}/execution/{}/output?lastlines=20'.format(self.API_URL, exec_id) | |
return self.__get(url) | |
def execution_info_by_id(self, exec_id): | |
url = '{}/execution/{}'.format(self.API_URL, exec_id) | |
return self.__get(url) | |
def abort_execution(self, exec_id): | |
url = '{}/execution/{}/abort'.format(self.API_URL, exec_id) | |
return self.__get(url) | |
if __name__ == '__main__': | |
from pprint import pprint | |
rundeck_url = os.environ.get('RUNDECK_URL', "https://rundeck.interalia.net") | |
username = os.environ.get('RUNDECK_USER', "admin") | |
password = os.environ.get('RUNDECK_PASS', None) | |
if not password: | |
import getpass | |
#import tempfile | |
#import os | |
#tempdir = tempfile.gettempdir() | |
#filepass = os.path.join(tempdir, ".rundeckpass") | |
password = getpass.getpass() | |
assert rundeck_url, 'Rundeck URL is required' | |
assert username, 'Username is required' | |
assert password, 'Password is required' | |
rd = Rundeck( | |
rundeck_url, username=username, password=password, | |
verify=False | |
) | |
project = os.environ.get("RUNDECK_PROJECT", "*") | |
execs = rd.list_running_executions(project) | |
if not execs: | |
print("No deploy executions") | |
for i in execs.get("executions"): | |
print( colorama.Fore.GREEN + "{}/{} [{}]" .format(i.get("project"), i.get("job").get("name"), colorama.Style.DIM + colorama.Back.GREEN+ i.get("status") + colorama.Style.RESET_ALL )) | |
print(colorama.Style.RESET_ALL) | |
print("#### {}#ouput".format(i.get("permalink"))) | |
print(colorama.Style.RESET_ALL) | |
exec_id = i.get("id") | |
output = rd.execution_output_by_id(exec_id) | |
if output.get("entries"): | |
print("------ LOG -----") | |
print(colorama.Style.RESET_ALL) | |
for log in output.get("entries"): | |
print(log.get("log")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment