├── .github ├── CODE-OF-CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── PULL-REQUEST-TEMPLATE.md ├── .travis.yml ├── Images ├── hc_user_data.png ├── jq_sample.png ├── no_jq_sample.png ├── sc_user_data.png ├── up_user_data.png ├── ur_user_data.png ├── usage.png ├── webhook.png ├── webhook_notifyAll.png ├── webhook_paused.png └── webhook_url.png ├── LICENSE.md ├── README.md ├── Templates ├── HealthChecks │ └── new-monitor.json ├── StatusCake │ ├── new-http-monitor.txt │ ├── new-ping-monitor.txt │ └── new-port-monitor.txt └── UptimeRobot │ ├── new-http-monitor.json │ ├── new-keyword-monitor.json │ ├── new-ping-monitor.json │ └── new-port-monitor.json ├── Travis ├── Config │ └── usage.cfg └── Scripts │ ├── Expects │ ├── Healthchecks │ │ ├── hc_api_key_expect.exp │ │ ├── hc_cleanup.exp │ │ ├── hc_delete_expect_long.exp │ │ ├── hc_delete_expect_short.exp │ │ ├── hc_find_expect_long.exp │ │ ├── hc_find_expect_short.exp │ │ ├── hc_pause_invalid_expect.exp │ │ ├── hc_webhook_empty_expect_long.exp │ │ └── hc_webhook_empty_expect_short.exp │ ├── StatusCake │ │ ├── sc_api_key_expect.exp │ │ ├── sc_cleanup.exp │ │ ├── sc_delete_expect_long.exp │ │ ├── sc_delete_expect_short.exp │ │ ├── sc_find_expect_long.exp │ │ ├── sc_find_expect_short.exp │ │ ├── sc_pause_invalid_expect.exp │ │ ├── sc_webhook_empty_expect_long.exp │ │ └── sc_webhook_empty_expect_short.exp │ └── UptimeRobot │ │ ├── ur_api_key_expect.exp │ │ ├── ur_cleanup.exp │ │ ├── ur_delete_expect_long.exp │ │ ├── ur_delete_expect_short.exp │ │ ├── ur_find_expect_long.exp │ │ ├── ur_find_expect_short.exp │ │ ├── ur_pause_invalid_expect.exp │ │ ├── ur_reset_expect_long.exp │ │ ├── ur_reset_expect_short.exp │ │ ├── ur_webhook_empty_expect_long.exp │ │ └── ur_webhook_empty_expect_short.exp │ ├── hc_prep.sh │ ├── sc_prep.sh │ ├── shfmt.sh │ ├── travis_tronitor.sh │ └── ur_prep.sh └── tronitor.sh /.github/CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at chris@chrisyocum.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | 1. Fork it. 4 | 2. Clone your forked project: `git clone http://github.com//tronitor` 5 | 3. Create a feature branch off of the develop branch: `git checkout -b my-new-feature develop` 6 | 4. Commit your changes: `git commit -am 'Added some feature'` 7 | 5. Push to the branch: `git push origin my-new-feature` 8 | 6. Submit a pull request to develop branch. 9 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: tronyx 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report an issue or bug 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the issue/bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | 21 | **Actual behavior** 22 | A clear and concise description of what is actually happening 23 | 24 | 25 | **Screenshots/CLI Output** 26 | If applicable, add screenshots or CLI output to help explain your problem. 27 | 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL-REQUEST-TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **By submitting this pull request, I confirm the following:** 2 | *Please fill in any appropriate check-boxes, e.g: [X]* 3 | 4 | - [ ] I have read and understood the [contributors guide](https://github.com/christronyxyocum/tronitor/blob/master/.github/CONTRIBUTING.md), as well as this entire template. 5 | - [ ] I have made only one major change in my proposed changes. 6 | - [ ] I have commented my proposed changes within the code. 7 | - [ ] I have tested my proposed changes, and have included unit tests where possible. 8 | - [ ] I am willing to help maintain this change if there are issues with it later. 9 | - [ ] I give this submission freely and claim no ownership. 10 | 11 | --- 12 | **What does this PR aim to accomplish?:** 13 | *A detailed description, screenshots (if necessary), as well as links to any relevant GitHub issues* 14 | 15 | **How does this PR accomplish the above?:** 16 | *A detailed description (such as a changelog) and screenshots (if necessary) of the implemented fix* 17 | 18 | **What documentation changes (if any) are needed to support this PR?:** 19 | *A detailed list of any necessary changes* 20 | 21 | --- 22 | - You must follow the template instructions. Failure to do so will result in your pull request being closed. 23 | - Please respect that Tronitor is developed by volunteers, IE: me, who can only reply in their spare time. 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: bash 2 | services: 3 | - docker 4 | addons: 5 | apt: 6 | packages: 7 | - expect 8 | - libcurl4-openssl-dev 9 | - libelf-dev 10 | - libdw-dev 11 | - cmake 12 | - jq 13 | jobs: 14 | include: 15 | - stage: test 16 | script: 17 | ## Dockerized SHFMT on Shell scripts 18 | - bash ./Travis/Scripts/shfmt.sh 19 | ## UptimeRobot Tests 20 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_api_key_expect.exp 21 | #- bash ./Travis/Scripts/ur_prep.sh 22 | #- sleep 60 23 | #- bash ./Travis/Scripts/travis_tronitor.sh -m ur 24 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur -c 25 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot -x 26 | #- bash ./Travis/Scripts/travis_tronitor.sh -h 27 | #- bash ./Travis/Scripts/travis_tronitor.sh --help 28 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur -p TravisOne 29 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_webhook_empty_expect_short.exp 30 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot --webhook 31 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur --list 32 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot -n 33 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur --no-prompt 34 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot -c http 35 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur --create ping 36 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot -c port 37 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur --create keyword 38 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot -c foobar 39 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur -a 40 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot --alerts 41 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur -s 42 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot --stats 43 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur -i 'travisone' 44 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot --info 'travistwo' 45 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_delete_expect_short.exp 46 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_delete_expect_long.exp 47 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur -p GooglePing 48 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot --pause all 49 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_find_expect_short.exp 50 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_find_expect_long.exp 51 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor ur -u all 52 | #- bash ./Travis/Scripts/travis_tronitor.sh -m uptimerobot --unpause all 53 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_reset_expect_short.exp 54 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_reset_expect_long.exp 55 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_pause_invalid_expect.exp 56 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_cleanup.exp 57 | ## Reset the webhook var 58 | #- sed -i "22s|.*|webhookUrl=''|" Travis/Scripts/travis_tronitor.sh 59 | ## StatusCake Tests 60 | #- expect ./Travis/Scripts/Expects/StatusCake/sc_api_key_expect.exp 61 | #- bash ./Travis/Scripts/sc_prep.sh 62 | #- sleep 60 63 | #- bash ./Travis/Scripts/travis_tronitor.sh -m sc 64 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor sc -c 65 | #- bash ./Travis/Scripts/travis_tronitor.sh -m statuscake -x 66 | #- bash ./Travis/Scripts/travis_tronitor.sh -h 67 | #- bash ./Travis/Scripts/travis_tronitor.sh --help 68 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor sc -p TravisOne 69 | #- expect ./Travis/Scripts/Expects/StatusCake/sc_webhook_empty_expect_short.exp 70 | #- bash ./Travis/Scripts/travis_tronitor.sh -m statuscake --webhook 71 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor sc --list 72 | #- bash ./Travis/Scripts/travis_tronitor.sh -m statuscake -n 73 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor sc --no-prompt 74 | #- bash ./Travis/Scripts/travis_tronitor.sh -m statuscake -c http 75 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor sc --create ping 76 | #- bash ./Travis/Scripts/travis_tronitor.sh -m statuscake -c port 77 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor sc --create keyword 78 | #- bash ./Travis/Scripts/travis_tronitor.sh -m statuscake -c foobar 79 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor sc -a 80 | #- bash ./Travis/Scripts/travis_tronitor.sh -m statuscake --alerts 81 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor sc -i 'travisone' 82 | #- bash ./Travis/Scripts/travis_tronitor.sh -m statuscake --info 'travistwo' 83 | #- expect ./Travis/Scripts/Expects/StatusCake/sc_delete_expect_short.exp 84 | #- expect ./Travis/Scripts/Expects/StatusCake/sc_delete_expect_long.exp 85 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor sc -p GooglePing 86 | #- bash ./Travis/Scripts/travis_tronitor.sh -m statuscake --pause all 87 | #- expect ./Travis/Scripts/Expects/StatusCake/sc_find_expect_short.exp 88 | #- expect ./Travis/Scripts/Expects/StatusCake/sc_find_expect_long.exp 89 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor sc -u all 90 | #- bash ./Travis/Scripts/travis_tronitor.sh -m statuscake --unpause all 91 | #- expect ./Travis/Scripts/Expects/StatusCake/sc_pause_invalid_expect.exp 92 | #- expect ./Travis/Scripts/Expects/StatusCake/sc_cleanup.exp 93 | ## Reset the webhook var 94 | #- sed -i "22s|.*|webhookUrl=''|" Travis/Scripts/travis_tronitor.sh 95 | ## HealthChecks Tests 96 | #- expect ./Travis/Scripts/Expects/Healthchecks/hc_api_key_expect.exp 97 | #- bash ./Travis/Scripts/hc_prep.sh 98 | #- sleep 60 99 | #- bash ./Travis/Scripts/travis_tronitor.sh -m hc 100 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor hc -c 101 | #- bash ./Travis/Scripts/travis_tronitor.sh -m healthchecks -x 102 | #- bash ./Travis/Scripts/travis_tronitor.sh -h 103 | #- bash ./Travis/Scripts/travis_tronitor.sh --help 104 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor hc -p TravisOne 105 | #- expect ./Travis/Scripts/Expects/Healthchecks/hc_webhook_empty_expect_short.exp 106 | #- bash ./Travis/Scripts/travis_tronitor.sh -m healthchecks --webhook 107 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor hc --list 108 | #- bash ./Travis/Scripts/travis_tronitor.sh -m healthchecks -n 109 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor hc --no-prompt 110 | #- bash ./Travis/Scripts/travis_tronitor.sh -m healthchecks -c http 111 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor hc --create ping 112 | #- bash ./Travis/Scripts/travis_tronitor.sh -m healthchecks -c port 113 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor hc --create keyword 114 | #- bash ./Travis/Scripts/travis_tronitor.sh -m healthchecks -c foobar 115 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor hc -a 116 | #- bash ./Travis/Scripts/travis_tronitor.sh -m healthchecks --alerts 117 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor hc -i 'travisone' 118 | #- bash ./Travis/Scripts/travis_tronitor.sh -m healthchecks --info 'travistwo' 119 | #- expect ./Travis/Scripts/Expects/Healthchecks/hc_delete_expect_short.exp 120 | #- expect ./Travis/Scripts/Expects/Healthchecks/hc_delete_expect_long.exp 121 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor hc -p GooglePing 122 | #- bash ./Travis/Scripts/travis_tronitor.sh -m healthchecks --pause all 123 | #- expect ./Travis/Scripts/Expects/Healthchecks/hc_find_expect_short.exp 124 | #- expect ./Travis/Scripts/Expects/Healthchecks/hc_find_expect_long.exp 125 | #- bash ./Travis/Scripts/travis_tronitor.sh --monitor hc -u all 126 | #- bash ./Travis/Scripts/travis_tronitor.sh -m healthchecks --unpause all 127 | #- expect ./Travis/Scripts/Expects/Healthchecks/hc_pause_invalid_expect.exp 128 | #- expect ./Travis/Scripts/Expects/Healthchecks/hc_cleanup.exp 129 | #after_success: 130 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_cleanup.exp 131 | #- expect ./Travis/Scripts/Expects/StatusCake/sc_cleanup.exp 132 | #- expect ./Travis/Scripts/Expects/Healthchecks/hc_cleanup.exp 133 | #after_failure: 134 | #- expect ./Travis/Scripts/Expects/UptimeRobot/ur_cleanup.exp 135 | #- expect ./Travis/Scripts/Expects/StatusCake/sc_cleanup.exp 136 | #- expect ./Travis/Scripts/Expects/Healthchecks/hc_cleanup.exp 137 | -------------------------------------------------------------------------------- /Images/hc_user_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/hc_user_data.png -------------------------------------------------------------------------------- /Images/jq_sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/jq_sample.png -------------------------------------------------------------------------------- /Images/no_jq_sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/no_jq_sample.png -------------------------------------------------------------------------------- /Images/sc_user_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/sc_user_data.png -------------------------------------------------------------------------------- /Images/up_user_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/up_user_data.png -------------------------------------------------------------------------------- /Images/ur_user_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/ur_user_data.png -------------------------------------------------------------------------------- /Images/usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/usage.png -------------------------------------------------------------------------------- /Images/webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/webhook.png -------------------------------------------------------------------------------- /Images/webhook_notifyAll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/webhook_notifyAll.png -------------------------------------------------------------------------------- /Images/webhook_paused.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/webhook_paused.png -------------------------------------------------------------------------------- /Images/webhook_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tronyx/tronitor/38fa548a78eafd815b7a024c1894dbe05472d861/Images/webhook_url.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Chris Yocum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tronitor 2 | 3 | [![CodeFactor](https://www.codefactor.io/repository/github/tronyx/tronitor/badge)](https://www.codefactor.io/repository/github/tronyx/tronitor) [![Travis (.com) branch](https://img.shields.io/travis/rust-lang/rust/master.svg?logo=travis)](https://app.travis-ci.com/tronyx/tronitor) [![made-with-bash](https://img.shields.io/badge/Made%20with-Bash-1f425f.svg)](https://www.gnu.org/software/bash/) [![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/tronyx/tronitor/blob/develop/LICENSE.md) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/tronyx/tronitor.svg)](http://isitmaintained.com/project/tronyx/tronitor "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/tronyx/tronitor.svg)](http://isitmaintained.com/project/tronyx/tronitor "Percentage of issues still open") 4 | 5 | A bash script to work with [UptimeRobot](https://uptimerobot.com), [StatusCake](https://www.statuscake.com), [HealthChecks.io](https://healthchecks.io), and [Upptime](https://upptime.js.org/) monitors via their respective APIs. It checks to make sure that the API key/token, username for StatusCake, and your GitHub username and the name of your Upptime repository on GitHub, that you provided are valid before performing any requested operations. 6 | 7 | ## Contributors 8 | 9 | [![GitHub contributors](https://img.shields.io/github/contributors/tronyx/tronitor.svg)](https://github.com/tronyx/tronitor/graphs/contributors/) 10 | 11 | Big thanks to [nemchik](https://github.com/GhostWriters/DockSTARTer/commits?author=nemchik) for all the ideas and help with getting some things to work, and to [1activegeek](https://github.com/1activegeek) for asking me to create this for him in the first place, albeit MUCH less complicated than what it's become. 12 | 13 | Feel free to check out their work and buy them a beer too! 14 | 15 | ## Application Healthchecks 16 | 17 | This script partners up with my [Application Healthchecks](https://github.com/tronyx/HealthChecks-Linux) script that provides checks for a lot of popular HTPC applications, IE: Plex, Sonarr, Radarr, etc. that work with HealthChecks.io. Tronitor would allow you to pause and unpause the checks manually or on a schedule, via a cronjob, for planned maintenance, etc. This essentially allows you to create your own maintenance windows without having to pay for a premium account with either of the providers. 18 | 19 | ## Package Requirements/Recommendations 20 | 21 | ### cURL 22 | 23 | The `cURL` command is required for the script to function as it's used to submit API calls to the providers. If it is not installed before you execute the script most, if not all, operations will fail. Because of this, the script does check whether or not `cURL` is installed and, if not, it will inform you as such and then exit. 24 | 25 | ### JQ 26 | 27 | The `jq` command is required for the script to function as it is used to more easily extract data from JSON files created by the script when gathering information for the monitoring providers and the corresponding checks/tests. 28 | 29 | It is also used by the script to automatically format the JSON output into a human-readable and colorized output. There is a variable at the beginning of the script to set the use of the `jq` command (strictly for displaying the output of the script) to true or false. I've personally encountered some issues with it when using the script within a cronjob and not using `jq` to format the output resolves them. It is set to `true` by default. 30 | 31 | ```bash 32 | # Set JQ to false to disable its use for displaying output. 33 | # This works better for using the script with cronjobs, etc. 34 | jq='true' 35 | ``` 36 | 37 | #### Installing JQ on Ubuntu Server 18.04: 38 | 39 | ```bash 40 | tronyx@suladan:~$ sudo apt install jq 41 | Reading package lists... Done 42 | Building dependency tree 43 | Reading state information... Done 44 | The following NEW packages will be installed: 45 | jq 46 | 0 upgraded, 1 newly installed, 0 to remove and 7 not upgraded. 47 | Need to get 45.6 kB of archives. 48 | After this operation, 90.1 kB of additional disk space will be used. 49 | Get:1 http://archive.ubuntu.com/ubuntu bionic/universe amd64 jq amd64 1.5+dfsg-2 [45.6 kB] 50 | Fetched 45.6 kB in 0s (123 kB/s) 51 | Selecting previously unselected package jq. 52 | (Reading database ... 107503 files and directories currently installed.) 53 | Preparing to unpack .../jq_1.5+dfsg-2_amd64.deb ... 54 | Unpacking jq (1.5+dfsg-2) ... 55 | Setting up jq (1.5+dfsg-2) ... 56 | Processing triggers for man-db (2.8.3-2) ... 57 | ``` 58 | 59 | #### Sample output using JQ: 60 | 61 | ![JQ True](/Images/jq_sample.png) 62 | 63 | #### Sample output without JQ: 64 | 65 | ![JQ False](/Images/no_jq_sample.png) 66 | 67 | ## Setting it up 68 | 69 | The best method to get the script working is to use `git` to clone the repository onto your preferred machine: 70 | 71 | ```bash 72 | tronyx@suladan:~$ git clone https://github.com/tronyx/tronitor.git 73 | Cloning into 'tronitor'... 74 | remote: Enumerating objects: 108, done. 75 | remote: Counting objects: 100% (108/108), done. 76 | remote: Compressing objects: 100% (75/75), done. 77 | remote: Total 262 (delta 60), reused 76 (delta 32), pack-reused 154 78 | Receiving objects: 100% (262/262), 161.85 KiB | 6.74 MiB/s, done. 79 | Resolving deltas: 100% (143/143), done. 80 | ``` 81 | 82 | :warning: **NOTE:** You CAN get away with just grabbing a copy of the `tronitor.sh` script itself, but the monitor creation functionality will not work as it depends on the included template files in the repository. 83 | 84 | The script stores the API keys/token, username for StatusCake, and, for Upptime, your GitHub username, PAT (Personal Access Token), and the name of your Upptime reposistory, for up to all four providers so that you do not need multiple copies of the script to work with each of the different providers. 85 | 86 | If you do not know how to create a PAT for your GitHub account, you can checkout their documentation on it [HERE](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token). 87 | 88 | The first time that you run the script for a specific monitor it will alert you that the API key/token, etc. are missing and prompt you to input them: 89 | 90 | ### UptimeRobot 91 | ![UptimeRobot User Data Prompt](/Images/ur_user_data.png) 92 | 93 | ### StatusCake 94 | ![StatusCake User Data Prompt](/Images/sc_user_data.png) 95 | 96 | ### Healthchecks.io 97 | ![Healthchecks User Data Prompt](/Images/hc_user_data.png) 98 | 99 | :warning: **NOTE:** If you are running your own, self-hosted version of the Healthchecks.io application, you will need to modify the `healthchecksDomain` variable on `line 24` of the `tronitor.sh` script with the domain name that you're hosting the application with. 100 | 101 | ### Upptime 102 | ![Upptime/GitHub User Data Prompt](/Images/up_user_data.png) 103 | 104 | You can also simply open the script with your favorite text editor and add your provider's API key, if you're using StatusCake, your account username, and, if you're using Upptime, the repository owner (organization or user), your GitHub username, PAT (Personal Access Token), and the name of your Upptime reposistory. 105 | 106 | After entering the information, the script will check whether or not it is valid and then add it to the script for you. 107 | 108 | If you use the alert option, be sure to also enter in your Discord/Slack webhook URL. If you forget this as well, the script will also prompt you to enter it: 109 | 110 | ![Webhook URL Prompt](/Images/webhook_url.png) 111 | 112 | ## Usage 113 | 114 | ![Script Usage](/Images/usage.png) 115 | 116 | The `-m/--monitor` option accepts both full and shorthand versions of the provider's name: 117 | 118 | ```bash 119 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m uptimerobot -l 120 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m ur -l 121 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m statuscake -l 122 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m sc -l 123 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m healthchecks -l 124 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m hc -l 125 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m upptime -l 126 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m up -l 127 | ``` 128 | 129 | ## Examples 130 | ### Get account statistics 131 | 132 | Display basic statistics for your account: 133 | 134 | ```json 135 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m uptimerobot -s 136 | Here are the basic statistics for your UptimeRobot account: 137 | 138 | { 139 | "stat": "ok", 140 | "account": { 141 | "email": "me@domain.com", 142 | "monitor_limit": 50, 143 | "monitor_interval": 5, 144 | "up_monitors": 14, 145 | "down_monitors": 0, 146 | "paused_monitors": 0 147 | } 148 | } 149 | ``` 150 | 151 | ### List all monitors 152 | 153 | Display all monitors associated with your account and their current statuses: 154 | 155 | ```json 156 | tronyx@suladan:~/tronitor$ ./tronitor.sh --monitor ur -l 157 | The following UptimeRobot monitors were found in your UptimeRobot account: 158 | 159 | Plex (ID: 779783111) - Status: Up 160 | Radarr (ID: 780859973) - Status: Down 161 | Sonarr (ID: 780859962) - Status: Paused 162 | Tautulli (ID: 780859975) - Status: Seems down 163 | ``` 164 | 165 | ### Find currently paused monitors 166 | 167 | Find and display all monitors in your account that are currently paused and then prompt you as to whether or not you would like to unpause them: 168 | 169 | ```json 170 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m ur -f 171 | The following StatusCake monitors are currently paused: 172 | 173 | Plex (ID: 779783111) 174 | Radarr (ID: 780859973) 175 | Sonarr (ID: 780859962) 176 | Tautulli (ID: 780859975) 177 | 178 | Would you like to unpause the paused monitors? ([Y]es or [N]o): 179 | ``` 180 | 181 | You can also use the `-n` option to display the same list, but not display a prompt to unpause the paused monitors. 182 | 183 | ### Discord alert for paused monitors 184 | 185 | Using the `-w` option will check for any paused monitors and, if there are any, send an alert to the specified Discord/Slack webhook like below: 186 | 187 | ![Discord/Slack Notification](/Images/webhook_paused.png) 188 | 189 | If you set the `notifyAll` option to `true`, Tronitor will send a notification even if there are no paused monitors: 190 | 191 | ![Discord/Slack Notification](/Images/webhook_notifyAll.png) 192 | 193 | ### Info 194 | 195 | Display all information for a single monitor: 196 | 197 | ```json 198 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m uptimerobot -i 'plex' 199 | { 200 | "stat": "ok", 201 | "pagination": { 202 | "offset": 0, 203 | "limit": 50, 204 | "total": 1 205 | }, 206 | "monitors": [ 207 | { 208 | "id": 779783111, 209 | "friendly_name": "Plex", 210 | "url": "https://plex.tv", 211 | "type": 1, 212 | "sub_type": "", 213 | "keyword_type": null, 214 | "keyword_value": "", 215 | "http_username": "", 216 | "http_password": "", 217 | "port": "", 218 | "interval": 300, 219 | "status": 2, 220 | "create_datetime": 1513815865 221 | } 222 | ] 223 | } 224 | ``` 225 | 226 | ### Get alert contacts 227 | 228 | Displays a list of all of the alert contacts configured for the account: 229 | 230 | ```json 231 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m ur -a 232 | The following alert contacts have been found for your UptimeRobot account: 233 | 234 | { 235 | "stat": "ok", 236 | "offset": 0, 237 | "limit": 50, 238 | "total": 2, 239 | "alert_contacts": [ 240 | { 241 | "id": "0526944", 242 | "friendly_name": "E-Mail", 243 | "type": 2, 244 | "status": 2, 245 | "value": "me@domain.com" 246 | }, 247 | { 248 | "id": "2611518", 249 | "friendly_name": "Discord", 250 | "type": 11, 251 | "status": 2, 252 | "value": "https://discordapp.com/api/webhooks/123456789/qwerty-qwerty-qwerty/slack" 253 | } 254 | ] 255 | } 256 | ``` 257 | 258 | This can be helpful when creating a new monitor as you can use the `id` field of the alert contact to specify the alert contact that you want to be notified when an event occurs with the new monitor that you're creating. 259 | 260 | ### Pause all monitors 261 | 262 | Pause all monitors in your account: 263 | 264 | ```json 265 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m uptimerobot -p all 266 | Pausing Plex: 267 | { 268 | "stat": "ok", 269 | "monitor": { 270 | "id": 779783111 271 | } 272 | } 273 | 274 | Pausing Radarr: 275 | { 276 | "stat": "ok", 277 | "monitor": { 278 | "id": 780859973 279 | } 280 | } 281 | 282 | Pausing Sonarr: 283 | { 284 | "stat": "ok", 285 | "monitor": { 286 | "id": 780859962 287 | } 288 | } 289 | 290 | Pausing Tautulli: 291 | { 292 | "stat": "ok", 293 | "monitor": { 294 | "id": 780859975 295 | } 296 | } 297 | ``` 298 | 299 | :warning: **NOTE:** Healthchecks.io works with cronjobs so, unless you disable your cronjobs for the HC.io monitors, or work with the created lock file, all paused monitors will become active again the next time they receive a ping. Tronitor creates a lock file, `/tmp/tronitor/healthchecks.lock`, so that you can modify your existing HC.io script to check for the lock file and not send pings if it is present. 300 | 301 | 302 | ### Pause specific monitors 303 | 304 | Pause specific monitors in your account: 305 | 306 | ```json 307 | tronyx@suladan:~/tronitor$ ./tronitor.sh --monitor ur -p 'Plex',780859973 308 | Pausing Plex: 309 | { 310 | "stat": "ok", 311 | "monitor": { 312 | "id": 779783111 313 | } 314 | } 315 | 316 | Pausing Radarr: 317 | { 318 | "stat": "ok", 319 | "monitor": { 320 | "id": 780859973 321 | } 322 | } 323 | ``` 324 | 325 | :warning: **NOTE:** Healthchecks.io works with cronjobs so, unless you disable your cronjobs for the HC.io monitors, or work with the created lock file, all paused monitors will become active again the next time they receive a ping. Tronitor creates a lock file, `/tmp/tronitor/MONITOR-UUID.lock`, so that you can modify your existing HC.io script to check for the lock file and not send pings if it is present. 326 | 327 | ### Unpause all currently paused monitors 328 | 329 | Unpause all monitors in your account: 330 | 331 | ```json 332 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m ur -u all 333 | Unpausing Plex: 334 | { 335 | "stat": "ok", 336 | "monitor": { 337 | "id": 779783111 338 | } 339 | } 340 | 341 | Unpausing Radarr: 342 | { 343 | "stat": "ok", 344 | "monitor": { 345 | "id": 780859973 346 | } 347 | } 348 | 349 | Unpausing Sonarr: 350 | { 351 | "stat": "ok", 352 | "monitor": { 353 | "id": 780859962 354 | } 355 | } 356 | 357 | Unpausing Tautulli: 358 | { 359 | "stat": "ok", 360 | "monitor": { 361 | "id": 780859975 362 | } 363 | } 364 | ``` 365 | 366 | ### Unpause specific monitors 367 | 368 | Unpause specific monitors that are currently paused in your account: 369 | 370 | ```json 371 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m ur -u 'Plex',780859973 372 | Unpausing Plex: 373 | { 374 | "stat": "ok", 375 | "monitor": { 376 | "id": 779783111 377 | } 378 | } 379 | 380 | Unpausing Radarr: 381 | { 382 | "stat": "ok", 383 | "monitor": { 384 | "id": 780859973 385 | } 386 | } 387 | ``` 388 | 389 | ### Create a new monitor 390 | 391 | Monitors can be created using this option. 392 | 393 | :warning: **NOTE:** StatusCake's API is dumb and WILL let you create more tests than you're supposed to have with the limit for your account and it can cause some very odd behavior with the monitors. 394 | 395 | Modify the settings of the corresponding monitor type template file in the corresponding `Templates` directory for your provider, IE: creating a new HTTP(s) monitor for UptimeRobot would require you to modify the `Templates/UptimeRobot/new-http-monitor.json` file. The full API documentation for the two providers can be found [HERE (UR)](https://uptimerobot.com/api), [HERE (SC)](https://www.statuscake.com/api/index.md), and [HERE (HC)](https://healthchecks.io/docs/api/) for information on monitor types and any required values and what they're for. 396 | 397 | The following example is for creating a new HTTP(s) monitor for Google: 398 | 399 | ```json 400 | tronyx@suladan:~/tronitor$ cat Templates/UptimeRobot/new-http-monitor.json 401 | { 402 | "api_key": "", 403 | "friendly_name": "Google", 404 | "url": "https://google.com", 405 | "type": 1, 406 | "http_username": "", 407 | "http_password": "", 408 | "interval": 300, 409 | "alert_contacts": "", 410 | "ignore_ssl_errors": "false", 411 | "format": "json" 412 | } 413 | ``` 414 | 415 | The `api_key` field is filled in automatically by the script, but you can still add it yourself if you'd like to. The `alert_contacts` field can be filled in with the `id` field from your preferred alert contact which you can retrieve using the `-a/--alerts` option with the script. 416 | 417 | Then just execute the script to create the monitor: 418 | 419 | ```json 420 | tronyx@suladan:~/tronitor$ ./tronitor.sh --monitor uptimerobot -c http 421 | { 422 | "stat": "ok", 423 | "monitor": { 424 | "id": 781067574, 425 | "status": 1 426 | } 427 | } 428 | ``` 429 | 430 | ### Resetting monitors 431 | 432 | Reset (deleting all stats and response time data) all or specific monitors in your account: 433 | 434 | ```json 435 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m ur -r google 436 | 437 | ***WARNING*** This will reset ALL data for the specified monitors!!! 438 | Are you sure you wish to continue? ([Y]es or [N]o): 439 | y 440 | 441 | Resetting Google: 442 | { 443 | "stat": "ok", 444 | "monitor": { 445 | "id": 781067574 446 | } 447 | } 448 | ``` 449 | 450 | ### Deleting monitors 451 | 452 | Delete all, or a specific, monitor from your account: 453 | 454 | ```json 455 | tronyx@suladan:~/tronitor$ ./tronitor.sh -m ur -d plex 456 | 457 | ***WARNING*** This will delete the specified monitor from your account!!! 458 | Are you sure you wish to continue? ([Y]es or [N]o): 459 | y 460 | 461 | Deleting Plex: 462 | { 463 | "stat": "ok", 464 | "monitor": { 465 | "id": 781067560 466 | } 467 | } 468 | ``` 469 | -------------------------------------------------------------------------------- /Templates/HealthChecks/new-monitor.json: -------------------------------------------------------------------------------- 1 | { 2 | "api_key": "${travisHCApiKey}", 3 | "name": "GoogleHttp", 4 | "tags": "prod www", 5 | "timeout": 3600, 6 | "grace": 60, 7 | "tz": "America/New_York" 8 | } 9 | -------------------------------------------------------------------------------- /Templates/StatusCake/new-http-monitor.txt: -------------------------------------------------------------------------------- 1 | WebsiteName=GoogleHttp&WebsiteURL=https://google.com&CheckRate=300&TestType=HTTP 2 | -------------------------------------------------------------------------------- /Templates/StatusCake/new-ping-monitor.txt: -------------------------------------------------------------------------------- 1 | WebsiteName=GooglePing&WebsiteURL=https://google.com&CheckRate=300&TestType=PING 2 | -------------------------------------------------------------------------------- /Templates/StatusCake/new-port-monitor.txt: -------------------------------------------------------------------------------- 1 | WebsiteName=GooglePort&WebsiteURL=https://google.com&Port=443&CheckRate=300&TestType=TCP 2 | -------------------------------------------------------------------------------- /Templates/UptimeRobot/new-http-monitor.json: -------------------------------------------------------------------------------- 1 | { 2 | "api_key": "", 3 | "friendly_name": "GoogleHttp", 4 | "url": "https://google.com", 5 | "type": 1, 6 | "http_username": "", 7 | "http_password": "", 8 | "interval": 300, 9 | "alert_contacts": "", 10 | "ignore_ssl_errors": "false", 11 | "format": "json" 12 | } 13 | -------------------------------------------------------------------------------- /Templates/UptimeRobot/new-keyword-monitor.json: -------------------------------------------------------------------------------- 1 | { 2 | "api_key": "", 3 | "friendly_name": "GoogleKeyword", 4 | "url": "https://google.de", 5 | "type": 2, 6 | "http_username": "", 7 | "http_password": "", 8 | "keyword_type": "2", 9 | "keyword_value": "About", 10 | "interval": 300, 11 | "alert_contacts": "", 12 | "ignore_ssl_errors": "false", 13 | "format": "json" 14 | } 15 | -------------------------------------------------------------------------------- /Templates/UptimeRobot/new-ping-monitor.json: -------------------------------------------------------------------------------- 1 | { 2 | "api_key": "", 3 | "friendly_name": "GooglePing", 4 | "url": "https://google.com", 5 | "type": 3, 6 | "interval": 300, 7 | "alert_contacts": "", 8 | "ignore_ssl_errors": "false", 9 | "format": "json" 10 | } 11 | -------------------------------------------------------------------------------- /Templates/UptimeRobot/new-port-monitor.json: -------------------------------------------------------------------------------- 1 | { 2 | "api_key": "", 3 | "friendly_name": "GooglePort", 4 | "url": "https://google.com", 5 | "type": 4, 6 | "sub_type": "2", 7 | "port": "443", 8 | "interval": 300, 9 | "alert_contacts": "", 10 | "ignore_ssl_errors": "false", 11 | "format": "json" 12 | } 13 | -------------------------------------------------------------------------------- /Travis/Config/usage.cfg: -------------------------------------------------------------------------------- 1 | # Define usage and script options 2 | usage() { 3 | cat <<- EOF 4 | 5 | Usage: $(echo -e "${lorg}$0${endColor}") $(echo -e "${grn}"-[OPTION]"${endColor}") $(echo -e "${ylw}"\(ARGUMENT\)"${endColor}"...) 6 | 7 | $(echo -e "${grn}"-s/--stats"${endColor}${red}"*"${endColor}") List account statistics. 8 | $(echo -e "${grn}"-l/--list"${endColor}") List all monitors. 9 | $(echo -e "${grn}"-f/--find"${endColor}") Find all paused monitors. 10 | $(echo -e "${grn}"-n/--no-prompt"${endColor}") Find all paused monitors without an unpause prompt. 11 | $(echo -e "${grn}"-w/--webhook"${endColor}") Find all paused monitors without an unpause prompt and 12 | send an alert to the Discord webhook specified in the script. 13 | $(echo -e "${grn}"-i/--info"${endColor}" "${ylw}"VALUE"${endColor}") List all information for the specified monitor. 14 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-i"${endColor}" "${ylw}"18095689"${endColor}")" 15 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--info"${endColor}" "${ylw}"\'Plex\'"${endColor}")" 16 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-i"${endColor}" "${ylw}"\"Tautulli\""${endColor}")" 17 | $(echo -e "${grn}"-a/--alerts"${endColor}") List all alert contacts. 18 | $(echo -e "${grn}"-p/--pause"${endColor}" "${ylw}"VALUE"${endColor}") Pause specified monitors. 19 | Option accepts arguments in the form of "$(echo -e "${ylw}"all"${endColor}")" or a comma-separated list 20 | of monitors by ID or Friendly Name. Friendly Name should be wrapped in 21 | a set of single or double quotes, IE: 22 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-p"${endColor}" "${ylw}"all"${endColor}")" 23 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--pause"${endColor}" "${ylw}"18095687,18095688,18095689"${endColor}")" 24 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-p"${endColor}" "${ylw}"\'Plex\',\"Tautulli\",18095689"${endColor}")" 25 | $(echo -e "${grn}"-u/--unpause"${endColor}" "${ylw}"VALUE"${endColor}") Unpause specified monitors. 26 | Option accepts arguments in the form of "$(echo -e "${ylw}"all"${endColor}")" or a comma-separated list 27 | of monitors by ID or Friendly Name. Friendly Name should be wrapped in 28 | a set of single or double quotes, IE: 29 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-u"${endColor}" "${ylw}"all"${endColor}")" 30 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--unpause"${endColor}" "${ylw}"18095687,18095688,18095689"${endColor}")" 31 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-u"${endColor}" "${ylw}"\'Plex\',\"Tautulli\",18095689"${endColor}")" 32 | $(echo -e "${grn}"-c/--create"${endColor}" "${ylw}"VALUE"${endColor}") Create a new monitor using the corresponding template file. Each type of test 33 | (HTTP, Ping, Port, & Keyword) has a template file in the Templates directory. 34 | Just edit the template file for the monitor type you wish to create and then run 35 | the script with the corresponding monitor type, IE: 36 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-c"${endColor}" "${ylw}"http"${endColor}")" 37 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--create"${endColor}" "${ylw}"port"${endColor}")" 38 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-c"${endColor}" "${ylw}"keyword"${endColor}")" 39 | $(echo -e "${grn}"-d/--delete"${endColor}" "${ylw}"VALUE"${endColor}") Delete the specified monitor, IE: 40 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-d"${endColor}" "${ylw}"\'Plex\'"${endColor}")" 41 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--delete"${endColor}" "${ylw}"\"Tautulli\""${endColor}")" 42 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-d"${endColor}" "${ylw}"18095688"${endColor}")" 43 | $(echo -e "${grn}"-r/--reset"${endColor}${red}"*"${endColor}" "${ylw}"VALUE"${endColor}") Reset the specified monitor, IE: 44 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-r"${endColor}" "${ylw}"\'Plex\'"${endColor}")" 45 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--reset"${endColor}" "${ylw}"\"Tautulli\""${endColor}")" 46 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-r"${endColor}" "${ylw}"18095688"${endColor}")" 47 | $(echo -e "${grn}"-h/--help"${endColor}") Display this usage dialog. 48 | 49 | $(echo -e "${red}"\*"${endColor}${ylw}" - Option is not compatible with StatusCake or HealthChecks.io."${endColor}") 50 | 51 | EOF 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/Healthchecks/hc_api_key_expect.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | set apiKey $::env(travisHCApiKey) 7 | 8 | spawn bash Travis/Scripts/travis_tronitor.sh -m hc -l 9 | 10 | expect "Enter your Healthchecks API key:" 11 | send -- "this-is-a-bad-api-key\r" 12 | 13 | expect "Enter your Healthchecks API key:" 14 | send -- "$apiKey\r" 15 | 16 | expect eof 17 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/Healthchecks/hc_cleanup.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m healthchecks -d all 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o):" 9 | send -- "y\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/Healthchecks/hc_delete_expect_long.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m hc --delete travisone 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o):" 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/Healthchecks/hc_delete_expect_short.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m healthchecks -d travistwo 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o):" 9 | send -- "y\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/Healthchecks/hc_find_expect_long.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m hc --find 7 | 8 | expect "Would you like to unpause the paused monitors? (\[Y\]es or \[N\]o): " 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/Healthchecks/hc_find_expect_short.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m healthchecks -f 7 | 8 | expect "Would you like to unpause the paused monitors? (\[Y\]es or \[N\]o): " 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/Healthchecks/hc_pause_invalid_expect.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m hc -p GooglePing,foobar 7 | 8 | expect "\[Y\]es or \[N\]o):" 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/Healthchecks/hc_webhook_empty_expect_long.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m hc --webhook 7 | 8 | expect "Enter your webhook URL:" 9 | send -- "https://discordapp.com/api/webhooks/123456789/qwerty-qwerty-qwerty/slack\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/Healthchecks/hc_webhook_empty_expect_short.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m healthchecks -w 7 | 8 | expect "Enter your webhook URL:" 9 | send -- "https://discordapp.com/api/webhooks/123456789/qwerty-qwerty-qwerty/slack\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/StatusCake/sc_api_key_expect.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -df 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | set apiKey $::env(travisSCApiKey) 7 | set username $::env(travisSCUsername) 8 | 9 | spawn bash Travis/Scripts/travis_tronitor.sh -m statuscake -l 10 | 11 | expect "Enter your Statuscake API key:" 12 | send -- "this-is-a-bad-api-key\r" 13 | 14 | expect "Enter your Statuscake username:" 15 | send -- "$username\r" 16 | 17 | expect "Enter your Statuscake username:" 18 | send -- "$username\r" 19 | 20 | expect "Enter your Statuscake API key:" 21 | send -- "$apiKey\r" 22 | 23 | expect eof 24 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/StatusCake/sc_cleanup.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m sc -d all 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o):" 9 | send -- "y\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/StatusCake/sc_delete_expect_long.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m sc --delete travisone 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o):" 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/StatusCake/sc_delete_expect_short.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m statuscake -d travistwo 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o):" 9 | send -- "y\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/StatusCake/sc_find_expect_long.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m sc --find 7 | 8 | expect "Would you like to unpause the paused monitors? (\[Y\]es or \[N\]o): " 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/StatusCake/sc_find_expect_short.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m statuscake -f 7 | 8 | expect "Would you like to unpause the paused monitors? (\[Y\]es or \[N\]o): " 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/StatusCake/sc_pause_invalid_expect.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m statuscake -p GoogleHttp,foobar 7 | 8 | expect "\[Y\]es or \[N\]o):" 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/StatusCake/sc_webhook_empty_expect_long.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m sc --webhook 7 | 8 | expect "Enter your webhook URL:" 9 | send -- "https://discordapp.com/api/webhooks/123456789/qwerty-qwerty-qwerty/slack\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/StatusCake/sc_webhook_empty_expect_short.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m statuscake -w 7 | 8 | expect "Enter your webhook URL:" 9 | send -- "https://discordapp.com/api/webhooks/123456789/qwerty-qwerty-qwerty/slack\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_api_key_expect.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | set apiKey $::env(travisApiKey) 7 | 8 | spawn bash Travis/Scripts/travis_tronitor.sh -m ur -l 9 | 10 | expect "Enter your Uptimerobot API key:" 11 | send -- "this-is-a-bad-api-key\r" 12 | 13 | expect "Enter your Uptimerobot API key:" 14 | send -- "$apiKey\r" 15 | 16 | expect eof 17 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_cleanup.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m uptimerobot -d all 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o):" 9 | send -- "y\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_delete_expect_long.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m ur --delete travisone 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o):" 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_delete_expect_short.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m uptimerobot -d travistwo 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o):" 9 | send -- "y\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_find_expect_long.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m ur --find 7 | 8 | expect "Would you like to unpause the paused monitors? (\[Y\]es or \[N\]o): " 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_find_expect_short.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m uptimerobot -f 7 | 8 | expect "Would you like to unpause the paused monitors? (\[Y\]es or \[N\]o): " 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_pause_invalid_expect.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m ur -p GoogleHttp,foobar 7 | 8 | expect "\[Y\]es or \[N\]o):" 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_reset_expect_long.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m ur --reset all 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o):" 9 | send -- "n\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_reset_expect_short.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m uptimerobot -r all 7 | 8 | expect "Are you sure you wish to continue? (\[Y\]es or \[N\]o): " 9 | send -- "y\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_webhook_empty_expect_long.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m ur --webhook 7 | 8 | expect "Enter your webhook URL:" 9 | send -- "https://discordapp.com/api/webhooks/123456789/qwerty-qwerty-qwerty/slack\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/Expects/UptimeRobot/ur_webhook_empty_expect_short.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | #!/usr/bin/env bash 3 | 4 | set timeout 10 5 | 6 | spawn bash Travis/Scripts/travis_tronitor.sh -m uptimerobot -w 7 | 8 | expect "Enter your webhook URL:" 9 | send -- "https://discordapp.com/api/webhooks/123456789/qwerty-qwerty-qwerty/slack\r" 10 | 11 | expect eof 12 | -------------------------------------------------------------------------------- /Travis/Scripts/hc_prep.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | curl -s -X POST https://healthchecks.io/api/v1/checks/ -H "X-Api-Key: ${travisHCApiKey}" \ 4 | --data '{"name": "TravisOne", "tags": "prod www", "timeout": 3600, "grace": 60}' 5 | 6 | curl -s -X POST https://healthchecks.io/api/v1/checks/ -H "X-Api-Key: ${travisHCApiKey}" \ 7 | --data '{"name": "TravisTwo", "tags": "prod www", "timeout": 3600, "grace": 60}' 8 | 9 | curl -s -X POST https://healthchecks.io/api/v1/checks/ -H "X-Api-Key: ${travisHCApiKey}" \ 10 | --data '{"name": "TravisThree", "tags": "prod www", "timeout": 3600, "grace": 60}' 11 | 12 | curl -s -X POST https://healthchecks.io/api/v1/checks/ -H "X-Api-Key: ${travisHCApiKey}" \ 13 | --data '{"name": "GooglePing", "tags": "prod www", "timeout": 3600, "grace": 60}' -------------------------------------------------------------------------------- /Travis/Scripts/sc_prep.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | curl -s -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" -H "API: ${travisSCApiKey}" -H "Username: ${travisSCUsername}" -d "WebsiteName=TravisOne&WebsiteURL=https://google.co.uk&CheckRate=300&TestType=HTTP" -X PUT https://app.statuscake.com/API/Tests/Update 4 | 5 | curl -s -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" -H "API: ${travisSCApiKey}" -H "Username: ${travisSCUsername}" -d "WebsiteName=TravisTwo&WebsiteURL=http://chrisyocumissuperawesome.com&CheckRate=300&TestType=HTTP" -X PUT https://app.statuscake.com/API/Tests/Update 6 | 7 | curl -s -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" -H "API: ${travisSCApiKey}" -H "Username: ${travisSCUsername}" -d "WebsiteName=TravisThree&WebsiteURL=https://ebay.com&CheckRate=300&TestType=HTTP" -X PUT https://app.statuscake.com/API/Tests/Update 8 | -------------------------------------------------------------------------------- /Travis/Scripts/shfmt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | sudo wget https://raw.githubusercontent.com/mvdan/sh/master/cmd/shfmt/Dockerfile 4 | sudo docker build -t jamesmstone/shfmt . 5 | sudo docker run -it --rm -v /home/travis/build/tronyx/tronitor/Travis/Scripts:/sh -w /sh mvdan/shfmt:latest -s -i 4 -ci -sr -d travis_tronitor.sh 6 | sudo docker run -it --rm -v /home/travis/build/tronyx/tronitor:/sh -w /sh mvdan/shfmt:latest -s -i 4 -ci -sr -d tronitor.sh 7 | -------------------------------------------------------------------------------- /Travis/Scripts/ur_prep.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | curl -s -X POST -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" -d "api_key=${travisApiKey}&format=json&type=1&url=https://google.co.uk&friendly_name=TravisOne" "https://api.uptimerobot.com/v2/newMonitor" 4 | 5 | curl -s -X POST -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" -d "api_key=${travisApiKey}&format=json&type=1&url=http://chrisyocumissuperawesome.com&friendly_name=TravisTwo" "https://api.uptimerobot.com/v2/newMonitor" 6 | 7 | curl -s -X POST -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" -d "api_key=${travisApiKey}&format=json&type=1&url=https://ebay.com&friendly_name=TravisThree" "https://api.uptimerobot.com/v2/newMonitor" 8 | -------------------------------------------------------------------------------- /tronitor.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Script to utilize the UptimeRobot, StatusCake, and HealthChecks.io APIs to 4 | # retrieve information on and work with checks you've created. 5 | # Tronyx 6 | set -eo pipefail 7 | IFS=$'\n\t' 8 | 9 | # Edit these with your corresponding information to finish setting up the script 10 | # or just run it and it will prompt you for it. 11 | # If your provider is StatusCake, specify your username. 12 | scUsername='' 13 | # If your provider is Upptime, specify the following. 14 | repoOwner='' 15 | gitHubUsername='' 16 | upptimeRepo='upptime' 17 | # Specify API key(s). 18 | urApiKey='' 19 | scApiKey='' 20 | hcApiKey='' 21 | ghToken='' 22 | # Specify the domain to use for Healthchecks as they allow you to self-host the 23 | # application. If you're self-hosting it, replace the default domain with the 24 | # domain you're hosting it on. 25 | healthchecksDomain='healthchecks.io' 26 | # Specify the Discord/Slack webhook URL to send notifications to. 27 | webhookUrl='' 28 | # Set notifyAll to true for notification to apply for all running state as well. 29 | notifyAll='false' 30 | # Set JQ to false to disable its use for displaying output. This works better 31 | # for using the script with cronjobs, etc. 32 | jq='true' 33 | 34 | # Declare some variables. 35 | # Temp dir and filenames. 36 | # Make sure you set this to something your user has write access to. 37 | tempDir="$HOME/tronitor/" 38 | apiTestFullFile="${tempDir}api_test_full.txt" 39 | badMonitorsFile="${tempDir}bad_monitors.txt" 40 | convertedMonitorsFile="${tempDir}converted_monitors.txt" 41 | friendlyListFile="${tempDir}friendly_list.txt" 42 | pausedMonitorsFile="${tempDir}paused_monitors.txt" 43 | specifiedMonitorsFile="${tempDir}specified_monitors.txt" 44 | monitorsFile="${tempDir}monitors.txt" 45 | monitorsFullFile="${tempDir}monitors_full.txt" 46 | hcPingURLsFile="${tempDir}hc_ping_urls.txt" 47 | validMonitorsFile="${tempDir}valid_monitors.txt" 48 | validMonitorsTempFile="${tempDir}valid_monitors_temp.txt" 49 | healthchecksLockFile="${tempDir}healthchecks.lock" 50 | # UUID regex pattern. 51 | uuidPattern='^\{?[A-Z0-9a-z]{8}-[A-Z0-9a-z]{4}-[A-Z0-9a-z]{4}-[A-Z0-9a-z]{4}-[A-Z0-9a-z]{12}\}?$' 52 | # Set initial API key(s) status. 53 | urApiKeyStatus='invalid' 54 | scApiKeyStatus='invalid' 55 | hcApiKeyStatus='invalid' 56 | ghTokenStatus='invalid' 57 | # Set initial provider status. 58 | urProviderStatus='invalid' 59 | scProviderStatus='invalid' 60 | hcProviderStatus='invalid' 61 | upProviderStatus='invalid' 62 | # Set initial SC username status. 63 | scUsernameStatus='invalid' 64 | # Set initial GH repo owner and username status. 65 | ghRepoOwnerStatus='invalid' 66 | ghUsernameStatus='invalid' 67 | # Set initial Upptime repo status. 68 | upRepoStatus='invalid' 69 | # Arguments. 70 | readonly args=("$@") 71 | # Text colors. 72 | #readonly blu='\e[34m' 73 | readonly lblu='\e[94m' 74 | readonly grn='\e[32m' 75 | readonly red='\e[31m' 76 | readonly ylw='\e[33m' 77 | readonly org='\e[38;5;202m' 78 | readonly lorg='\e[38;5;130m' 79 | readonly mgt='\e[35m' 80 | #readonly bold='\e[1m' 81 | readonly endColor='\e[0m' 82 | 83 | # Function to define usage and script options. 84 | usage() { 85 | cat <<- EOF 86 | 87 | Usage: $(echo -e "${lorg}$0${endColor}") $(echo -e "${grn}"-m"${endColor}" "${ylw}"\{MONITOR\}"${endColor}") $(echo -e "${grn}"-[OPTION]"${endColor}") $(echo -e "${ylw}"\{ARGUMENT\}"${endColor}"...) 88 | 89 | $(echo -e "${grn}"-m/--monitor"${endColor}" "${ylw}"VALUE"${endColor}") Specify the monitoring provider you would like to work with. 90 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-m"${endColor}" "${ylw}"UptimeRobot"${endColor}" "${grn}"-\[OPTION\]"${endColor}" "${ylw}"\{ARGUMENT\}"${endColor}")" 91 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--monitor"${endColor}" "${ylw}"\'sc\'"${endColor}" "${grn}"-l"${endColor}")" 92 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-m"${endColor}" "${ylw}"\"healthchecks\""${endColor}" "${grn}"-p"${endColor}" "${ylw}"all"${endColor}")" 93 | 94 | $(echo -e "${grn}"-s/--stats"${endColor}""${red}"*+"${endColor}") List account statistics. 95 | 96 | $(echo -e "${grn}"-l/--list"${endColor}""${red}"+"${endColor}") List all monitors. 97 | 98 | $(echo -e "${grn}"-f/--find"${endColor}") Find all paused monitors. 99 | 100 | $(echo -e "${grn}"-n/--no-prompt"${endColor}") Find all paused monitors without an unpause prompt. 101 | 102 | $(echo -e "${grn}"-w/--webhook"${endColor}""${red}"+"${endColor}") Find all paused monitors without an unpause prompt and 103 | send an alert to the Discord webhook specified in the script. 104 | 105 | $(echo -e "${grn}"-i/--info"${endColor}""${red}"+"${endColor}" "${ylw}"VALUE"${endColor}") List all information for the specified monitor. 106 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-i"${endColor}" "${ylw}"18095689"${endColor}")" 107 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--info"${endColor}" "${ylw}"\'Plex\'"${endColor}")" 108 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-i"${endColor}" "${ylw}"\"Tautulli\""${endColor}")" 109 | 110 | $(echo -e "${grn}"-a/--alerts"${endColor}""${red}"+"${endColor}") List all alert contacts. 111 | 112 | $(echo -e "${grn}"-p/--pause"${endColor}" "${ylw}"VALUE"${endColor}") Pause specified monitors. 113 | Option accepts arguments in the form of "$(echo -e "${ylw}"all"${endColor}")" or a comma-separated list 114 | of monitors by ID or Friendly Name. Friendly Name should be wrapped in 115 | a set of single or double quotes, IE: 116 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-p"${endColor}" "${ylw}"all"${endColor}")" 117 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--pause"${endColor}" "${ylw}"18095687,18095688,18095689"${endColor}")" 118 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-p"${endColor}" "${ylw}"\'Plex\',\"Tautulli\",18095689"${endColor}")" 119 | $(echo -e "${ylw}"NOTE:"${endColor}" For Upptime, the only possible option is "${ylw}"all"${endColor}".) 120 | 121 | $(echo -e "${grn}"-u/--unpause"${endColor}" "${ylw}"VALUE"${endColor}") Unpause specified monitors. 122 | Option accepts arguments in the form of "$(echo -e "${ylw}"all"${endColor}")" or a comma-separated list 123 | of monitors by ID or Friendly Name. Friendly Name should be wrapped in 124 | a set of single or double quotes, IE: 125 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-u"${endColor}" "${ylw}"all"${endColor}")" 126 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--unpause"${endColor}" "${ylw}"18095687,18095688,18095689"${endColor}")" 127 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-u"${endColor}" "${ylw}"\'Plex\',\"Tautulli\",18095689"${endColor}")" 128 | $(echo -e "${ylw}"NOTE:"${endColor}" For Upptime, the only possible option is "${ylw}"all"${endColor}".) 129 | 130 | $(echo -e "${grn}"-c/--create"${endColor}""${red}"+"${endColor}" "${ylw}"VALUE"${endColor}") Create a new monitor using the corresponding template file. Each type of test 131 | (HTTP, Ping, Port, & Keyword) has a template file in the Templates directory. 132 | Just edit the template file for the monitor type you wish to create and then run 133 | the script with the corresponding monitor type, IE: 134 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-c"${endColor}" "${ylw}"http"${endColor}")" 135 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--create"${endColor}" "${ylw}"port"${endColor}")" 136 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-c"${endColor}" "${ylw}"keyword"${endColor}")" 137 | 138 | $(echo -e "${grn}"-d/--delete"${endColor}""${red}"+"${endColor}" "${ylw}"VALUE"${endColor}") Delete the specified monitor, IE: 139 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-d"${endColor}" "${ylw}"\'Plex\'"${endColor}")" 140 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--delete"${endColor}" "${ylw}"\"Tautulli\""${endColor}")" 141 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-d"${endColor}" "${ylw}"18095688"${endColor}")" 142 | 143 | $(echo -e "${grn}"-r/--reset"${endColor}""${red}"*+"${endColor}" "${ylw}"VALUE"${endColor}") Reset the specified monitor, IE: 144 | A) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-r"${endColor}" "${ylw}"\'Plex\'"${endColor}")" 145 | B) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"--reset"${endColor}" "${ylw}"\"Tautulli\""${endColor}")" 146 | C) "$(echo -e "${lorg}"./tronitor.sh"${endColor}" "${grn}"-r"${endColor}" "${ylw}"18095688"${endColor}")" 147 | 148 | $(echo -e "${grn}"-h/--help"${endColor}") Display this usage dialog. 149 | 150 | 151 | $(echo -e "${red}"\*"${endColor}""${ylw}" - Option is not compatible with StatusCake or HealthChecks.io."${endColor}") 152 | $(echo -e "${red}"\+"${endColor}""${ylw}" - Option is not compatible with Upptime."${endColor}") 153 | 154 | EOF 155 | 156 | } 157 | 158 | # Function to define script options. 159 | cmdline() { 160 | local arg= 161 | local local_args 162 | local OPTERR=0 163 | for arg; do 164 | local delim="" 165 | case "${arg}" in 166 | # Translate --gnu-long-options to -g (short options). 167 | --monitor) local_args="${local_args}-m " ;; 168 | --stats) local_args="${local_args}-s " ;; 169 | --list) local_args="${local_args}-l " ;; 170 | --find) local_args="${local_args}-f " ;; 171 | --no-prompt) local_args="${local_args}-n " ;; 172 | --webhook) local_args="${local_args}-w " ;; 173 | --info) local_args="${local_args:-}-i " ;; 174 | --alerts) local_args="${local_args}-a " ;; 175 | --create) local_args="${local_args:-}-c " ;; 176 | --pause) local_args="${local_args:-}-p " ;; 177 | --unpause) local_args="${local_args:-}-u " ;; 178 | --reset) local_args="${local_args:-}-r " ;; 179 | --delete) local_args="${local_args:-}-d " ;; 180 | --help) local_args="${local_args}-h " ;; 181 | # Pass through anything else. 182 | *) 183 | [[ ${arg:0:1} == '-' ]] || delim='"' 184 | local_args="${local_args:-}${delim}${arg}${delim} " 185 | ;; 186 | esac 187 | done 188 | 189 | # Reset the positional parameters to the short options. 190 | eval set -- "${local_args:-}" 191 | 192 | while getopts "hm:slfnwai:c:r:d:p:u:" OPTION; do 193 | case "$OPTION" in 194 | m) 195 | providerName="${OPTARG}" 196 | monitorFlag=true 197 | ;; 198 | s) 199 | stats=true 200 | ;; 201 | l) 202 | list=true 203 | ;; 204 | f) 205 | find=true 206 | prompt=true 207 | ;; 208 | n) 209 | find=true 210 | prompt=false 211 | ;; 212 | w) 213 | find=true 214 | prompt=false 215 | webhook=true 216 | ;; 217 | a) 218 | alerts=true 219 | ;; 220 | i) 221 | info=true 222 | infoType="${OPTARG}" 223 | ;; 224 | c) 225 | create=true 226 | createType="${OPTARG}" 227 | ;; 228 | r) 229 | reset=true 230 | resetType="${OPTARG}" 231 | ;; 232 | d) 233 | delete=true 234 | deleteType="${OPTARG}" 235 | ;; 236 | p) 237 | pause=true 238 | pauseType="${OPTARG}" 239 | ;; 240 | u) 241 | unpause=true 242 | unpauseType="${OPTARG}" 243 | ;; 244 | h) 245 | usage 246 | exit 247 | ;; 248 | *) 249 | if [[ ${arg} == '-m' || ${arg} == '-p' || ${arg} == '-u' || ${arg} == '-r' || ${arg} == '-d' || ${arg} == '-i' || ${arg} == '-c' ]] && [[ -z ${OPTARG} ]]; then 250 | echo -e "${red}Option ${arg} requires an argument!${endColor}" 251 | else 252 | echo -e "${red}You are specifying a non-existent option!${endColor}" 253 | fi 254 | usage 255 | exit 256 | ;; 257 | esac 258 | done 259 | shift $((OPTIND - 1)) 260 | return 0 261 | } 262 | 263 | # Function to gather script information. 264 | get_scriptname() { 265 | local source 266 | local dir 267 | source="${BASH_SOURCE[0]}" 268 | 269 | while [[ -L ${source} ]]; do 270 | dir="$(cd -P "$(dirname "${source}")" > /dev/null && pwd)" 271 | source="$(readlink "${source}")" 272 | [[ ${source} != /* ]] && source="${dir}/${source}" 273 | done 274 | 275 | echo "${source}" 276 | } 277 | 278 | readonly scriptname="$(get_scriptname)" 279 | 280 | # Function to create the directory to neatly store temp files, if it does 281 | # not exist. 282 | create_dir() { 283 | mkdir -p "${tempDir}" 284 | chmod 777 "${tempDir}" 285 | } 286 | 287 | # Function to cleanup temp files. 288 | cleanup() { 289 | rm -rf "${tempDir}"*.txt || true 290 | } 291 | trap 'cleanup' 0 1 3 6 14 15 292 | 293 | # Function to exit the script if the user hits CTRL+C. 294 | function control_c() { 295 | cleanup 296 | exit 0 297 | } 298 | trap 'control_c' 2 299 | 300 | # Function to check that the monitor option has been provided. 301 | check_monitor_opt() { 302 | if [[ ${monitorFlag} != 'true' ]]; then 303 | echo -e "${red}You must specify the monitor you wish to work with!${endColor}" 304 | usage 305 | exit 306 | fi 307 | } 308 | 309 | # Function to check that two options were provided. 310 | check_opt_num() { 311 | if [[ ${OPTIND} -lt '4' || ${OPTIND} -gt '5' ]]; then 312 | echo -e "${red}You specified an invalid number of options!${endColor}" 313 | usage 314 | exit 315 | fi 316 | } 317 | 318 | # Function to check for an empty arg. 319 | check_empty_arg() { 320 | for arg in "${args[@]:-}"; do 321 | if [[ -z ${arg} ]]; then 322 | usage 323 | exit 324 | fi 325 | done 326 | } 327 | 328 | # Function to check that only all is used for pause and unpause if the provider 329 | # is Upptime 330 | check_pauseType_upptime() { 331 | if [[ ${providerName} == 'upptime' ]] && [[ ${pause} == 'true' || ${unpause} == 'true' ]] && [[ ${pauseType} != 'all' && ${unpauseType} != 'all' ]]; then 332 | echo -e "${red}You can only specify all for Upptime!${endColor}" 333 | usage 334 | exit 335 | fi 336 | } 337 | 338 | # Function to check if cURL is installed and, if not, inform the user and exit. 339 | check_curl() { 340 | whichCURL=$(which curl) 341 | if [[ -z ${whichCURL} ]]; then 342 | echo -e "${red}cURL is not currently installed on this system!${endColor}" 343 | echo -e "${ylw}The script with NOT function without it. Install cURL and run the script again.${endColor}" 344 | exit 345 | fi 346 | } 347 | 348 | # Function to grab line numbers of the user-defined and status variables. 349 | get_line_numbers() { 350 | # Line numbers for user-defined variables. 351 | scUsernameLineNum=$(head -68 "${scriptname}" | grep -En -A1 'specify your username' | tail -1 | awk -F- '{print $1}') 352 | ghRepoOwnerLineNum=$(head -68 "${scriptname}" | grep -En 'repoOwner' | awk -F: '{print $1}') 353 | ghUsernameLineNum=$(head -68 "${scriptname}" | grep -En 'gitHubUser' | awk -F: '{print $1}') 354 | upRepoLineNum=$(head -68 "${scriptname}" | grep -En 'upptimeRepo' | awk -F: '{print $1}') 355 | urApiKeyLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Specify API key' | grep 'ur' | awk -F- '{print $1}') 356 | scApiKeyLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Specify API key' | grep 'sc' | awk -F- '{print $1}') 357 | hcApiKeyLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Specify API key' | grep 'hc' | awk -F- '{print $1}') 358 | ghTokenLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Specify API key' | grep 'gh' | awk -F- '{print $1}') 359 | webhookUrlLineNum=$(head -68 "${scriptname}" | grep -En -A1 'Discord/Slack' | tail -1 | awk -F- '{print $1}') 360 | # Line numbers for status variables. 361 | urApiStatusLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Set initial API key' | grep 'ur' | awk -F- '{print $1}') 362 | scApiStatusLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Set initial API key' | grep 'sc' | awk -F- '{print $1}') 363 | hcApiStatusLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Set initial API key' | grep 'hc' | awk -F- '{print $1}') 364 | ghTokenStatusLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Set initial API key' | grep 'gh' | awk -F- '{print $1}') 365 | urProviderStatusLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Set initial provider status' | grep 'ur' | awk -F- '{print $1}') 366 | scProviderStatusLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Set initial provider status' | grep 'sc' | awk -F- '{print $1}') 367 | hcProviderStatusLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Set initial provider status' | grep 'hc' | awk -F- '{print $1}') 368 | upProviderStatusLineNum=$(head -68 "${scriptname}" | grep -En -A4 'Set initial provider status' | grep 'up' | awk -F- '{print $1}') 369 | scUserStatusLineNum=$(head -68 "${scriptname}" | grep -En -A1 'Set initial SC username status' | tail -1 | awk -F- '{print $1}') 370 | ghUserStatusLineNum=$(head -68 "${scriptname}" | grep -En -A2 'Set initial GH repo owner and username status' | grep ghUser | awk -F- '{print $1}') 371 | ghRepoOwnerStatusLineNum=$(head -68 "${scriptname}" | grep -En -A2 'Set initial GH repo owner and username status' | grep RepoOwner | awk -F- '{print $1}') 372 | upRepoStatusLineNum=$(head -68 "${scriptname}" | grep -En -A1 'Set initial Upptime repo status' | tail -1 | awk -F- '{print $1}') 373 | } 374 | 375 | # Function for catching when a curl or jq command fails to display a message and 376 | # exit the script. 377 | fatal() { 378 | echo -e "${red}There seems to be an issue connecting to ${providerName^}. Please try again in a few minutes.${endColor}" 379 | exit 380 | } 381 | 382 | # Function to convert shorthand provider names to their full names and to make 383 | # sure the provider name is lowercase and, if not, convert it. 384 | convert_provider_name() { 385 | if [[ ${providerName} == 'ur' ]]; then 386 | providerName='uptimerobot' 387 | elif [[ ${providerName} == 'sc' ]]; then 388 | providerName='statuscake' 389 | elif [[ ${providerName} == 'hc' ]]; then 390 | providerName='healthchecks' 391 | elif [[ ${providerName} == 'up' ]]; then 392 | providerName='upptime' 393 | fi 394 | 395 | if [[ ${providerName} =~ [[:upper:]] ]]; then 396 | providerName=$(echo "${providerName}" | awk '{print tolower($0)}') 397 | fi 398 | } 399 | 400 | # Function to check that provider is not empty and valid. 401 | check_provider() { 402 | if [[ ${providerName} == 'uptimerobot' ]]; then 403 | providerStatus="${urProviderStatus}" 404 | elif [[ ${providerName} == 'statuscake' ]]; then 405 | providerStatus="${scProviderStatus}" 406 | elif [[ ${providerName} == 'healthchecks' ]]; then 407 | providerStatus="${hcProviderStatus}" 408 | elif [[ ${providerName} == 'upptime' ]]; then 409 | providerStatus="${upProviderStatus}" 410 | else 411 | providerStatus='invalid' 412 | fi 413 | 414 | while [[ ${providerStatus} == 'invalid' ]]; do 415 | if [[ ${providerName} != 'uptimerobot' ]] && [[ ${providerName} != 'statuscake' ]] && [[ ${providerName} != 'healthchecks' ]] && [[ ${providerName} != 'upptime' ]]; then 416 | echo -e "${red}You didn't specify a valid monitoring provider with the -m flag!${endColor}" 417 | echo -e "${ylw}Please specify either uptimerobot, statuscake, healthchecks, or upptime.${endColor}" 418 | exit 419 | else 420 | if [[ ${providerName} == 'uptimerobot' ]]; then 421 | sed -i "${urProviderStatusLineNum} s|urProviderStatus='[^']*'|urProviderStatus='ok'|" "${scriptname}" 422 | elif [[ ${providerName} == 'statuscake' ]]; then 423 | sed -i "${scProviderStatusLineNum} s|scProviderStatus='[^']*'|scProviderStatus='ok'|" "${scriptname}" 424 | elif [[ ${providerName} == 'healthchecks' ]]; then 425 | sed -i "${hcProviderStatusLineNum} s|hcProviderStatus='[^']*'|hcProviderStatus='ok'|" "${scriptname}" 426 | elif [[ ${providerName} == 'upptime' ]]; then 427 | sed -i "${upProviderStatusLineNum} s|upProviderStatus='[^']*'|upProviderStatus='ok'|" "${scriptname}" 428 | fi 429 | 430 | convert_provider_name 431 | 432 | if [[ ${providerName} == 'uptimerobot' ]]; then 433 | urProviderStatus='ok' 434 | elif [[ ${providerName} == 'statuscake' ]]; then 435 | scProviderStatus='ok' 436 | elif [[ ${providerName} == 'healthchecks' ]]; then 437 | hcProviderStatus='ok' 438 | elif [[ ${providerName} == 'upptime' ]]; then 439 | upProviderStatus='ok' 440 | fi 441 | 442 | providerStatus='ok' 443 | 444 | fi 445 | done 446 | 447 | if [[ ${providerName} == 'uptimerobot' ]]; then 448 | readonly apiUrl='https://api.uptimerobot.com/v2/' 449 | elif [[ ${providerName} == 'statuscake' ]]; then 450 | readonly apiUrl='https://app.statuscake.com/API/' 451 | elif [[ ${providerName} == 'healthchecks' ]]; then 452 | readonly apiUrl="https://${healthchecksDomain}/api/v1/" 453 | elif [[ ${providerName} == 'upptime' ]]; then 454 | readonly apiUrl='https://api.github.com/' 455 | upRawURL="https://raw.githubusercontent.com/${repoOwner}/${upptimeRepo}/" 456 | fi 457 | } 458 | 459 | # Function to specifically check that the provided StatusCake username and API 460 | # key are valid. 461 | check_sc_creds() { 462 | while [[ ${scUsernameStatus} == 'invalid' ]] || [[ ${scApiKeyStatus} == 'invalid' ]]; do 463 | if [[ -z ${scApiKey} ]]; then 464 | echo -e "${red}You didn't define your ${providerName^} API key in the script!${endColor}" 465 | echo '' 466 | echo "Enter your ${providerName^} API key:" 467 | read -rs API 468 | echo '' 469 | echo '' 470 | sed -i "${scApiKeyLineNum} s/scApiKey='[^']*'/scApiKey='${API}'/" "${scriptname}" 471 | scApiKey="${API}" 472 | elif [[ -z ${scUsername} ]]; then 473 | echo -e "${red}You didn't specify your ${providerName^} username in the script!${endColor}" 474 | echo '' 475 | echo "Enter your ${providerName^} username:" 476 | read -r username 477 | echo '' 478 | echo '' 479 | sed -i "${scUsernameLineNum} s/scUsername='[^']*'/scUsername='${username}'/" "${scriptname}" 480 | scUsername="${username}" 481 | else 482 | scStatus=$(curl -s -H "API: ${scApiKey}" -H "Username: ${scUsername}" -X GET "${apiUrl}"Tests/ | jq .ErrNo 2> /dev/null || echo '1') 483 | 484 | if [[ ${scStatus} == '0' ]]; then 485 | clear >&2 486 | echo -e "${red}The API Key and/or username that you provided for ${providerName^} are not valid!${endColor}" 487 | sed -i "${scApiKeyLineNum} s/scApiKey='[^']*'/scApiKey=''/" "${scriptname}" 488 | scApiKey='' 489 | sed -i "${scUsernameLineNum} s/scUsername='[^']*'/scUsername=''/" "${scriptname}" 490 | scUsername='' 491 | echo '' 492 | echo "Enter your ${providerName^} username:" 493 | read -r username 494 | echo '' 495 | echo '' 496 | sed -i "${scUsernameLineNum} s/scUsername='[^']*'/scUsername='${username}'/" "${scriptname}" 497 | scUsername="${username}" 498 | elif [[ ${scStatus} == '1' ]]; then 499 | echo "Validating that the provided ${providerName^} username and API key are functional..." 500 | sed -i "${scApiStatusLineNum} s/scApiKeyStatus='[^']*'/scApiKeyStatus='ok'/" "${scriptname}" 501 | scApiKeyStatus='ok' 502 | sed -i "${scUserStatusLineNum} s/scUsernameStatus='[^']*'/scUsernameStatus='ok'/" "${scriptname}" 503 | scUsernameStatus='ok' 504 | echo -e "${grn}Success!${endColor}" 505 | echo '' 506 | fi 507 | fi 508 | done 509 | } 510 | 511 | # Function to check that the provided Upptime repo owner, GitHub username, and PAT are valid. 512 | check_gh_creds() { 513 | while [[ ${ghRepoOwnerStatus} == 'invalid' ]] || [[ ${ghUsernameStatus} == 'invalid' ]] || [[ ${ghTokenStatus} == 'invalid' ]]; do 514 | if [[ -z ${ghToken} ]]; then 515 | echo -e "${red}You didn't define your ${providerName^} PAT in the script!${endColor}" 516 | echo '' 517 | echo "Enter your ${providerName^} PAT:" 518 | read -rs API 519 | echo '' 520 | echo '' 521 | sed -i "${ghTokenLineNum} s/ghToken='[^']*'/ghToken='${API}'/" "${scriptname}" 522 | ghToken="${API}" 523 | elif [[ -z ${repoOwner} ]]; then 524 | echo -e "${red}You didn't specify the owner of your Upptime repository in the script!${endColor}" 525 | echo '' 526 | echo "Enter your Upptime repo owner:" 527 | read -r owner 528 | echo '' 529 | echo '' 530 | sed -i "${ghRepoOwnerLineNum} s/repoOwner='[^']*'/repoOwner='${owner}'/" "${scriptname}" 531 | repoOwner="${owner}" 532 | upRawURL="https://raw.githubusercontent.com/${repoOwner}/${upptimeRepo}/" 533 | elif [[ -z ${gitHubUsername} ]]; then 534 | echo -e "${red}You didn't specify your GitHub username in the script!${endColor}" 535 | echo '' 536 | echo "Enter your GitHub username:" 537 | read -r username 538 | echo '' 539 | echo '' 540 | sed -i "${ghUsernameLineNum} s/gitHubUsername='[^']*'/gitHubUsername='${username}'/" "${scriptname}" 541 | gitHubUsername="${username}" 542 | else 543 | ghStatus=$(curl -s -XGET -H "Authorization: bearer ${ghToken}" "${apiUrl}"user | jq -r .login) 544 | ghStatus=$(echo "${ghStatus}" | awk '{print tolower($0)}') 545 | 546 | if [[ ${ghStatus} != "${gitHubUsername}" ]]; then 547 | clear >&2 548 | echo -e "${red}The PAT and/or username that you provided for GitHub are not valid!${endColor}" 549 | sed -i "${ghTokenLineNum} s/ghToken='[^']*'/ghToken=''/" "${scriptname}" 550 | ghToken='' 551 | sed -i "${ghUsernameLineNum} s/gitHubUsername='[^']*'/gitHubUsername=''/" "${scriptname}" 552 | gitHubUsername='' 553 | echo '' 554 | echo "Enter your GitHub username:" 555 | read -r username 556 | echo '' 557 | echo '' 558 | sed -i "${ghUsernameLineNum} s/gitHubUsername='[^']*'/gitHubUsername='${username}'/" "${scriptname}" 559 | gitHubUsername="${username}" 560 | upRawURL="https://raw.githubusercontent.com/${repoOwner}/${upptimeRepo}/" 561 | elif [[ ${ghStatus} == "${gitHubUsername}" ]]; then 562 | echo 'Validating that the provided Upptime repo owner, GitHub username, and PAT are functional...' 563 | sed -i "${ghRepoOwnerStatusLineNum} s/ghRepoOwnerStatus='[^']*'/ghRepoOwnerStatus='ok'/" "${scriptname}" 564 | ghRepoOwnerStatus='ok' 565 | sed -i "${ghTokenStatusLineNum} s/ghTokenStatus='[^']*'/ghTokenStatus='ok'/" "${scriptname}" 566 | ghTokenStatus='ok' 567 | sed -i "${ghUserStatusLineNum} s/ghUsernameStatus='[^']*'/ghUsernameStatus='ok'/" "${scriptname}" 568 | ghUsernameStatus='ok' 569 | echo -e "${grn}Success!${endColor}" 570 | echo '' 571 | fi 572 | fi 573 | done 574 | } 575 | 576 | # Function to check that the provided Upptime repository is valid. 577 | check_up_repo() { 578 | while [[ ${upRepoStatus} == 'invalid' ]]; do 579 | if [[ -z ${upptimeRepo} ]]; then 580 | echo -e "${red}You didn't define your ${providerName^} repository in the script!${endColor}" 581 | echo '' 582 | echo "Enter your ${providerName^} repository name:" 583 | read -r repo 584 | echo '' 585 | echo '' 586 | sed -i "${upRepoLineNum} s/upptimeRepo='[^']*'/upptimeRepo='${repo}'/" "${scriptname}" 587 | upptimeRepo="${repo}" 588 | upRawURL="https://raw.githubusercontent.com/${repoOwner}/${upptimeRepo}/" 589 | else 590 | echo 'Validating that the provided Upptime repository is functional...' 591 | status=$(curl -w "%{http_code}\n" -sI -o /dev/null https://github.com/"${repoOwner}"/"${upptimeRepo}"/) || fatal 592 | 593 | if [[ ${status} != '200' ]]; then 594 | echo -e "${red}The Upptime repository that you provided does not appear to be valid!${endColor}" 595 | echo -e "${ylw}Resetting it so that you can enter it again...${endColor}" 596 | sed -i "${upRepoLineNum} s/upptimeRepo='[^']*'/upptimeRepo=''/" "${scriptname}" 597 | upptimeRepo='' 598 | echo '' 599 | elif [[ ${status} == '200' ]]; then 600 | sed -i "${upRepoStatusLineNum} s/upRepoStatus='[^']*'/upRepoStatus='ok'/" "${scriptname}" 601 | upRepoStatus='ok' 602 | upRawURL="https://raw.githubusercontent.com/${repoOwner}/${upptimeRepo}/" 603 | echo -e "${grn}Success!${endColor}" 604 | echo '' 605 | fi 606 | fi 607 | done 608 | } 609 | 610 | # Function to check that the provided UptimeRobot or Healthchecks.io API Key 611 | # is valid. 612 | check_api_key() { 613 | if [[ ${providerName} == 'uptimerobot' ]]; then 614 | while [[ ${urApiKeyStatus} == 'invalid' ]]; do 615 | if [[ -z ${urApiKey} ]]; then 616 | echo -e "${red}You didn't define your ${providerName^} API key in the script!${endColor}" 617 | echo '' 618 | echo "Enter your ${providerName^} API key:" 619 | read -rs API 620 | echo '' 621 | echo '' 622 | sed -i "${urApiKeyLineNum} s/urApiKey='[^']*'/urApiKey='${API}'/" "${scriptname}" 623 | urApiKey="${API}" 624 | else 625 | curl --fail -s -X POST "${apiUrl}"getAccountDetails -d "api_key=${urApiKey}" -d "format=json" > "${apiTestFullFile}" || fatal 626 | status=$(jq -r .stat "${apiTestFullFile}" 2> /dev/null) || fatal 627 | 628 | if [[ ${status} == 'fail' ]]; then 629 | echo -e "${red}The API Key that you provided for ${providerName^} is not valid!${endColor}" 630 | sed -i "${urApiKeyLineNum} s/urApiKey='[^']*'/urApiKey=''/" "${scriptname}" 631 | urApiKey='' 632 | elif [[ ${status} == 'ok' ]]; then 633 | echo "Validating that the provided ${providerName^} API key is functional..." 634 | sed -i "${urApiStatusLineNum} s/urApiKeyStatus='[^']*'/urApiKeyStatus='${status}'/" "${scriptname}" 635 | urApiKeyStatus="${status}" 636 | echo -e "${grn}Success!${endColor}" 637 | echo '' 638 | fi 639 | fi 640 | done 641 | elif [[ ${providerName} == 'healthchecks' ]]; then 642 | while [[ ${hcApiKeyStatus} == 'invalid' ]]; do 643 | if [[ -z ${hcApiKey} ]]; then 644 | echo -e "${red}You didn't define your ${providerName^} API key in the script!${endColor}" 645 | echo '' 646 | echo "Enter your ${providerName^} API key:" 647 | read -rs API 648 | echo '' 649 | echo '' 650 | sed -i "${hcApiKeyLineNum} s/hcApiKey='[^']*'/hcApiKey='${API}'/" "${scriptname}" 651 | hcApiKey="${API}" 652 | else 653 | curl --fail -s -H "X-Api-Key: ${hcApiKey}" -X GET "${apiUrl}"checks/ > "${apiTestFullFile}" 654 | status=$(jq -r .error "${apiTestFullFile}" 2> /dev/null) || fatal 655 | 656 | if [[ ${status} != 'null' ]]; then 657 | echo -e "${red}The API Key that you provided for ${providerName^} is not valid!${endColor}" 658 | sed -i "${hcApiKeyLineNum} s/hcApiKey='[^']*'/hcApiKey=''/" "${scriptname}" 659 | hcApiKey='' 660 | elif [[ ${status} == 'null' ]]; then 661 | echo "Validating that the provided ${providerName^} API key is functional..." 662 | sed -i "${hcApiStatusLineNum} s/hcApiKeyStatus='[^']*'/hcApiKeyStatus='ok'/" "${scriptname}" 663 | hcApiKeyStatus='ok' 664 | echo -e "${grn}Success!${endColor}" 665 | echo '' 666 | fi 667 | fi 668 | done 669 | fi 670 | } 671 | 672 | # Function to check that the webhook URL is defined if alert is set to true. 673 | check_webhook_url() { 674 | if [[ ${webhookUrl} == '' ]] && [[ ${webhook} == 'true' ]]; then 675 | echo -e "${red}You didn't define your Discord webhook URL!${endColor}" 676 | echo '' 677 | echo 'Enter your webhook URL:' 678 | read -r url 679 | echo '' 680 | echo '' 681 | sed -i "${webhookUrlLineNum} s|webhookUrl='[^']*'|webhookUrl='${url}'|" "${scriptname}" 682 | webhookUrl="${url}" 683 | fi 684 | } 685 | 686 | # Function to wrap all other checks into one function. 687 | checks() { 688 | get_line_numbers 689 | check_monitor_opt 690 | check_opt_num 691 | check_empty_arg 692 | check_pauseType_upptime 693 | check_curl 694 | check_provider 695 | 696 | if [[ ${providerName} == 'statuscake' ]]; then 697 | check_sc_creds 698 | elif [[ ${providerName} == 'upptime' ]]; then 699 | check_gh_creds 700 | check_up_repo 701 | else 702 | check_api_key 703 | fi 704 | 705 | check_webhook_url 706 | } 707 | 708 | # Function to set the API key variable to the API key for the specified monitor. 709 | set_api_key() { 710 | if [[ ${providerName} == 'uptimerobot' ]]; then 711 | apiKey="${urApiKey}" 712 | elif [[ ${providerName} == 'statuscake' ]]; then 713 | apiKey="${scApiKey}" 714 | elif [[ ${providerName} == 'healthchecks' ]]; then 715 | apiKey="${hcApiKey}" 716 | elif [[ ${providerName} == 'upptime' ]]; then 717 | apiKey="${ghToken}" 718 | fi 719 | } 720 | 721 | # Function to grab data for all monitors. 722 | get_data() { 723 | if [[ ${providerName} == 'uptimerobot' ]]; then 724 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"getMonitors -d "api_key=${apiKey}" -d "format=json" > "${monitorsFullFile}" || fatal 725 | elif [[ ${providerName} == 'statuscake' ]]; then 726 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -X GET "${apiUrl}"Tests/ > "${monitorsFullFile}" || fatal 727 | elif [[ ${providerName} == 'healthchecks' ]]; then 728 | curl --fail -s -H "X-Api-Key: ${apiKey}" -X GET "${apiUrl}"checks/ > "${monitorsFullFile}" || fatal 729 | elif [[ ${providerName} == 'upptime' ]]; then 730 | curl --fail -s -H "Authorization: bearer ${ghToken}" "${apiUrl}repos/${repoOwner}/${upptimeRepo}/git/trees/master?recursive=1" | grep -e 'api\/' | awk -F'/' 'NF==2' | awk -F'/' '{print $2}' | tr -d '",' > "${monitorsFullFile}" || fatal 731 | fi 732 | } 733 | 734 | # Function to create a list of monitor IDs. 735 | get_monitors() { 736 | if [[ ${providerName} == 'uptimerobot' ]]; then 737 | totalMonitors=$(jq -r .pagination.total "${monitorsFullFile}" 2> /dev/null) || fatal 738 | elif [[ ${providerName} == 'statuscake' ]]; then 739 | totalMonitors=$(jq -r .[].TestID "${monitorsFullFile}" | wc -l 2> /dev/null) || fatal 740 | elif [[ ${providerName} == 'healthchecks' ]]; then 741 | totalMonitors=$(jq -r .checks[].name "${monitorsFullFile}" | wc -l 2> /dev/null) || fatal 742 | elif [[ ${providerName} == 'upptime' ]]; then 743 | totalMonitors=$(wc -l "${monitorsFullFile}" | awk '{print $1}' 2> /dev/null) || fatal 744 | fi 745 | 746 | if [[ ${totalMonitors} == '0' ]]; then 747 | echo "There are currently no monitors associated with your ${providerName^} account." 748 | exit 0 749 | else 750 | if [[ ${providerName} == 'uptimerobot' ]]; then 751 | jq -r .monitors[].id "${monitorsFullFile}" > "${monitorsFile}" 2> /dev/null || fatal 752 | elif [[ ${providerName} == 'statuscake' ]]; then 753 | jq -r .[].TestID "${monitorsFullFile}" > "${monitorsFile}" 2> /dev/null || fatal 754 | elif [[ ${providerName} == 'healthchecks' ]]; then 755 | jq -r .checks[].ping_url "${monitorsFullFile}" 2> /dev/null > "${hcPingURLsFile}" || fatal 756 | rev "${hcPingURLsFile}" | cut -c1-36 | rev > "${monitorsFile}" 757 | elif [[ ${providerName} == 'upptime' ]]; then 758 | cat "${monitorsFullFile}" > "${monitorsFile}" 2> /dev/null || fatal 759 | fi 760 | fi 761 | } 762 | 763 | # Function to create individual monitor files. 764 | create_monitor_files() { 765 | while IFS= read -r monitor; do 766 | if [[ ${providerName} == 'uptimerobot' ]]; then 767 | jq -r '. | {stat: .stat, pagination: .pagination, monitors: [.monitors[] | select(.id=='"${monitor}"')]} | .pagination.total=1' "${monitorsFullFile}" > "${tempDir}${monitor}".txt 768 | elif [[ ${providerName} == 'statuscake' ]]; then 769 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -X GET "${apiUrl}Tests/Details/?TestID=${monitor}" > "${tempDir}${monitor}".txt || fatal 770 | elif [[ ${providerName} == 'healthchecks' ]]; then 771 | jq --arg monitor "${monitor}" '.checks[] | select(.ping_url | contains($monitor))' "${monitorsFullFile}" > "${tempDir}${monitor}".txt 772 | elif [[ ${providerName} == 'upptime' ]]; then 773 | curl --fail -s -H "Authorization: bearer ${ghToken}" "${upRawURL}master/history/${monitor}.yml" 2> /dev/null > "${tempDir}${monitor}".txt || fatal 774 | fi 775 | done < <(cat "${monitorsFile}") 776 | } 777 | 778 | # Function to create friendly output of all monitors. 779 | create_friendly_list() { 780 | true > "${friendlyListFile}" 781 | 782 | while IFS= read -r monitor; do 783 | if [[ ${providerName} == 'uptimerobot' ]]; then 784 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 785 | status=$(jq .monitors[].status "${tempDir}${monitor}".txt 2> /dev/null) || fatal 786 | 787 | if [[ ${status} == '0' ]]; then 788 | friendlyStatus="${ylw}Paused${endColor}" 789 | elif [[ ${status} == '1' ]]; then 790 | friendlyStatus="${mgt}Not checked yet${endColor}" 791 | elif [[ ${status} == '2' ]]; then 792 | friendlyStatus="${grn}Up${endColor}" 793 | elif [[ ${status} == '8' ]]; then 794 | friendlyStatus="${org}Seems down${endColor}" 795 | elif [[ ${status} == '9' ]]; then 796 | friendlyStatus="${red}Down${endColor}" 797 | fi 798 | elif [[ ${providerName} == 'statuscake' ]]; then 799 | friendlyName=$(jq -r .WebsiteName "${tempDir}${monitor}".txt 2> /dev/null) || fatal 800 | status=$(jq -r .Status "${tempDir}${monitor}".txt 2> /dev/null) || fatal 801 | paused=$(jq -r .Paused "${tempDir}${monitor}".txt 2> /dev/null) || fatal 802 | 803 | if [[ ${status} == 'Up' ]] && [[ ${paused} == 'true' ]]; then 804 | friendlyStatus="${ylw}Paused (Up)${endColor}" 805 | elif [[ ${status} == 'Down' ]] && [[ ${paused} == 'true' ]]; then 806 | friendlyStatus="${ylw}Paused (Down)${endColor}" 807 | elif [[ ${status} == 'Up' ]] && [[ ${paused} == 'false' ]]; then 808 | friendlyStatus="${grn}Up${endColor}" 809 | elif [[ ${status} == 'Down' ]] && [[ ${paused} == 'false' ]]; then 810 | friendlyStatus="${red}Down${endColor}" 811 | fi 812 | elif [[ ${providerName} == 'healthchecks' ]]; then 813 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 814 | friendlyName=$(jq -r .name "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 815 | status=$(jq -r .status "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 816 | 817 | if [[ ${status} == 'up' ]]; then 818 | friendlyStatus="${grn}Up${endColor}" 819 | elif [[ ${status} == 'down' ]]; then 820 | friendlyStatus="${red}Down${endColor}" 821 | elif [[ ${status} == 'paused' ]]; then 822 | friendlyStatus="${ylw}Paused${endColor}" 823 | elif [[ ${status} == 'late' ]]; then 824 | friendlyStatus="${org}Late${endColor}" 825 | elif [[ ${status} == 'new' ]]; then 826 | friendlyStatus="${mgt}New${endColor}" 827 | fi 828 | elif [[ ${providerName} == 'upptime' ]]; then 829 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 830 | siteURL=$(grep url "${tempDir}${monitor}"_short.txt | awk '{print $2}') 831 | friendlyName=$(curl --fail -s "${upRawURL}master/.upptimerc.yml" | grep -v href | grep -B1 "${siteURL}"$ | grep name | awk -F':' '{print $2}' | cut -c2- 2> /dev/null) || fatal 832 | status=$(grep status "${tempDir}${monitor}"_short.txt | grep -v url | awk '{print $2}' 2> /dev/null) || fatal 833 | workflowStatus=$(curl -s -H "Authorization: bearer ${ghToken}" -H "Accept: application/vnd.github.v3+json" "${apiUrl}repos/${repoOwner}/${upptimeRepo}/actions/workflows/uptime.yml" | jq -r .state) 834 | 835 | if [[ ${workflowStatus} == 'disabled_manually' ]]; then 836 | status='paused' 837 | fi 838 | 839 | if [[ ${status} == 'up' ]]; then 840 | friendlyStatus="${grn}Up${endColor}" 841 | elif [[ ${status} == 'down' ]]; then 842 | friendlyStatus="${red}Down${endColor}" 843 | elif [[ ${status} == 'paused' ]]; then 844 | friendlyStatus="${ylw}Paused${endColor}" 845 | fi 846 | fi 847 | 848 | if [[ ${providerName} == 'upptime' ]]; then 849 | echo -e "${lorg}${friendlyName}${endColor} | URL: ${lblu}${siteURL}${endColor} | Status: ${friendlyStatus}" >> "${friendlyListFile}" 850 | else 851 | echo -e "${lorg}${friendlyName}${endColor} | ID: ${lblu}${monitor}${endColor} | Status: ${friendlyStatus}" >> "${friendlyListFile}" 852 | fi 853 | 854 | done < <(cat "${monitorsFile}") 855 | } 856 | 857 | # Function to display a friendly list of all monitors. 858 | display_all_monitors() { 859 | if [[ -s ${friendlyListFile} ]]; then 860 | if [[ ${providerName} == 'upptime' ]]; then 861 | echo "The following monitors were found in your ${providerName^} repository:" 862 | echo '' 863 | column -ts "|" "${friendlyListFile}" 864 | echo '' 865 | else 866 | echo "The following monitors were found in your ${providerName^} account:" 867 | echo '' 868 | column -ts "|" "${friendlyListFile}" 869 | echo '' 870 | fi 871 | fi 872 | } 873 | 874 | # Function to find all currently paused monitors. 875 | get_paused_monitors() { 876 | true > "${pausedMonitorsFile}" 877 | 878 | if [[ ${providerName} == 'upptime' ]]; then 879 | workflowStatus=$(curl -s -H "Authorization: bearer ${ghToken}" -H "Accept: application/vnd.github.v3+json" "${apiUrl}repos/${repoOwner}/${upptimeRepo}/actions/workflows/uptime.yml" | jq -r .state) 880 | if [[ ${workflowStatus} == 'disabled_manually' ]]; then 881 | while IFS= read -r monitor; do 882 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 883 | siteURL=$(grep url "${tempDir}${monitor}"_short.txt | awk '{print $2}') 884 | friendlyName=$(curl --fail -s "${upRawURL}master/.upptimerc.yml" | grep -v href | grep -B1 "${siteURL}"$ | grep name | awk -F':' '{print $2}' | cut -c2- 2> /dev/null) || fatal 885 | echo -e "${lorg}${friendlyName}${endColor} | URL: ${lblu}${siteURL}${endColor}" >> "${pausedMonitorsFile}" 886 | done < <(cat "${monitorsFile}") 887 | fi 888 | else 889 | while IFS= read -r monitor; do 890 | if [[ ${providerName} == 'uptimerobot' ]]; then 891 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 892 | status=$(jq -r .monitors[].status "${tempDir}${monitor}".txt 2> /dev/null) || fatal 893 | 894 | if [[ ${status} == '0' ]]; then 895 | echo -e "${lorg}${friendlyName}${endColor} | ID: ${lblu}${monitor}${endColor}" >> "${pausedMonitorsFile}" 896 | fi 897 | elif [[ ${providerName} == 'statuscake' ]]; then 898 | friendlyName=$(jq -r .WebsiteName "${tempDir}${monitor}".txt 2> /dev/null) || fatal 899 | status=$(jq -r .Status "${tempDir}${monitor}".txt 2> /dev/null) || fatal 900 | paused=$(jq -r .Paused "${tempDir}${monitor}".txt 2> /dev/null) || fatal 901 | 902 | if [[ ${status} == 'Up' ]] && [[ ${paused} == 'true' ]]; then 903 | echo -e "${lorg}${friendlyName}${endColor} | ID: ${lblu}${monitor}${endColor}" >> "${pausedMonitorsFile}" 904 | fi 905 | elif [[ ${providerName} == 'healthchecks' ]]; then 906 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 907 | friendlyName=$(jq -r .name "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 908 | status=$(jq -r .status "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 909 | 910 | if [[ ${status} == 'paused' ]]; then 911 | echo -e "${lorg}${friendlyName}${endColor} | ID: ${lblu}${monitor}${endColor}" >> "${pausedMonitorsFile}" 912 | fi 913 | fi 914 | done < <(cat "${monitorsFile}") 915 | fi 916 | } 917 | 918 | # Function to display a list of all paused monitors. 919 | display_paused_monitors() { 920 | if [[ -s ${pausedMonitorsFile} ]]; then 921 | echo "The following ${providerName^} monitors are currently paused:" 922 | echo '' 923 | column -ts "|" "${pausedMonitorsFile}" 924 | echo '' 925 | else 926 | echo "There are currently no paused ${providerName^} monitors." 927 | echo '' 928 | fi 929 | } 930 | 931 | # Function to prompt the user to unpause monitors after finding paused monitors. 932 | unpause_prompt() { 933 | echo '' 934 | echo -e "Would you like to unpause the currently paused monitors? (${grn}[Y]${endColor}es or ${red}[N]${endColor}o): " 935 | read -r unpausePrompt 936 | echo '' 937 | 938 | if ! [[ ${unpausePrompt} =~ ^(Yes|yes|Y|y|No|no|N|n)$ ]]; then 939 | echo -e "${red}Please specify yes, y, no, or n.${endColor}" 940 | read -r unpausePrompt 941 | fi 942 | } 943 | 944 | # Function to prompt the user to continue actioning valid monitors after 945 | # finding invalid ones. 946 | invalid_prompt() { 947 | echo 'Would you like to continue actioning the following valid monitors?' 948 | echo '' 949 | cat "${validMonitorsFile}" 950 | echo '' 951 | echo -e "${grn}[Y]${endColor}es or ${red}[N]${endColor}o):" 952 | read -r invalidPrompt 953 | echo '' 954 | 955 | if ! [[ ${invalidPrompt} =~ ^(Yes|yes|Y|y|No|no|N|n)$ ]]; then 956 | echo -e "${red}Please specify yes, y, no, or n.${endColor}" 957 | read -r invalidPrompt 958 | fi 959 | } 960 | 961 | # Function to check if any bad, IE: non-existent, monitors were provided. 962 | check_bad_monitors() { 963 | true > "${badMonitorsFile}" 964 | 965 | while IFS= read -r monitor; do 966 | if [[ $(sed 's/\x1B\[[0-9;]*[JKmsu]//g' "${friendlyListFile}" | grep -ic "${monitor} |") != "1" ]]; then 967 | if [[ ${monitor} =~ ^[A-Za-z]+$ ]]; then 968 | echo -e "${lorg}${monitor}${endColor}" >> "${badMonitorsFile}" 969 | elif [[ ${monitor} != ^[A-Za-z]+$ ]]; then 970 | echo -e "${lblu}${monitor}${endColor}" >> "${badMonitorsFile}" 971 | fi 972 | fi 973 | done < <(sed 's/\x1B\[[0-9;]*[JKmsu]//g' "${specifiedMonitorsFile}") 974 | 975 | if [[ -s ${badMonitorsFile} ]]; then 976 | echo -e "${red}The following monitors you specified are not valid:${endColor}" 977 | echo '' 978 | cat "${badMonitorsFile}" 979 | sed -i 's/\x1B\[[0-9;]*[JKmsu]//g' "${badMonitorsFile}" 980 | set +e 981 | grep -vxf "${badMonitorsFile}" "${specifiedMonitorsFile}" > "${validMonitorsTempFile}" 982 | true > "${validMonitorsFile}" 983 | 984 | if [[ -s ${validMonitorsTempFile} ]]; then 985 | while IFS= read -r monitor; do 986 | echo -e "${grn}${monitor}${endColor}" >> "${validMonitorsFile}" 987 | done < <(cat "${validMonitorsTempFile}") 988 | echo '' 989 | invalid_prompt 990 | elif [[ ! -s ${validMonitorsTempFile} ]]; then 991 | echo '' 992 | echo 'Please make sure you are specifying a valid monitor and try again.' 993 | echo '' 994 | exit 995 | fi 996 | set -e 997 | fi 998 | } 999 | 1000 | # Function to convert friendly names to IDs. 1001 | convert_friendly_monitors() { 1002 | true > "${convertedMonitorsFile}" 1003 | 1004 | if [[ -s ${validMonitorsFile} ]]; then 1005 | cat "${validMonitorsFile}" > "${specifiedMonitorsFile}" 1006 | fi 1007 | 1008 | if [[ ${providerName} == 'healthchecks' ]]; then 1009 | while IFS= read -r monitor; do 1010 | if [[ $(echo "${monitor}" | tr -d ' ') =~ ${uuidPattern} ]]; then 1011 | echo "${monitor}" >> "${convertedMonitorsFile}" 1012 | else 1013 | tempCurl=$(curl --fail -s -H "X-Api-Key: ${apiKey}" -X GET ${apiUrl}checks/) || fatal 1014 | tempJQ=$(echo "${tempCurl}" | jq -r --arg monitor "${monitor}" '.checks[] | select(.name | match($monitor;"i"))'.ping_url 2> /dev/null) || fatal 1015 | echo "${tempJQ}" | rev | cut -c1-36 | rev >> "${convertedMonitorsFile}" 1016 | fi 1017 | done < <(sed 's/\x1B\[[0-9;]*[JKmsu]//g' "${specifiedMonitorsFile}") 1018 | else 1019 | while IFS= read -r monitor; do 1020 | if [[ $(echo "${monitor}" | tr -d ' ') =~ [A-Za-z] ]]; then 1021 | sed 's/\x1B\[[0-9;]*[JKmsu]//g' "${friendlyListFile}" | grep -i "${monitor} |" | awk -F ':' '{print $2}' | awk -F ' ' '{print $1}' >> "${convertedMonitorsFile}" 1022 | else 1023 | echo "${monitor}" >> "${convertedMonitorsFile}" 1024 | fi 1025 | done < <(sed 's/\x1B\[[0-9;]*[JKmsu]//g' "${specifiedMonitorsFile}") 1026 | fi 1027 | } 1028 | 1029 | # Function to pause all monitors. 1030 | pause_all_monitors() { 1031 | if [[ ${providerName} == 'upptime' ]]; then 1032 | workflowStatus=$(curl -s -H "Authorization: bearer ${ghToken}" -H "Accept: application/vnd.github.v3+json" "${apiUrl}repos/${repoOwner}/${upptimeRepo}/actions/workflows/uptime.yml" | jq -r .state) 1033 | if [[ ${workflowStatus} == 'disabled_manually' ]]; then 1034 | echo -e "${ylw}The Uptime CI workflow for your Upptime repository is already paused!${endColor}" 1035 | elif [[ ${workflowStatus} != 'disabled_manually' ]]; then 1036 | echo 'Pausing the Uptime CI workflow for your Upptime repository...' 1037 | curl --fail -X PUT -H "Authorization: bearer ${ghToken}" -H "Accept: application/vnd.github.v3+json" "${apiUrl}repos/${repoOwner}/${upptimeRepo}/actions/workflows/uptime.yml/disable" 2> /dev/null || fatal 1038 | echo -e "${grn}Success!${endColor}" 1039 | echo '' 1040 | fi 1041 | else 1042 | while IFS= read -r monitor; do 1043 | if [[ ${providerName} == 'uptimerobot' ]]; then 1044 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1045 | echo "Pausing ${friendlyName}:" 1046 | 1047 | if [[ ${jq} == 'true' ]]; then 1048 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"editMonitor -d "api_key=${apiKey}" -d "id=${monitor}" -d "status=0" | jq 2> /dev/null || fatal 1049 | elif [[ ${jq} == 'false' ]]; then 1050 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"editMonitor -d "api_key=${apiKey}" -d "id=${monitor}" -d "status=0" || fatal 1051 | fi 1052 | elif [[ ${providerName} == 'statuscake' ]]; then 1053 | friendlyName=$(jq -r .WebsiteName "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1054 | echo "Pausing ${friendlyName}:" 1055 | 1056 | if [[ ${jq} == 'true' ]]; then 1057 | curl -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -d "Paused=1" -X PUT "${apiUrl}Tests/Update" | jq 2> /dev/null || fatal 1058 | elif [[ ${jq} == 'false' ]]; then 1059 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -d "Paused=1" -X PUT "${apiUrl}Tests/Update" || fatal 1060 | fi 1061 | elif [[ ${providerName} == 'healthchecks' ]]; then 1062 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 1063 | friendlyName=$(jq -r .name "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 1064 | true > "${healthchecksLockFile}" 1065 | echo "Pausing ${friendlyName}:" 1066 | 1067 | if [[ ${jq} == 'true' ]]; then 1068 | curl -s "${apiUrl}checks/${monitor}"/pause -X POST -H "X-Api-Key: ${apiKey}" --data "" | jq 2> /dev/null || fatal 1069 | elif [[ ${jq} == 'false' ]]; then 1070 | curl --fail -s "${apiUrl}checks/${monitor}"/pause -X POST -H "X-Api-Key: ${apiKey}" --data "" || fatal 1071 | fi 1072 | fi 1073 | 1074 | echo '' 1075 | 1076 | done < <(cat "${monitorsFile}") 1077 | fi 1078 | if [[ ${providerName} == 'healthchecks' ]]; then 1079 | echo '' 1080 | echo -e "${ylw}**NOTE:** Healthchecks.io works with cronjobs so, unless you disable your cronjobs for${endColor}" 1081 | echo -e "${ylw}the HC.io monitors, or work with the created lock file, all paused monitors will become${endColor}" 1082 | echo -e "${ylw}active again the next time they receive a ping.${endColor}" 1083 | echo '' 1084 | else 1085 | : 1086 | fi 1087 | } 1088 | 1089 | # Function to pause specified monitors. 1090 | pause_specified_monitors() { 1091 | echo "${pauseType}" | tr , '\n' | tr -d '"' > "${specifiedMonitorsFile}" 1092 | check_bad_monitors 1093 | 1094 | if [[ ${invalidPrompt} == @(No|no|N|n) ]]; then 1095 | exit 0 1096 | else 1097 | convert_friendly_monitors 1098 | fi 1099 | 1100 | while IFS= read -r monitor; do 1101 | if [[ ${providerName} == 'uptimerobot' ]]; then 1102 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1103 | echo "Pausing ${friendlyName}:" 1104 | 1105 | if [[ ${jq} == 'true' ]]; then 1106 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"editMonitor -d "api_key=${apiKey}" -d "id=${monitor}" -d "status=0" | jq 2> /dev/null || fatal 1107 | elif [[ ${jq} == 'false' ]]; then 1108 | curl --fail -s -X POST "${apiUrl}"editMonitor -d "api_key=${apiKey}" -d "id=${monitor}" -d "status=0" || fatal 1109 | fi 1110 | elif [[ ${providerName} == 'statuscake' ]]; then 1111 | friendlyName=$(jq -r .WebsiteName "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1112 | echo "Pausing ${friendlyName}:" 1113 | 1114 | if [[ ${jq} == 'true' ]]; then 1115 | curl -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -d "Paused=1" -X PUT "${apiUrl}Tests/Update" | jq 2> /dev/null || fatal 1116 | elif [[ ${jq} == 'false' ]]; then 1117 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -d "Paused=1" -X PUT "${apiUrl}Tests/Update" || fatal 1118 | fi 1119 | elif [[ ${providerName} == 'healthchecks' ]]; then 1120 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 1121 | friendlyName=$(jq -r .name "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 1122 | true > "${tempDir}${monitor}".lock 1123 | echo "Pausing ${friendlyName}:" 1124 | 1125 | if [[ ${jq} == 'true' ]]; then 1126 | curl -s "${apiUrl}checks/${monitor}"/pause -X POST -H "X-Api-Key: ${apiKey}" --data "" | jq 2> /dev/null || fatal 1127 | elif [[ ${jq} == 'false' ]]; then 1128 | curl --fail -s "${apiUrl}checks/${monitor}"/pause -X POST -H "X-Api-Key: ${apiKey}" --data "" || fatal 1129 | fi 1130 | fi 1131 | 1132 | echo '' 1133 | 1134 | done < <(sed 's/\x1B\[[0-9;]*[JKmsu]//g' "${convertedMonitorsFile}") 1135 | 1136 | if [[ ${providerName} == 'healthchecks' ]]; then 1137 | echo '' 1138 | echo -e "${ylw}**NOTE:** Healthchecks.io works with cronjobs so, unless you disable your cronjobs for${endColor}" 1139 | echo -e "${ylw}the HC.io monitors, all paused monitors will become active again the next time they receive a ping.${endColor}" 1140 | echo '' 1141 | fi 1142 | } 1143 | 1144 | # Function to unpause all monitors. 1145 | unpause_all_monitors() { 1146 | if [[ ${providerName} == 'upptime' ]]; then 1147 | echo 'Unpausing the Uptime CI workflow for your Upptime repository...' 1148 | curl --fail -X PUT -H "Authorization: bearer ${ghToken}" -H "Accept: application/vnd.github.v3+json" "${apiUrl}repos/${repoOwner}/${upptimeRepo}/actions/workflows/uptime.yml/enable" 2> /dev/null || fatal 1149 | echo -e "${grn}Success!${endColor}" 1150 | echo '' 1151 | else 1152 | while IFS= read -r monitor; do 1153 | if [[ ${providerName} == 'uptimerobot' ]]; then 1154 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1155 | echo "Unpausing ${friendlyName}:" 1156 | 1157 | if [[ ${jq} == 'true' ]]; then 1158 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"editMonitor -d "api_key=${apiKey}" -d "id=${monitor}" -d "status=1" | jq 2> /dev/null || fatal 1159 | elif [[ ${jq} == 'false' ]]; then 1160 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"editMonitor -d "api_key=${apiKey}" -d "id=${monitor}" -d "status=1" || fatal 1161 | fi 1162 | elif [[ ${providerName} == 'statuscake' ]]; then 1163 | friendlyName=$(jq -r .WebsiteName "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1164 | echo "Unpausing ${friendlyName}:" 1165 | 1166 | if [[ ${jq} == 'true' ]]; then 1167 | curl -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -d "Paused=0" -X PUT "${apiUrl}Tests/Update" | jq 2> /dev/null || fatal 1168 | elif [[ ${jq} == 'false' ]]; then 1169 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -d "Paused=0" -X PUT "${apiUrl}Tests/Update" || fatal 1170 | fi 1171 | elif [[ ${providerName} == 'healthchecks' ]]; then 1172 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 1173 | friendlyName=$(jq -r .name "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 1174 | pingURL=$(jq -r .ping_url "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 1175 | rm -f "${healthchecksLockFile}" 1176 | rm -f "${tempDir}"*.lock 1177 | echo "Unpausing ${friendlyName} by sending a ping:" 1178 | pingResponse=$(curl -fsS --retry 3 "${pingURL}") 1179 | 1180 | if [[ ${pingResponse} == 'OK' ]]; then 1181 | echo -e "${grn}Success!${endColor}" 1182 | else 1183 | echo -e "${red}Unable to unpause ${friendlyName}!${endColor}" 1184 | fi 1185 | fi 1186 | 1187 | echo '' 1188 | 1189 | done < <(cat "${monitorsFile}") 1190 | fi 1191 | } 1192 | 1193 | # Function to unpause specified monitors. 1194 | unpause_specified_monitors() { 1195 | echo "${unpauseType}" | tr , '\n' | tr -d '"' > "${specifiedMonitorsFile}" 1196 | check_bad_monitors 1197 | 1198 | if [[ ${invalidPrompt} == @(No|no|N|n) ]]; then 1199 | exit 0 1200 | else 1201 | convert_friendly_monitors 1202 | fi 1203 | 1204 | while IFS= read -r monitor; do 1205 | if [[ ${providerName} == 'uptimerobot' ]]; then 1206 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1207 | echo "Unpausing ${friendlyName}:" 1208 | 1209 | if [[ ${jq} == 'true' ]]; then 1210 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"editMonitor -d "api_key=${apiKey}" -d "id=${monitor}" -d "status=1" | jq 2> /dev/null || fatal 1211 | elif [[ ${jq} == 'false' ]]; then 1212 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"editMonitor -d "api_key=${apiKey}" -d "id=${monitor}" -d "status=1" || fatal 1213 | fi 1214 | elif [[ ${providerName} == 'statuscake' ]]; then 1215 | friendlyName=$(jq -r .WebsiteName "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1216 | echo "Unpausing ${friendlyName}:" 1217 | 1218 | if [[ ${jq} == 'true' ]]; then 1219 | curl -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -d "Paused=0" -X PUT "${apiUrl}Tests/Update" | jq 2> /dev/null || fatal 1220 | elif [[ ${jq} == 'false' ]]; then 1221 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -d "Paused=0" -X PUT "${apiUrl}Tests/Update" || fatal 1222 | fi 1223 | elif [[ ${providerName} == 'healthchecks' ]]; then 1224 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 1225 | friendlyName=$(jq -r .name "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 1226 | pingURL=$(jq -r .ping_url "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 1227 | rm -f "${tempDir}${monitor}".lock 1228 | echo "Unpausing ${friendlyName} by sending a ping:" 1229 | pingResponse=$(curl -fsS --retry 3 "${pingURL}") 1230 | 1231 | if [[ ${pingResponse} == 'OK' ]]; then 1232 | echo -e "${grn}Success!${endColor}" 1233 | else 1234 | echo -e "${red}Unable to unpause ${friendlyName}!${endColor}" 1235 | fi 1236 | fi 1237 | 1238 | echo '' 1239 | 1240 | done < <(sed 's/\x1B\[[0-9;]*[JKmsu]//g' "${convertedMonitorsFile}") 1241 | } 1242 | 1243 | # Function to send Discord notifications. 1244 | send_notification() { 1245 | if [[ -s ${pausedMonitorsFile} ]]; then 1246 | pausedTests='"fields": [' 1247 | lineCount=$(wc -l < "${pausedMonitorsFile}") 1248 | count=0 1249 | 1250 | while IFS= read -r line; do 1251 | ((++count)) 1252 | pausedTests="${pausedTests}{\"name\": \"$(echo ${line} | sed 's/\x1B\[[0-9;]*[JKmsu]//g' | cut -d '|' -f 1)\", 1253 | \"value\": \"$(echo ${line} | sed 's/\x1B\[[0-9;]*[JKmsu]//g' | cut -d '|' -f 2)\"}" 1254 | 1255 | if [[ ${count} -ne ${lineCount} ]]; then 1256 | pausedTests="${pausedTests}," 1257 | fi 1258 | 1259 | done < "${pausedMonitorsFile}" 1260 | 1261 | pausedTests="${pausedTests}]" 1262 | 1263 | if [[ ${providerName} == 'uptimerobot' ]]; then 1264 | curl -s -H "Content-Type: application/json" -X POST -d '{"embeds": [{ "title": "There are currently paused UptimeRobot monitors:","color": 3381759,'"${pausedTests}"'}]}' "${webhookUrl}" 1265 | elif [[ ${providerName} == 'statuscake' ]]; then 1266 | curl -s -H "Content-Type: application/json" -X POST -d '{"embeds": [{ "title": "There are currently paused StatusCake monitors:","color": 3381759,'"${pausedTests}"'}]}' "${webhookUrl}" 1267 | elif [[ ${providerName} == 'healthchecks' ]]; then 1268 | curl -s -H "Content-Type: application/json" -X POST -d '{"embeds": [{ "title": "There are currently paused HealthChecks.io monitors:","color": 3381759,'"${pausedTests}"'}]}' "${webhookUrl}" 1269 | elif [[ ${providerName} == 'upptime' ]]; then 1270 | curl -s -H "Content-Type: application/json" -X POST -d '{"embeds": [{ "title": "The Uptime CI workflow for your Upptime repository is currently disabled!","color": 3381759}]}' "${webhookUrl}" 1271 | fi 1272 | elif [[ ${notifyAll} == 'true' ]]; then 1273 | if [[ ${providerName} == 'uptimerobot' ]]; then 1274 | curl -s -H "Content-Type: application/json" -X POST -d '{"embeds": [{ "title": "All UptimeRobot monitors are currently running.","color": 10092339}]}' "${webhookUrl}" 1275 | elif [[ ${providerName} == 'statuscake' ]]; then 1276 | curl -s -H "Content-Type: application/json" -X POST -d '{"embeds": [{ "title": "All StatusCake monitors are currently running.","color": 10092339}]}' "${webhookUrl}" 1277 | elif [[ ${providerName} == 'healthchecks' ]]; then 1278 | curl -s -H "Content-Type: application/json" -X POST -d '{"embeds": [{ "title": "All HealthChecks.io monitors are currently running.","color": 10092339}]}' "${webhookUrl}" 1279 | elif [[ ${providerName} == 'upptime' ]]; then 1280 | curl -s -H "Content-Type: application/json" -X POST -d '{"embeds": [{ "title": "The Uptime CI workflow for your Upptime repository is currently enabled.","color": 3381759}]}' "${webhookUrl}" 1281 | fi 1282 | fi 1283 | } 1284 | 1285 | # Function to create a new monitor. 1286 | create_monitor() { 1287 | if [[ ${providerName} == 'uptimerobot' ]]; then 1288 | newHttpMonitorConfigFile='Templates/UptimeRobot/new-http-monitor.json' 1289 | newPortMonitorConfigFile='Templates/UptimeRobot/new-port-monitor.json' 1290 | newKeywordMonitorConfigFile='Templates/UptimeRobot/new-keyword-monitor.json' 1291 | newPingMonitorConfigFile='Templates/UptimeRobot/new-ping-monitor.json' 1292 | elif [[ ${providerName} == 'statuscake' ]]; then 1293 | newHttpMonitorConfigFile='Templates/StatusCake/new-http-monitor.txt' 1294 | newPortMonitorConfigFile='Templates/StatusCake/new-port-monitor.txt' 1295 | newPingMonitorConfigFile='Templates/StatusCake/new-ping-monitor.txt' 1296 | elif [[ ${providerName} == 'healthchecks' ]]; then 1297 | newPingMonitorConfigFile='Templates/HealthChecks/new-monitor.json' 1298 | fi 1299 | 1300 | if [[ ${providerName} == 'uptimerobot' ]]; then 1301 | if [[ ${createType} != 'http' && ${createType} != 'ping' && ${createType} != 'port' && ${createType} != 'keyword' ]]; then 1302 | echo -e "${red}You did not specify a valid monitor type!${endColor}" 1303 | echo -e "${red}Your choices are http, ping, port, or keyword.${endColor}" 1304 | echo '' 1305 | exit 0 1306 | fi 1307 | elif [[ ${providerName} == 'statuscake' ]]; then 1308 | if [[ ${createType} != 'http' && ${createType} != 'ping' && ${createType} != 'port' ]]; then 1309 | echo -e "${red}You did not specify a valid monitor type!${endColor}" 1310 | echo -e "${red}Your choices are http, ping, or port.${endColor}" 1311 | echo '' 1312 | exit 0 1313 | fi 1314 | elif [[ ${providerName} == 'healthchecks' ]]; then 1315 | if [[ ${createType} != 'ping' ]]; then 1316 | echo -e "${red}You did not specify a valid monitor type!${endColor}" 1317 | echo -e "${red}Your only choice is ping.${endColor}" 1318 | echo '' 1319 | exit 0 1320 | fi 1321 | fi 1322 | 1323 | if [[ ${createType} == 'http' ]]; then 1324 | newMonitorConfigFile="${newHttpMonitorConfigFile}" 1325 | elif [[ ${createType} == 'ping' ]]; then 1326 | newMonitorConfigFile="${newPingMonitorConfigFile}" 1327 | elif [[ ${createType} == 'port' ]]; then 1328 | newMonitorConfigFile="${newPortMonitorConfigFile}" 1329 | elif [[ ${createType} == 'keyword' ]]; then 1330 | newMonitorConfigFile="${newKeywordMonitorConfigFile}" 1331 | fi 1332 | 1333 | sed -i "s|\"api_key\": \"[^']*\"|\"api_key\": \"${apiKey}\"|" "${newMonitorConfigFile}" 1334 | 1335 | if [[ ${providerName} == 'uptimerobot' ]]; then 1336 | if [[ ${jq} == 'true' ]]; then 1337 | curl -s -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" "${apiUrl}"newMonitor -d @"${newMonitorConfigFile}" --header "Content-Type: application/json" | jq 2> /dev/null || fatal 1338 | elif [[ ${jq} == 'false' ]]; then 1339 | curl --fail -s -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" "${apiUrl}"newMonitor -d @"${newMonitorConfigFile}" --header "Content-Type: application/json" || fatal 1340 | fi 1341 | elif [[ ${providerName} == 'statuscake' ]]; then 1342 | if [[ ${jq} == 'true' ]]; then 1343 | curl -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "$(cat ${newMonitorConfigFile})" --header "Content-Type: application/json" -X PUT "${apiUrl}Tests/Update" | jq 2> /dev/null || fatal 1344 | elif [[ ${jq} == 'false' ]]; then 1345 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "$(cat ${newMonitorConfigFile})" --header "Content-Type: application/json" -X PUT "${apiUrl}Tests/Update" || fatal 1346 | fi 1347 | elif [[ ${providerName} == 'healthchecks' ]]; then 1348 | if [[ ${jq} == 'true' ]]; then 1349 | curl -s -X POST "${apiUrl}"checks/ -d "$(cat ${newMonitorConfigFile})" | jq 2> /dev/null || fatal 1350 | elif [[ ${jq} == 'false' ]]; then 1351 | curl --fail -s -X POST "${apiUrl}"checks/ -d "$(cat ${newMonitorConfigFile})" || fatal 1352 | fi 1353 | fi 1354 | 1355 | echo '' 1356 | } 1357 | 1358 | # Function to display account statistics. 1359 | get_stats() { 1360 | echo 'Here are the basic statistics for your UptimeRobot account:' 1361 | echo '' 1362 | 1363 | if [[ ${jq} == 'true' ]]; then 1364 | curl -s -X POST "${apiUrl}"getAccountDetails -d "api_key=${apiKey}" -d "format=json" | jq 2> /dev/null || fatal 1365 | elif [[ ${jq} == 'false' ]]; then 1366 | curl --fail -s -X POST "${apiUrl}"getAccountDetails -d "api_key=${apiKey}" -d "format=json" || fatal 1367 | fi 1368 | 1369 | echo '' 1370 | } 1371 | 1372 | # Function to display all stats for single specified monitor. 1373 | get_info() { 1374 | echo "${infoType}" | tr , '\n' | tr -d '"' > "${specifiedMonitorsFile}" 1375 | check_bad_monitors 1376 | convert_friendly_monitors 1377 | monitor=$(sed 's/\x1B\[[0-9;]*[JKmsu]//g' "${convertedMonitorsFile}") 1378 | 1379 | if [[ ${providerName} == 'uptimerobot' ]]; then 1380 | if [[ ${jq} == 'true' ]]; then 1381 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"getMonitors -d "api_key=${apiKey}" -d "monitors=${monitor}" -d "format=json" | jq 2> /dev/null || fatal 1382 | elif [[ ${jq} == 'false' ]]; then 1383 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"getMonitors -d "api_key=${apiKey}" -d "monitors=${monitor}" -d "format=json" || fatal 1384 | fi 1385 | elif [[ ${providerName} == 'statuscake' ]]; then 1386 | if [[ ${jq} == 'true' ]]; then 1387 | curl -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -X GET "${apiUrl}Tests/Details/?TestID=${monitor}" | jq 2> /dev/null || fatal 1388 | elif [[ ${jq} == 'false' ]]; then 1389 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -X GET "${apiUrl}Tests/Details/?TestID=${monitor}" || fatal 1390 | fi 1391 | elif [[ ${providerName} == 'healthchecks' ]]; then 1392 | if [[ ${jq} == 'true' ]]; then 1393 | curl -s "${apiUrl}"checks/ -X GET -H "X-Api-Key: ${apiKey}" | jq --arg monitor "${monitor}" '.checks[] | select(.ping_url | contains($monitor))' 2> /dev/null || fatal 1394 | elif [[ ${jq} == 'false' ]]; then 1395 | curl --fail -s "${apiUrl}checks/${monitor}" -X POST -H "X-Api-Key: ${apiKey}" || fatal 1396 | fi 1397 | fi 1398 | 1399 | echo '' 1400 | } 1401 | 1402 | # Function to display all alert contacts. 1403 | get_alert_contacts() { 1404 | if [[ ${providerName} == 'uptimerobot' ]]; then 1405 | echo "The following alert contacts have been found for your ${providerName^} account:" 1406 | echo '' 1407 | 1408 | if [[ ${jq} == 'true' ]]; then 1409 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"getAlertContacts -d "api_key=${apiKey}" -d "format=json" | jq 2> /dev/null || fatal 1410 | elif [[ ${jq} == 'false' ]]; then 1411 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"getAlertContacts -d "api_key=${apiKey}" -d "format=json" || fatal 1412 | fi 1413 | elif [[ ${providerName} == 'statuscake' ]]; then 1414 | echo "The following alert contacts have been found for your ${providerName^} account:" 1415 | echo '' 1416 | 1417 | if [[ ${jq} == 'true' ]]; then 1418 | curl -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -X GET "${apiUrl}ContactGroups" | jq 2> /dev/null || fatal 1419 | elif [[ ${jq} == 'false' ]]; then 1420 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -X GET "${apiUrl}ContactGroups" || fatal 1421 | fi 1422 | elif [[ ${providerName} == 'healthchecks' ]]; then 1423 | if [[ ${jq} == 'true' ]]; then 1424 | curl -s -X GET "${apiUrl}"channels/ -H "X-Api-Key: ${apiKey}" | jq 2> /dev/null || fatal 1425 | elif [[ ${jq} == 'false' ]]; then 1426 | curl --fail -s -X GET "${apiUrl}"channels/ -H "X-Api-Key: ${apiKey}" || fatal 1427 | fi 1428 | fi 1429 | 1430 | echo '' 1431 | } 1432 | 1433 | # Function to display reset monitors prompt. 1434 | reset_prompt() { 1435 | echo '' 1436 | echo -e "${red}***WARNING*** This will reset ALL data for the specified monitors!!!${endColor}" 1437 | echo -e "Are you sure you wish to continue? (${grn}[Y]${endColor}es or ${red}[N]${endColor}o): " 1438 | read -r resetPrompt 1439 | echo '' 1440 | 1441 | if ! [[ ${resetPrompt} =~ ^(Yes|yes|Y|y|No|no|N|n)$ ]]; then 1442 | echo -e "${red}Please specify yes, y, no, or n.${endColor}" 1443 | elif [[ ${resetPrompt} =~ ^(No|no|N|n)$ ]]; then 1444 | exit 0 1445 | elif [[ ${resetPrompt} =~ ^(Yes|yes|Y|y)$ ]]; then 1446 | : 1447 | fi 1448 | } 1449 | 1450 | # Function to reset all monitors. 1451 | reset_all_monitors() { 1452 | reset_prompt 1453 | 1454 | while IFS= read -r monitor; do 1455 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1456 | echo "Resetting ${friendlyName}:" 1457 | 1458 | if [[ ${jq} == 'true' ]]; then 1459 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"resetMonitor -d "api_key=${apiKey}" -d "id=${monitor}" | jq 2> /dev/null || fatal 1460 | elif [[ ${jq} == 'false' ]]; then 1461 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"resetMonitor -d "api_key=${apiKey}" -d "id=${monitor}" || fatal 1462 | fi 1463 | 1464 | echo '' 1465 | 1466 | done < <(cat "${monitorsFile}") 1467 | } 1468 | 1469 | # Function to reset specified monitors. 1470 | reset_specified_monitors() { 1471 | echo "${resetType}" | tr , '\n' | tr -d '"' > "${specifiedMonitorsFile}" 1472 | check_bad_monitors 1473 | 1474 | if [[ ${invalidPrompt} == @(No|no|N|n) ]]; then 1475 | exit 0 1476 | else 1477 | convert_friendly_monitors 1478 | fi 1479 | 1480 | reset_prompt 1481 | 1482 | while IFS= read -r monitor; do 1483 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1484 | echo "Resetting ${friendlyName}:" 1485 | 1486 | if [[ ${jq} == 'true' ]]; then 1487 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"resetMonitor -d "api_key=${apiKey}" -d "id=${monitor}" | jq 2> /dev/null || fatal 1488 | elif [[ ${jq} == 'false' ]]; then 1489 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"resetMonitor -d "api_key=${apiKey}" -d "id=${monitor}" || fatal 1490 | fi 1491 | echo '' 1492 | 1493 | done < <(sed 's/\x1B\[[0-9;]*[JKmsu]//g' "${convertedMonitorsFile}") 1494 | } 1495 | 1496 | # Function to display delete monitors prompt. 1497 | delete_prompt() { 1498 | echo '' 1499 | 1500 | if [[ ${deleteType} == 'all' ]]; then 1501 | echo -e "${red}***WARNING*** This will delete ALL monitors in your account!!!${endColor}" 1502 | elif [[ ${deleteType} != 'all' ]]; then 1503 | echo -e "${red}***WARNING*** This will delete the specified monitor from your account!!!${endColor}" 1504 | fi 1505 | 1506 | echo -e "Are you sure you wish to continue? (${grn}[Y]${endColor}es or ${red}[N]${endColor}o): " 1507 | read -r deletePrompt 1508 | echo '' 1509 | 1510 | if ! [[ ${deletePrompt} =~ ^(Yes|yes|Y|y|No|no|N|n)$ ]]; then 1511 | echo -e "${red}Please specify yes, y, no, or n.${endColor}" 1512 | elif [[ ${deletePrompt} =~ ^(No|no|N|n)$ ]]; then 1513 | exit 0 1514 | elif [[ ${deletePrompt} =~ ^(Yes|yes|Y|y)$ ]]; then 1515 | : 1516 | fi 1517 | } 1518 | 1519 | # Function to delete all monitors. 1520 | delete_all_monitors() { 1521 | delete_prompt 1522 | 1523 | while IFS= read -r monitor; do 1524 | if [[ ${providerName} == 'uptimerobot' ]]; then 1525 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1526 | echo "Deleting ${friendlyName}:" 1527 | 1528 | if [[ ${jq} == 'true' ]]; then 1529 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"deleteMonitor -d "api_key=${apiKey}" -d "id=${monitor}" | jq 2> /dev/null || fatal 1530 | elif [[ ${jq} == 'false' ]]; then 1531 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"deleteMonitor -d "api_key=${apiKey}" -d "id=${monitor}" || fatal 1532 | fi 1533 | elif [[ ${providerName} == 'statuscake' ]]; then 1534 | friendlyName=$(jq -r .WebsiteName "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1535 | echo "Deleting ${friendlyName}:" 1536 | 1537 | if [[ ${jq} == 'true' ]]; then 1538 | curl -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -X DELETE "${apiUrl}Tests/Details/?TestID=${monitor}" | jq 2> /dev/null || fatal 1539 | elif [[ ${jq} == 'false' ]]; then 1540 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -X DELETE "${apiUrl}Tests/Details/?TestID=${monitor}" || fatal 1541 | fi 1542 | elif [[ ${providerName} == 'healthchecks' ]]; then 1543 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 1544 | friendlyName=$(jq -r .name "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 1545 | echo "Deleting ${friendlyName}:" 1546 | 1547 | if [[ ${jq} == 'true' ]]; then 1548 | curl -s "${apiUrl}checks/${monitor}" -X DELETE -H "X-Api-Key: ${apiKey}" | jq 2> /dev/null || fatal 1549 | elif [[ ${jq} == 'false' ]]; then 1550 | curl --fail -s "${apiUrl}checks/${monitor}" -X DELETE -H "X-Api-Key: ${apiKey}" || fatal 1551 | fi 1552 | fi 1553 | 1554 | echo '' 1555 | 1556 | done < <(cat "${monitorsFile}") 1557 | } 1558 | 1559 | # Function to delete specified monitors. 1560 | delete_specified_monitors() { 1561 | echo "${deleteType}" | tr , '\n' | tr -d '"' > "${specifiedMonitorsFile}" 1562 | check_bad_monitors 1563 | 1564 | if [[ ${invalidPrompt} == @(No|no|N|n) ]]; then 1565 | exit 0 1566 | else 1567 | convert_friendly_monitors 1568 | fi 1569 | 1570 | delete_prompt 1571 | 1572 | while IFS= read -r monitor; do 1573 | if [[ ${providerName} == 'uptimerobot' ]]; then 1574 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1575 | echo "Deleting ${friendlyName}:" 1576 | 1577 | if [[ ${jq} == 'true' ]]; then 1578 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"deleteMonitor -d "api_key=${apiKey}" -d "id=${monitor}" | jq 2> /dev/null || fatal 1579 | elif [[ ${jq} == 'false' ]]; then 1580 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"deleteMonitor -d "api_key=${apiKey}" -d "id=${monitor}" || fatal 1581 | fi 1582 | elif [[ ${providerName} == 'statuscake' ]]; then 1583 | friendlyName=$(jq -r .WebsiteName "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1584 | echo "Deleting ${friendlyName}:" 1585 | 1586 | if [[ ${jq} == 'true' ]]; then 1587 | curl -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -X DELETE "${apiUrl}Tests/Details/?TestID=${monitor}" | jq 2> /dev/null || fatal 1588 | elif [[ ${jq} == 'false' ]]; then 1589 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -X DELETE "${apiUrl}Tests/Details/?TestID=${monitor}" || fatal 1590 | fi 1591 | elif [[ ${providerName} == 'healthchecks' ]]; then 1592 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 1593 | friendlyName=$(jq -r .name "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 1594 | echo "Deleting ${friendlyName}:" 1595 | 1596 | if [[ ${jq} == 'true' ]]; then 1597 | curl -s "${apiUrl}checks/${monitor}" -X DELETE -H "X-Api-Key: ${apiKey}" | jq 2> /dev/null || fatal 1598 | elif [[ ${jq} == 'false' ]]; then 1599 | curl --fail -s "${apiUrl}checks/${monitor}" -X DELETE -H "X-Api-Key: ${apiKey}" || fatal 1600 | fi 1601 | fi 1602 | 1603 | echo '' 1604 | 1605 | done < <(sed 's/\x1B\[[0-9;]*[JKmsu]//g' "${convertedMonitorsFile}") 1606 | } 1607 | 1608 | # Main function to run all other functions. 1609 | main() { 1610 | cmdline "${args[@]:-}" 1611 | create_dir 1612 | convert_provider_name 1613 | checks 1614 | set_api_key 1615 | 1616 | if [[ ${list} == 'true' ]]; then 1617 | get_data 1618 | get_monitors 1619 | create_monitor_files 1620 | create_friendly_list 1621 | display_all_monitors 1622 | elif [[ ${find} == 'true' ]]; then 1623 | get_data 1624 | get_monitors 1625 | create_monitor_files 1626 | get_paused_monitors 1627 | display_paused_monitors 1628 | 1629 | if [[ -s ${pausedMonitorsFile} ]]; then 1630 | if [[ ${prompt} == 'false' ]]; then 1631 | : 1632 | else 1633 | unpause_prompt 1634 | 1635 | if [[ ${unpausePrompt} =~ ^(Yes|yes|Y|y)$ ]]; then 1636 | if [[ ${providerName} == 'upptime' ]]; then 1637 | echo 'Unpausing the Uptime CI workflow for your Upptime repository...' 1638 | curl --fail -s -X PUT -H "Authorization: bearer ${ghToken}" -H "Accept: application/vnd.github.v3+json" "${apiUrl}repos/${repoOwner}/${upptimeRepo}/actions/workflows/uptime.yml/enable" || fatal 1639 | echo -e "${grn}Success!${endColor}" 1640 | echo '' 1641 | else 1642 | while IFS= read -r monitor; do 1643 | if [[ ${providerName} == 'uptimerobot' ]]; then 1644 | friendlyName=$(jq -r .monitors[].friendly_name "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1645 | echo "Unpausing ${friendlyName}:" 1646 | 1647 | if [[ ${jq} == 'true' ]]; then 1648 | curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"editMonitor -d "api_key=${apiKey}" -d "id=${monitor}" -d "status=1" | jq 2> /dev/null || fatal 1649 | elif [[ ${jq} == 'false' ]]; then 1650 | curl --fail -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Cache-Control: no-cache" "${apiUrl}"editMonitor -d "api_key=${apiKey}" -d "id=${monitor}" -d "status=1" || fatal 1651 | fi 1652 | elif [[ ${providerName} == 'statuscake' ]]; then 1653 | friendlyName=$(jq -r .WebsiteName "${tempDir}${monitor}".txt 2> /dev/null) || fatal 1654 | echo "Unpausing ${friendlyName}:" 1655 | 1656 | if [[ ${jq} == 'true' ]]; then 1657 | curl -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -d "Paused=0" -X PUT "${apiUrl}Tests/Update" | jq 2> /dev/null || fatal 1658 | elif [[ ${jq} == 'false' ]]; then 1659 | curl --fail -s -H "API: ${apiKey}" -H "Username: ${scUsername}" -d "TestID=${monitor}" -d "Paused=0" -X PUT "${apiUrl}Tests/Update" || fatal 1660 | fi 1661 | elif [[ ${providerName} == 'healthchecks' ]]; then 1662 | cp "${tempDir}${monitor}".txt "${tempDir}${monitor}"_short.txt 1663 | friendlyName=$(jq -r .name "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 1664 | pingURL=$(jq -r .ping_url "${tempDir}${monitor}"_short.txt 2> /dev/null) || fatal 1665 | echo "Unpausing ${friendlyName} by sending a ping:" 1666 | pingResponse=$(curl -fsS --retry 3 "${pingURL}") 1667 | 1668 | if [[ ${pingResponse} == 'OK' ]]; then 1669 | echo -e "${grn}Success!${endColor}" 1670 | else 1671 | echo -e "${red}Unable to unpause ${friendlyName}!${endColor}" 1672 | fi 1673 | fi 1674 | 1675 | echo '' 1676 | 1677 | done < <(awk -F: '{print $2}' "${pausedMonitorsFile}" | sed 's/\x1B\[[0-9;]*[JKmsu]//g' | tr -d ' ') 1678 | fi 1679 | elif [[ ${unpausePrompt} =~ ^(No|no|N|n)$ ]]; then 1680 | exit 0 1681 | fi 1682 | fi 1683 | fi 1684 | 1685 | if [[ ${webhook} == 'true' ]]; then 1686 | send_notification 1687 | fi 1688 | elif [[ ${pause} == 'true' ]]; then 1689 | if [[ ${pauseType} == 'all' ]]; then 1690 | get_data 1691 | get_monitors 1692 | create_monitor_files 1693 | pause_all_monitors 1694 | elif [[ ${pauseType} != 'all' ]]; then 1695 | get_data 1696 | get_monitors 1697 | create_monitor_files 1698 | create_friendly_list 1699 | pause_specified_monitors 1700 | fi 1701 | elif [[ ${unpause} == 'true' ]]; then 1702 | if [[ ${unpauseType} == 'all' ]]; then 1703 | get_data 1704 | get_monitors 1705 | create_monitor_files 1706 | unpause_all_monitors 1707 | elif [[ ${unpauseType} != 'all' ]]; then 1708 | get_data 1709 | get_monitors 1710 | create_monitor_files 1711 | create_friendly_list 1712 | unpause_specified_monitors 1713 | fi 1714 | elif [[ ${reset} == 'true' ]]; then 1715 | if [[ ${providerName} == 'statuscake' ]] || [[ ${providerName} == 'healthchecks' ]]; then 1716 | echo -e "${red}Sorry, but that option is not currently possible with you ${providerName^} account!${endColor}" 1717 | exit 0 1718 | fi 1719 | 1720 | if [[ ${resetType} == 'all' ]]; then 1721 | get_data 1722 | get_monitors 1723 | create_monitor_files 1724 | reset_all_monitors 1725 | elif [[ ${resetType} != 'all' ]]; then 1726 | get_data 1727 | get_monitors 1728 | create_monitor_files 1729 | create_friendly_list 1730 | reset_specified_monitors 1731 | fi 1732 | elif [[ ${delete} == 'true' ]]; then 1733 | if [[ ${deleteType} == 'all' ]]; then 1734 | get_data 1735 | get_monitors 1736 | create_monitor_files 1737 | delete_all_monitors 1738 | elif [[ ${deleteType} != 'all' ]]; then 1739 | get_data 1740 | get_monitors 1741 | create_monitor_files 1742 | create_friendly_list 1743 | delete_specified_monitors 1744 | fi 1745 | elif [[ ${stats} == 'true' ]]; then 1746 | if [[ ${providerName} == 'statuscake' ]] || [[ ${providerName} == 'healthchecks' ]]; then 1747 | echo -e "${red}Sorry, but that option is not valid for ${providerName^}.${endColor}" 1748 | exit 0 1749 | else 1750 | get_stats 1751 | fi 1752 | elif [[ ${create} == 'true' ]]; then 1753 | create_monitor 1754 | elif [[ ${alerts} == 'true' ]]; then 1755 | get_alert_contacts 1756 | elif [[ ${info} == 'true' ]]; then 1757 | get_data 1758 | get_monitors 1759 | create_monitor_files 1760 | create_friendly_list 1761 | get_info 1762 | fi 1763 | } 1764 | 1765 | main 1766 | --------------------------------------------------------------------------------