From cfcfea5a9dff317c830f0af60894cf17abb83844 Mon Sep 17 00:00:00 2001 From: Benjamin Collet Date: Thu, 1 Jun 2017 15:54:07 +0200 Subject: [PATCH] Initial commit --- .gitignore | 1 + config.yml.dist | 8 +++ ripe-api.py | 158 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 .gitignore create mode 100644 config.yml.dist create mode 100755 ripe-api.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d3ed4c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config.yml diff --git a/config.yml.dist b/config.yml.dist new file mode 100644 index 0000000..ed1c11b --- /dev/null +++ b/config.yml.dist @@ -0,0 +1,8 @@ +#base_url: 'http://sandbox.alt.tf/whois/glanet' +base_url: 'https://rest.db.ripe.net/ripe' +params: + password: + - 'mnt1-password' + - 'mnt2-password' + - 'mnt3-password' + unfiltered: True # Needed to get all attributes diff --git a/ripe-api.py b/ripe-api.py new file mode 100755 index 0000000..0fee543 --- /dev/null +++ b/ripe-api.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +import requests +import json +import yaml +import sys +import argparse +import tempfile +import os +import hashlib +from subprocess import call + + +# Read configuration +with open("config.yml", 'r') as ymlfile: + cfg = yaml.load(ymlfile) + + +# Functions +def call_api(method, url, object_data=None): + headers = { 'Content-Type': 'application/json', + 'Accept': 'application/json' } + response = requests.request(method, url, json=object_data, headers=headers, + params=cfg['params']) + if not response.text: + print "No response received (error %i)" % response.status_code + sys.exit(1) + + json_response=json.loads(response.text) + + if "errormessages" in json_response: + for err in json_response['errormessages']['errormessage']: + if 'args' in err: + print err['text'].replace('\n', ' ').replace('\r', '') \ + % tuple([d['value'] for d in err['args']]) + else: + print err['text'] + + return json_response + + +# Print formatted output from JSON +def print_output(json, object_file): + if "objects" in json: + for attr in json['objects']['object'][0]['attributes']['attribute']: + object_file.write("%-20s %s\n" % (attr['name']+':', + attr['value'])) + if object_file: + object_file.close() + + +def read_input(object_file): + attr = [] + for line in object_file.readlines(): + if not line: continue + attr.append({'name':line.split(':')[0].strip(), + 'value':line.split(':')[1].strip() }) + + object_data = { + "objects": { + "object": [ + { + "attributes": { + "attribute": attr + } + } + ] + } + } + return object_data + + +# Get record +def get(args): + print "Getting %s object %s" % (args.type, args.key) + url = '/'.join((cfg['base_url'],args.type,args.key)) + json_response=call_api("GET", url) + print_output(json_response, args.file) + return + + +# Delete record +def delete(args): + print "Deleting %s object %s" % (args.type, args.key) + url = '/'.join((cfg['base_url'],args.type,args.key)) + json_response=call_api("DELETE", url) + return + + +# Create record +def create(args): + print "Creating %s object" % (args.type) + url = '/'.join((cfg['base_url'],args.type)) + object_data = read_input(args.file) + json_response=call_api("POST", url, object_data) + print_output(json_response, sys.stdout) + return + + +# Update record +def update(args): + print "Updating %s object %s" % (args.type, args.key) + url = '/'.join((cfg['base_url'],args.type,args.key)) + object_data = read_input(args.file) + json_response=call_api("PUT", url, object_data) + print_output(json_response, sys.stdout) + return + + +# Edit record +def edit(args): + tmp_fd, tmp_name = tempfile.mkstemp() + get(parser.parse_args(["get", args.type, args.key, tmp_name])) + EDITOR = os.environ.get('EDITOR','vim') + # Memory inefficient, but who cares? + hash1 = hashlib.md5(open(tmp_name).read()).hexdigest() + call([EDITOR, tmp_name]) + hash2 = hashlib.md5(open(tmp_name).read()).hexdigest() + + if hash1 != hash2: + update(parser.parse_args(["update", args.type, args.key, tmp_name])) + else: + print "Object unchanged, not updating" + return + + +# Arguments parsing +# USAGE : ./ripe-api.py delete +# ./ripe-api.py create +# ./ripe-api.py update +# ./ripe-api.py get +# ./ripe-api.py edit +parser = argparse.ArgumentParser() +subparsers = parser.add_subparsers(help='Action to perform',dest='action') + +parser_get = subparsers.add_parser('get', help='Delete an object') +parser_get.add_argument('type', type=str, help='Object type') +parser_get.add_argument('key', type=str, help='Object identifier') +parser_get.add_argument('file', type=argparse.FileType('w'), help='Output file') + +parser_delete = subparsers.add_parser('delete', help='Delete an object') +parser_delete.add_argument('type', type=str, help='Object type') +parser_delete.add_argument('key', type=str, help='Object identifier') + +parser_post = subparsers.add_parser('create', help='Create an object') +parser_post.add_argument('type', type=str, help='Object type') +parser_post.add_argument('file', type=argparse.FileType('r'), help='Input file') + +parser_put = subparsers.add_parser('update', help='Update an object') +parser_put.add_argument('type', type=str, help='Object type') +parser_put.add_argument('key', type=str, help='Object identifier') +parser_put.add_argument('file', type=argparse.FileType('r'), help='Input file') + +parser_edit = subparsers.add_parser('edit', help='Edit an object') +parser_edit.add_argument('type', type=str, help='Object type') +parser_edit.add_argument('key', type=str, help='Object identifier') + +args = parser.parse_args() +globals()[args.action](args)