Last active
July 8, 2016 11:44
-
-
Save phillipkent/9c0da406ac2af2647450a7ac34200927 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
# This program is configured for Python version 2.6/2.7 | |
# | |
# Copyright (C) Interoute Communications Limited, 2016 | |
# | |
# The config file should have the form: | |
# {"api_secret": "ABCDEFe17Pgc5WMs28Jwm3H4Drn9CZa3y2K1RiFj5x9S8TzQo64Yfk0L7GqXp71AdWe3k9E0NzPw56XpHd8n4", | |
# "api_key": "GHIJKL7H0XeKt25Ygi6ANp89JrWj46Fbo5L0Zfc7PTn1z9D3MwQy28EaBq42Sdk4RJd85SoHc0s6FBw39LyDp", | |
# "api_url": "https://apiserver.example.com/host/c6142d6b-69d8-4114-9721-a627a76f8cce"} | |
# | |
# Example use: | |
# (1) GET request | |
# $ python puppet_api_signer.py -c puppetconfig | |
# (2) POST request | |
# $ python puppet_api_signer.py -c puppetconfig -m POST --postdata '{"networkenable":true, "networkid":"bcd588dd-db0d-47e0-9628-910461050b4d", "cpu":2}' | |
# | |
from __future__ import print_function | |
import base64 | |
import hashlib | |
import hmac | |
import json | |
import sys | |
import urllib | |
import urllib2 | |
import getpass | |
import os | |
import argparse | |
if __name__ == '__main__': | |
# Parse command line arguments | |
parser = argparse.ArgumentParser() | |
parser.add_argument("-c", "--config", default=os.path.join(os.path.expanduser('~'), '.vdcapi'), | |
help="path/name of the config file to be used for the API URL and API keys (default is ~/.vdcapi)") | |
parser.add_argument("-d", "--postdata", type=json.loads, default='{}', help="data for a POST request (you must use single quotes outside, double quotes inside)") | |
parser.add_argument("-e", "--execute", action='store_true', help="execute the API call") | |
parser.add_argument("-m", "--method", choices=['GET','POST'], default='GET', | |
help="specify the request method type: GET (default) or POST") | |
parser.add_argument("-o", "--outfile", default="", help="name of output file to receive the API call response") | |
config_file = parser.parse_args().config | |
args = parser.parse_args().postdata | |
executeCall = parser.parse_args().execute | |
httpMethod = parser.parse_args().method | |
outfile = parser.parse_args().outfile | |
# If config file is found, read its content, | |
# else query user for the API endpoint URL, API key, Secret key | |
if os.path.isfile(config_file): | |
with open(config_file) as fh: | |
data = fh.read() | |
config = json.loads(data) | |
api_url = config['api_url'] | |
apiKey = config['api_key'] | |
secret = config['api_secret'] | |
else: | |
print('API endpoint url (e.g. http://10.220.18.115:8080/client/api):', end='') | |
api_url = raw_input() | |
print('API key:', end='') | |
apiKey = raw_input() | |
secret = getpass.getpass(prompt='API secret key:') | |
args['apiKey'] = apiKey | |
request = zip(args.keys(), args.values()) | |
request.sort(key=lambda x: x[0].lower()) | |
request_data = "&".join(["=".join([r[0], urllib.quote_plus(str(r[1]),safe='*')]) for r in request]) | |
hashStr = "&".join( | |
[ | |
"=".join( | |
[r[0].lower(), | |
str.lower(urllib.quote_plus(str(r[1]),safe='*')).replace( | |
"+", "%20" | |
)] | |
) for r in request | |
] | |
) | |
sig = base64.b64encode( | |
hmac.new( | |
secret, | |
hashStr, | |
hashlib.sha1 | |
).digest()).strip() | |
sig_encoded = urllib.quote_plus(sig) | |
print("Calculated signature (not URL-encoded): %s" % sig) | |
request_data += "&signature=%s" % sig_encoded | |
print("Runnable URL: \n%s" % (api_url + '?' + request_data)) | |
if executeCall: | |
try: | |
if httpMethod == 'GET': | |
connection = urllib2.urlopen(api_url + '?' + request_data) | |
else: # POST request | |
connection = urllib2.urlopen(api_url, request_data) | |
response = connection.read() | |
except urllib2.HTTPError as error: | |
print('HTTP Error: %s' % error.code) | |
description = str(error.info()) | |
description = description.split('\n') | |
description = [line | |
for line | |
in description | |
if line.startswith('X-Description: ')] | |
if len(description) > 0: | |
description = description[0].split(':', 1)[-1].lstrip() | |
else: | |
description = '(No extended error message.)' | |
print(description) | |
sys.exit() | |
if outfile: | |
fhout = open(outfile, 'w') | |
fhout.write("# API CALL:\n# %s\n#" % (api_url + '?' + request_data)) | |
fhout.write("\n%s" % response) | |
fhout.close() | |
else: | |
print("Response:\n %s" % response) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment