From 2b7694fcc23cdc8843227fad7db470925194785c Mon Sep 17 00:00:00 2001 From: Bert Tejeda Date: Wed, 10 May 2023 13:30:14 -0400 Subject: [PATCH] Update rollup --- confluence/create-page.py | 199 ++++++++++++++++++++++++++++++++++++++ git/get-bitbucketfile.ps1 | 40 ++++++++ remote/run.py | 10 +- servicenow/list.sh | 96 ++++++++++++++++++ shell/autocomplete.sh | 3 + shell/dotfiles.sh | 0 system/launcher.py | 8 +- 7 files changed, 346 insertions(+), 10 deletions(-) create mode 100755 confluence/create-page.py create mode 100755 git/get-bitbucketfile.ps1 create mode 100755 servicenow/list.sh create mode 100755 shell/autocomplete.sh create mode 100755 shell/dotfiles.sh diff --git a/confluence/create-page.py b/confluence/create-page.py new file mode 100755 index 0000000..db5b485 --- /dev/null +++ b/confluence/create-page.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +__author__ = 'etejeda' +import argparse +from argparse import RawTextHelpFormatter +try: + import configparser +except ImportError as e: + import ConfigParser as configparser +from ecli.lib.dictutils import DictUtils +from bertdotconfig import Config +import json +import os +import getpass +import requests +from requests.auth import HTTPBasicAuth +import sys +import warnings +try: + import urllib.parse as urllib +except ImportError as e: + import urllib + +# compatibility +python_version_major = sys.version_info.major + +# requests stuffs +requests.packages.urllib3.disable_warnings() + +# Internals +current_user = getpass.getuser() +config = '~/.{u}.conflutil'.format(u=current_user) + +# Messages +msg_Invalid_Credentials = """You did not specify valid credentials + and a valid [Auth] section was not found in the specified or default configuration file ({c}). + Proceeding with NO Authentication""" +msg_INVALID_CONFIG = "No valid config file specified and I could not find a default configuration: {c}" +msg_IMPROPER_CONFIG = 'I did find a valid config file but it is improperly formatted: {c}' +msg_NO_CONTENT = 'Although you may have specified a document, there was a problem determining its content' +msg_NO_DOCUMENT = 'You didn''t specify a valid document path (-d option). See usage!' +msg_NO_PAGE_ID = "You didn't specify a PAGE ID" +msg_NO_PAGE_KEY = "You didn't specify a PAGE Key, e.g. VIP" +msg_HTTP_ERROR = 'There was an error updating or creating the specified page: {e}' +msg_RETRV_ERROR = 'Failed in retrieving Confluence object information for "{p}", {msg}' + +# Parse Command-line Parameters +parser = argparse.ArgumentParser( + description='Creates and/or updates a specified confluence page from specified document', + formatter_class=RawTextHelpFormatter, + epilog="""Default configuration file is {c}) formatted as: +[Auth] +username = TomTester +password = 123456ABCD + +[API] +server = 'www.confluence.example.local', +rest_endpoint = '/rest/api/content/' +""".format(c=config)) + +parser.add_argument("--config", '-c', + help="Manually specify a configuration file instead of default file path (~/.$USERNAME.confluence)") +parser.add_argument("--username", '-u', help="Specify username used in authentication") +parser.add_argument("--password", '-p', help="Specify password used in authentication") +parser.add_argument("--server", '-s', help="Specify the Confluence server, e.g. www.confluence.example.local") +parser.add_argument("--rest-endpoint", '-r', + help="Specify the Confluence rest api endpoint, e.g. /confluence/rest/api/content/") +parser.add_argument("--document", '-d', help="Specify the document you'll be pushing up") +parser.add_argument("--page-key", '-key', help="Specify the confluence page key, e.g. VIP") +parser.add_argument("--page-id", '-id', help="Specify the confluence page id") +parser.add_argument("--page-title", '-title', help="Specify the confluence page title") +parameters, args = parser.parse_known_args() + + +# Catch bad system calls +if not len(sys.argv[1:]) > 0: + parser.print_help() + sys.exit(0) + +# Content origination +document = parameters.document if parameters.document else None +if not document or not os.path.exists(document): + print(msg_NO_DOCUMENT) + parser.print_help() + print('\n\n' + msg_NO_DOCUMENT) + sys.exit(0) +else: + document_content = open(document).read() + +# Configuration Files +try: + script_dir = os.path.dirname(os.path.abspath(my.invocation.path)) +except NameError: + script_dir = os.path.dirname(os.path.abspath(__file__)) +config_file = os.path.abspath(os.path.join(script_dir, 'config.yaml')) +# Initialize Config +config = Config(config_file_uri=config_file).read() + +# Content origination +document = parameters.document if parameters.document else None +if not document or not os.path.exists(document): + print(msg_NO_DOCUMENT) + parser.print_help() + print('\n\n' + msg_NO_DOCUMENT) + sys.exit(0) +else: + document_content = open(document).read() + +# Catch specified credentials +if all([parameters.username, parameters.password]) or len(args) >= 2: + if args: + username = args[0] + password = args[1] + else: + username = parameters.username + password = parameters.password +elif not config_has_auth: + warnings.warn(msg_Invalid_Credentials.format(c=config)) + +# Catch Config errors +if not any([config_exists, parameters.config]): + quit(msg_INVALID_CONFIG.format(c=config)) +elif not config_is_valid: + quit(msg_IMPROPER_CONFIG.format(c=config)) + +# Variables +username = parameters.username if parameters.username else cfg.get('Auth', 'username') +password = parameters.password if parameters.password else cfg.get('Auth', 'password') +page_title = parameters.page_title if parameters.page_title else os.path.basename(document).split('.')[0] +page_title_safe = urllib.quote(page_title, safe='') +safe_password = urllib.quote(password, safe='') +rest_endpoint = parameters.rest_endpoint if parameters.rest_endpoint else cfg.get('API', 'rest_endpoint') +server = parameters.server if parameters.server else cfg.get('API', 'server') +page_id = parameters.page_id if parameters.page_id else None +page_key = parameters.page_key if parameters.page_key else quit(msg_NO_PAGE_KEY) + +url_http_get = 'https://{u}:{p}@{s}{r}?space={k}&title={t}'.format( + u=username, + p=safe_password, + s=server, + r=rest_endpoint, + k=page_key, + t=page_title_safe +) + +def get_page_data(u=url_http_get): + headers = {'X-Atlassian-Token': 'no-check', 'content-type': 'application/json'} + response = requests.get(u, headers=headers, verify=False) + if not response.status_code == 200: + error = json.loads(response.text)['message'] + quit(msg_HTTP_ERROR.format(e=error)) + return response + + +def update_page(content, title=None, **kwargs): + page = type('obj', (object,), {'type': 'obj_container'}) + try: + if python_version_major > 2: + page_data = get_page_data().json().items() + else: + page_data = get_page_data().json().iteritems() + except Exception as e: + quit(msg_RETRV_ERROR.format(p=page_title, msg="error was %s" % e)) + [setattr(page, str(k), v) for k, v in page_data] + if not len(page.results) > 0: + quit(msg_RETRV_ERROR.format(p=page_title, msg="does this page exist?")) + page_id = page.results[0]['id'] + page_content_url = page.results[0]['_links']['self'] + page_content_auth_url = page_content_url.replace("https://", "https://%s:%s@" % (username, safe_password)) + page_metadata = get_page_data(page_content_auth_url) + old_version = int(page_metadata.json()['version']['number']) + new_version = old_version + 1 + content = content if content else quit(msg_NO_CONTENT) + title = title if title else page.results[0]['title'] + data = {"id": page_id, "type": "page", "title": title, + "space": {"key": page_key}, + "body": {"storage": {"value": content, "representation": "wiki"}}, + "version": {"number": str(new_version)}} + headers = {'X-Atlassian-Token': 'no-check', 'content-type': 'application/json'} + response = requests.put(page_content_url, headers=headers, data=json.dumps(data), + verify=False,auth=HTTPBasicAuth(username, password)) + if not response.status_code == 200: + try: + response_message = "\n" + json.loads(response.text)['message'] + except Exception: + response_message = "" + error_message = "HTTP Return Code: %s Reason: %s %s" % (response.status_code, response.reason, response_message) + quit(msg_HTTP_ERROR.format(e=error_message)) + return response.status_code + + +if __name__ == '__main__': + result = update_page(document_content) + if result == 200: + print("Success: Document Published") + elif result.startswith("5"): + print("Fail: Something went wrong, error: {e}".format(e=result)) + sys.exit(result) diff --git a/git/get-bitbucketfile.ps1 b/git/get-bitbucketfile.ps1 new file mode 100755 index 0000000..514295c --- /dev/null +++ b/git/get-bitbucketfile.ps1 @@ -0,0 +1,40 @@ +[CmdletBinding()] +param ([Parameter(Mandatory=$False, ValueFromPipelineByPropertyName=$True,Position=0)][Alias('user')]$UserName, +[Parameter(Mandatory=$False,Position=1)]$Password, +[ValidateNotNull()] +[System.Management.Automation.PSCredential] +[System.Management.Automation.Credential()] +$Credentials = [System.Management.Automation.PSCredential]::Empty, +[Parameter(Mandatory=$True,Position=3)]$URL, +[Parameter(Mandatory=$False,Position=4)]$OutFile +) + +switch ($True) { +($Credentials.username -and $Credentials.password) { + $Username = ($Credentials.GetNetworkCredential()).username + $ClearPassword = ($Credentials.GetNetworkCredential()).password + break; +} +(!$UserName) {$UserName = Read-Host "Enter your Bitbucket Username"} +(!$Password) { + $Password = Read-Host "Enter your Bitbucket Password" -AsSecureString + $ClearPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)) +} +($Password -ne '') {$ClearPassword = $Password;break} +default { break;} +} +$ClearCredentials = "$UserName`:$ClearPassword" +$encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($ClearCredentials)) +$authorization = "Basic $encodedCredentials" +$Headers = @{ + Authorization = $authorization + "Content-Type" = "application/json" +} + +$RequestURL = "$URL/?raw" + +if ($OutFile){ + Invoke-WebRequest -Headers $Headers $RequestURL -OutFile $OutFile +} else { + return $(Invoke-WebRequest -Headers $Headers $RequestURL).content +} diff --git a/remote/run.py b/remote/run.py index 7419179..fb190cf 100644 --- a/remote/run.py +++ b/remote/run.py @@ -13,7 +13,7 @@ # Import third-party and custom modules from ecli.lib.dictutils import DictUtils from ecli.lib.proc.remote_cli_provider import RemoteCLIProvider -from ecli.lib.superduperconfig import SuperDuperConfig +from bertdotconfig import Config from ecli.lib.logger import Logger # Setup Logging @@ -49,9 +49,9 @@ def parse_args(): help="R|Remote command to execute, e.g.\n" "* Run command, specifying remote host (remote path defaults to CWD)\n" " example 1:\n" - " ecli remote.run -H myremote-host.mydomain.local --- ansible-playbook -i localhost, myplaybook.yaml\n" + " ecli remote.run -H myhost.example.local --- ansible-playbook -i localhost, myplaybook.yaml\n" " example 2:\n" - " ecli remote.run -H myremote-host.mydomain.local --- myscript.sh\n" + " ecli remote.run -H myhost.example.local --- myscript.sh\n" "* Specify config file with connection settings\n" " example 1:\n" " ecli remote.run -f remote-config.yaml --- ansible-playbook -i localhost, myplaybook.yaml\n" @@ -86,8 +86,8 @@ def parse_args(): if not args.sftp_config: logger.debug('No config file specified') config_file = args.sftp_config or os.path.abspath(os.path.join(script_dir, 'remote-config.yaml')) -# Initialize App Config -settings = Config(config_file_uri=config_file).read() +# Initialize Config +settings = config = Config(config_file_uri=config_file).read() remote_command = re.sub('[A-Z]:','',remote_command) remote_command = remote_command.replace('/Users/%s' % username,'~') remote_command = remote_command.replace('/users/%s' % username,'~') diff --git a/servicenow/list.sh b/servicenow/list.sh new file mode 100755 index 0000000..2ce2bf3 --- /dev/null +++ b/servicenow/list.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +script_dir=${0%/*} +script_name=${0##*/} +script_base_name=${script_name%%.*} +script_dir_name=${script_dir##*/} +baseurl=https://service-now.example.local +__docstring__="Query ServiceNow" + +USAGE=""" +Usage: ${script_dir_name}.${script_base_name} +param: [--username|-u ] +param: [--password|-p ] +param: [--ticket-numbers|-t ] +param: [--verbose # Show informational output] +param: [--use-cred-mgr This implicit option +populates the username/password environment +variables from the Operating System's Credential Manager +It expects a entry in the credential manager +for '${script_dir_name}.${script_base_name}' +Note: This must be a Generic Credential for Windows Hosts] +""" + +BINARY=jello +if ! [[ ($(type /usr/{,local/}{,s}bin/${BINARY} 2> /dev/null)) || ($(which $BINARY 2> /dev/null)) ]];then + echo "This function requires $BINARY, install with subcommand pip.install ${BINARY}" + exit 1 +fi + +system_fields="number,state,sys_created_by,sys_created_on,variables.slt_application_name,variables.custom_attribute,variables.custom_attribute_2" +group_name="Some%20Group%20Name" +ticket_category="Some%20Catagory%20Name" + +# CLI +for arg in "${@}";do + shift + if [[ "$arg" =~ '^--username$|^-u$|@The ServiceNow username to authenticate as - required' ]]; then username=$1;continue;fi + if [[ "$arg" =~ '^--password$|^-p$|@The ServiceNow password to use - required' ]]; then password=$1;continue;fi + if [[ "$arg" =~ '^--group-name$|^-g$|@The ServiceNow Group Name for filtering ticket results' ]]; then group_name=$1;continue;fi + if [[ "$arg" =~ '^--ticket-numbers$|^-t$|@Specify ticket numbers explicitly' ]]; then ticket_numbers=$1;continue;fi + if [[ "$arg" =~ '^--system-fields$|^-f$|@Specify ticket numbers explicitly' ]]; then system_fields=$1;continue;fi + if [[ "$arg" =~ '^--short$|@Short output' ]]; then short=true;continue;fi + if [[ "$arg" =~ '^--verbose$|@Verbose logging' ]]; then verbose=true;continue;fi + if [[ "$arg" =~ '^--dry$|@Dry run, only echo commands' ]]; then PREFIX=echo;continue;fi + if [[ "$arg" =~ '^--help$|@Show Help' ]]; then help=true;continue;fi + set -- "$@" "$arg" +done + +if [[ (-z $username) && (-z $password) && (-z $help) ]];then + echo "Warning: Values for Username and password are empty!" + echo -e "${USAGE}" + exit 0 +elif [[ ((-z $username) || (-z $password)) && (-z $help) ]];then + echo "Warning: Values for either of username or password is empty!" + echo -e "${USAGE}" + exit 0 +elif [[ (-n $help) ]];then + echo -e "${USAGE}" + exit 0 +fi + +if [[ -n $verbose ]];then + echo "Querying $baseurl for Tickets matching criteria" +fi + +if [[ -n $ticket_numbers ]];then + tickets_param="number=$(echo $ticket_numbers | sed s/,/^ORnumber=/g)" + query="${baseurl}/api/now/table/sc_req_item?&displayvalue=all&sysparm_query=${tickets_param}&sysparm_display_value=true&sysparm_exclude_reference_li&sysparm_fields=${system_fields}" +else + query="${baseurl}/api/now/table/sc_req_item?&displayvalue=all&sysparm_query=assignment_group.name=${group_name}^state!=-3&cat_item=${ticket_category}&sysparm_fields=${system_fields}" +fi + +result=$(curl -s \ +"${query}" \ +-X GET \ +--header 'Accept:application/json' \ +--user "${username}:${password}") + +if [[ -n $result ]];then + tickets=$(echo "${result}" | jello -r '[r["number"] for r in _["result"]]' | tail -n +2 | head -n -1) + n_tickets=$(echo "${tickets}" | wc -l) + if [[ -n $verbose ]];then + echo "Found $n_tickets tickets:" + fi + if [[ -n $short ]];then + echo "${tickets}" | tr -d \", + else + echo "${result}" | jello -r '_' + fi +else + if [[ -n $verbose ]];then + echo No tickets found + else + echo '{}' + fi +fi \ No newline at end of file diff --git a/shell/autocomplete.sh b/shell/autocomplete.sh new file mode 100755 index 0000000..1d98cd2 --- /dev/null +++ b/shell/autocomplete.sh @@ -0,0 +1,3 @@ + +echo 'source <(ecli shell.autocomplete) # setup autocomplete in bash into the current shell.' +echo '"source <(ecli shell.autocomplete)" >> ~/.bashrc # add autocomplete permanently to your bash shell.' \ No newline at end of file diff --git a/shell/dotfiles.sh b/shell/dotfiles.sh new file mode 100755 index 0000000..e69de29 diff --git a/system/launcher.py b/system/launcher.py index c682f9f..2c5aadb 100644 --- a/system/launcher.py +++ b/system/launcher.py @@ -1,7 +1,7 @@ import argparse from ecli.lib.dictutils import DictUtils import os -from ecli.lib.superduperconfig import SuperDuperConfig +from bertdotconfig import Config import sys __docstring__ = 'Launch System Utilities' @@ -25,10 +25,8 @@ def parse_args(): except NameError: script_dir = os.path.dirname(os.path.abspath(__file__)) config_file = os.path.abspath(os.path.join(script_dir, 'launcher.config.yaml')) -# Initialize Config Module -superconf = SuperDuperConfig(config_path=config_file) -# Initialize App Config -config = superconf.load_config() +# Initialize Config +config = Config(config_file_uri=config_file).read() # Dictutil dictutil = DictUtils() system_utilities = dictutil.deep_get(config, 'utilities')