Embodiment through Python 2 Pingdom Contact Management
Tags: python, embodiment, philosophy
Published: 2020-04-15 17:44:09

# Managing Pingdom Check Contact Info

Hello and good morning to you and your family!

## I Made This A Long Time Ago  <a name="I-Made-This-A-Long-Time-Ago"></a>

This is an overview of some old code and some other comments about things of that nature. 

Throughout this document I refer to this section in apology for not having the better sense to write the code better in the first place. 

## Junk Becoming and Code Overview

The Python code [here](#update_pingdom_contact-py) is about four years old and isn't what I would call "good", or "secure"; however, *it is* what I would call, "junk". Honestly, it's probably better for your health to avoid using the code, but I can't stop you... You're too powerful.

### If it's junk, why keep it?

Well, yeah! Right?! you're totally right! I should just delete it!

Look, I get it, I'm sure this kind of junk seems verrrry static, in the sense that it may appear to be nothing more than inanimate, slivers of a past frame of mind - an incorrect one at that; so moved-on from that it's rarely thought of, if not forgotten entirely. Revived only in context to how it can be learned from, it's thrashed though cycles of revival, wasteful analysis and re-use. How can junk be anything other than static?

### Junk Becoming

I'm sentimental lil' froggy, and I'm imaginative too! I love the idea that the things I hold onto are powerful fibres of embodiment - past, current and future;  slivers - cleaned and combed, becoming the yarn through which my cognition is weaved into a body; my body, which is sewn in thread of the same yarn. This is not static junk, it's just as becoming as I am! _It's part of me_, yet it's distinct from me - becoming in its own right; as the Python junk code and myself are compositional wholes. That is, I am a whole, of which - in part, is comprised of this junk; and this junk, is also a whole, which - in part, is comprised of me. 

Are the junk and myself compositional to something else? in turn compositionally whole? Absolutely! or, probably, at least. `¯\_(ツ)_/¯`

#### Okay, buddy...

Maybe it's cheezy2u but ^that's^ really how I feeL!! 

Also, ummmmm I initially made this gist public and updated the README because I would repeatedly come across this code, as it was stored in a secret gist, named README.md. This was more than enough to entice me to open it, **every. single. time.** and either feel nostalgic about
how much fun I had writing this small automation, or anxious at how many
problems there were with it.

Eventually, I decided to update the gist so that I'll always know what it is, just by looking at the name.

Eventuallyier, I decided to update the gist so that this README appeared above the code and I figured while I'm at it, why not share a little about myself?

### So what does the code does?

Well, this here code was built to automate the rotation of a Pingdom alert's contact. The code is a Python 2 script, which executes the following:

1. Reads a configuration file for a list of Pingdom alert & contact information
1. Retrieving the first contact in the list
1. Updates the Pingdom alert with the retrieved contact information
1. Moves the retrieved contact to the end of the list

### Why does it do what it does?

The script was created to be run periodically, with the goal of implementing the concept of an on-call roster.

Alternatively, the script can be used in an ad-hoc fashion to simply replace a Pingdom alert's contact with another contact.

## Configuration

Let's talk about how this thing is configured, or was it _how to configure this thing_? I can't remember :0

### config.yaml <a name="config-yaml"></a>

```yaml
auth:
  account-email: ’someone@email.com'
  app-key: ‘1234567890'
  credentials: '01234567890123456789012345678901234567890123456789012345'
check_id: '1234567'
contacts:
  - id: '123456'
    name: 'Ikey Battistonm'
  - id: '123457'
    name: 'Mikey Battiston'
  - id: '123458'
    name: 'Bikey Mattiston'
```

### This Script Modifies Your Configuration File

Whether you use a different configuration path or use the default location for your configuration file, this script will modify the file.

After the script updates the contact information for a Pingdom Check,
it remove the contact from the sequence of mappings in the configuration file and re-add it to the end of the sequence.

[I'm so sorry](#I-Made-This-A-Long-Time-Ago)

### Using your own config

You may pass in your own configuration file with the `-c` option but you don't need to, as by default, the script will try to read ./config.yaml for it's configuration.

### Configuration Attributes

This describes the configuration itself and what it represents for
an example of the configuration, see [config.yaml](#config-yaml).

The script expects that the configuration is specified in a Yaml file.
The Yaml file must consist of the following top-level mappings:

-   **auth:** Represents the authentication information used by the script to connect to Pingdom.

    **auth** maps a set of three mappings, which are:
    -   **account-email:** Your Pingdom account's email address
    -   **app-key:** One of your Pingdom account's app-keys
    -   **credentials:** The secret key to the app-key you used in auth.app-key

-   **check_id**: Represents which represents the ID of the Pingdom Check you want to manage the contact information of.

-   **contacts:** Represents the contact information to be used, by the script, to modify the contact information of the Pingdom Check specified by check_id.

    **contacts** maps to a sequence of mappings, each mapping in the sequence maps to:
    -   **id:** A string which represents a contact's ID.
    -   **name:** A string which represents the name of a contact.
        The contact who's name is specified should have an ID which matches the ID which is specified in the same mapping as the contact's name. [Confusing, I'm sorry](#I-Made-This-A-Long-Time-Ago) :)  

## Code

This is what the main junk pile looks like

### update_pingdom_contact.py <a name="update_pingdom_contact-py"></a>

```python
__author__  = 'Mikey B'
__version__ = '0.0.1'
__purpose__ = 'Automating the rotation of contacts for pingdom alerts'
print (__purpose__)

import json
import yaml
import urllib
import urllib2
import argparse

parser = argparse.ArgumentParser(description='')
parser.add_argument('-o', '--config_file', nargs='?', const='config.yaml', default='config.yaml', required=False)

args = parser.parse_args()
config_file = args.config_file

def get_config():
    print "Attempting to open %s for reading" % config_file
    with open("%s" % (config_file), 'r') as config_file_stream:
        config = yaml.load(config_file_stream)

    return config

def modify_contact_in_pingdom_check(options):
    url           = options['url']
    app_key       = options['app-key']
    check_id      = options['check_id']
    contact_id    = options['contact_id']
    credentials   = options['credentials']
    account_email = options['account-email']

    try:
        print "Making request to modify contact in check: %s" % options['check_id']
        opener = urllib2.build_opener(urllib2.HTTPSHandler)

        data = {
            'contactids' : "%s" % contact_id
        }
        data = urllib.urlencode(data)

        headers = {
            'App-Key'       : app_key,
            'Account-Email' : account_email,
            'Authorization' : 'Basic %s' % credentials
        }

        request = urllib2.Request(url, data=data, headers=headers)
        request.get_method = lambda: 'PUT'
        response = opener.open(request)

        return {
            "body" : response.read(),
            "code" : response.getcode()
        }
    except urllib2.HTTPError, e:
         return {
            "body" : e.read(),
            "code" : e.getcode()
            }

def cycle_contacts():
    print "Attempting to open %s for writing" % config_file
    with open("%s" % (config_file), 'r') as config_file_stream:
        config = yaml.load(config_file_stream)

    contact_to_rotate = config['contacts'].pop(0)
    config['contacts'].append(contact_to_rotate)

    with open("%s" % (config_file), 'w') as config_file_stream:
        yaml.dump(config, config_file_stream, default_flow_style=False)

    contact = config['contacts'][0]
    return contact

if __name__ == "__main__":
    print "Getting config from %s" % config_file
    try:
        config = get_config()
        print "Done."
        print ""
    except Exception as e:
        print "Error: Unable to retrieve config from %s" % config_file
        print e.message, e.args
        exit(1)

    print "Getting next contact..."
    try:
        contact = config['contacts'][0]
        print "Done. Next contact is %s, id: %s" % (contact['name'],contact['id'])
        print ""
    except Exception as e:
        print "Error: Unable to retrieve contact"
        print e.message, e.args
        exit(1)

    print "Getting check id..."
    try:
        check_id = config['check_id']
        print "Done. Updating check: %s" % check_id
        print ""
    except Exception as e:
        print "Error: Unable to retrieve check_id"
        print e.message, e.args
        exit(1)

    options = {
      'url'           : "https://api.pingdom.com/api/2.0/checks/%s" % check_id,
      'check_id'      : check_id,
      'contact_id'    : contact['id'],
      'credentials'   : config['auth']['credentials'],
      'app-key'       : config['auth']['app-key'],
      'account-email' : config['auth']['account-email']
    }
    response = modify_contact_in_pingdom_check(options)

    if response['code'] is not 200:
        print "Error: %s" % response;
        exit(1)
    else:
        print "Success: %s" % response;
        print ""

    print "Rotating contacts..."
    try:
        next_contact = cycle_contacts()
        print "Done. Next contact will be  %s, id: %s" % (next_contact['name'],next_contact['id'])
    except Exception as e:
        print "Error: Unable to rotate contacts in %s" % config_file
        print e.message, e.args
        exit(1)

    exit(0)
```

## Usage

If you want to use the script, here's how to do it and what to expect...

#### Put The Top Down 4 Some Ventilation

1.   Touchscreen Navigate to [config.yaml](#config-yaml) and download that
     config!
     
1.   Touchscreen Navigate to
     [update_pingdom_contact.py](#update_pingdom_contact-py) and
     download that script!

Do it now!

#### Chuck In Your Own Config Values

Please, if any part of you still loves me, do as I say...

1.   Open your new [config.yaml](#config-yaml) file in your least fav editor

1.   Overwrite the values for each of the three mappings in the auth mapping

1.   Overwrite the value of the check_id mapping

1.   Overwrite the values for each of the two mappings within each of the three sequence elements in the contacts mapping
     
Okay, one last favour :0 please save your work ;) Thank me later (;

#### But Don't Use Python 3

This script probably won't work with Python 3 (please believe and understand,
[I Made This A Long Time Ago](#I-Made-This-A-Long-Time-Ago))

#### Executing The Script

Simply run `python update_contact_in_pingdom_check.py` in your terminal.

Or, if you're passing in a config file, try:
`python update_contact_in_pingdom_check.py -c /path/to/config.yaml` in your terminal.

#### When The Script Fails

If the update fails, in any way, it will not rotate any contacts it hasn't already rotated. How confusing and annoying!

### Output

While you'll _probably_ observe _some_ differences, like:
- Contact IDs
- Contact Names
- Check ID

You should see something like following text in the output of the Python script

```
Automating the rotation of a contacts for pingdom alerts
Getting config from config.yaml
Attempting to open config.yaml for reading
Done.

Getting next contact...
Done. Next contact is Mike Mudstone , id: 420666

Getting check id...
Done. Updating check: 6966669

Making request to modify contact in check: 6966669
Success: {'body': '{"message":"Modification of check was successful!"}',
'code': 200}

Rotating contacts...
Attempting to open config.yaml for writing
Done. Next contact will be Steven Robinson ASE, editor of First Contact;
Not to be confused with this script, which is merely the editor of...
The first contact... of your config.yaml ;)
Oh yeah, id: 123457
```

## Please Like and Subscribe

Thank you for your time and the grace of your loving energy

### A Word From My Sponsors

> May your neighbours respect you,
> Trouble neglect you,
> Angels protect you,
> And heaven accept you.

  _- Drake_
  
# GoodBye

_Love From_
_Mikey B_