#!/usr/bin/env python3 import requests import json import yaml import sys import argparse import tempfile import os import hashlib from subprocess import call config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "config.yml") # Read configuration with open(config, "r") as ymlfile: cfg = yaml.load(ymlfile, Loader=yaml.FullLoader) # Functions def call_api(method, url, object_data=None): headers = {"Content-Type": "application/json", "Accept": "application/json"} auth_basic = requests.auth.HTTPBasicAuth(cfg["username"], cfg["password"]) response = requests.request( method, url, json=object_data, headers=headers, params=cfg["params"], auth=auth_basic, ) 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(":", 1)[0].strip(), "value": line.split(":", 1)[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().encode("utf-8")).hexdigest() call([EDITOR, tmp_name]) hash2 = hashlib.md5(open(tmp_name).read().encode("utf-8")).hexdigest() if hash1 != hash2: update(parser.parse_args(["update", args.type, args.key, tmp_name])) else: print("Object unchanged, not updating") os.unlink(tmp_name) return if __name__ == "__main__": # Arguments parsing # USAGE : ./ripe-api.py delete <TYPE> <KEY> # ./ripe-api.py create <TYPE> <FILE> # ./ripe-api.py update <TYPE> <KEY> <FILE> # ./ripe-api.py get <TYPE> <KEY> <FILE> # ./ripe-api.py edit <TYPE> <KEY> parser = argparse.ArgumentParser(description="RIPE API client") subparsers = parser.add_subparsers( help="Action to perform", dest="action", required=True ) parser_get = subparsers.add_parser("get", help="Get 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", nargs="?", default="-" ) 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", nargs="?", default="-" ) 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)