Commit 445c8884 by Curtis

made changes as requested by mpdehaan and added code to remove key and cert pem…

made changes as requested by mpdehaan and added code to remove key and cert pem files on removal of meter
parent 56bfae36
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
......@@ -7,11 +6,6 @@ Ansible module to add boundary meters.
(c) 2013, curtis <curtis@serverascode.com>
* Module sponsored by Cybera - a non-profit organization providing
high-capacity networking and computing solutions to the province
of Alberta.
* Please note much of this converted from the boundary puppet module!
This file is part of Ansible
Ansible is free software: you can redistribute it and/or modify
......@@ -32,6 +26,7 @@ import json
import datetime
import urllib2
import base64
import os
DOCUMENTATION = '''
......@@ -43,7 +38,8 @@ version_added: "1.3"
author: curtis@serverascode.com
requirements:
- Boundary API access
- Boundary client is needed to send data, but not to register meter
- bprobe is required to send data, but not to register a meter
- Python urllib2
options:
name:
description:
......@@ -54,22 +50,15 @@ options:
- Whether to create or remove the client from boundary
required: false
default: true
choices: ["present", "removed"]
aliases: []
choices: ["present", "absent"]
apiid:
description:
- Organizations boundary API ID
required: true
default: null
choices: []
aliases: []
apikey:
description:
- Organizations boundary API KEY
required: true
default: null
choices: []
aliases: []
notes:
- This module does not yet support tags.
......@@ -81,7 +70,7 @@ EXAMPLES='''
boundary_meter: apiid=AAAAAA apikey=BBBBBB state=present name={{ inventory_hostname }}"
- name: Delete meter
boundary_meter: apiid=AAAAAA apikey=BBBBBB state=removed name={{ inventory_hostname }}"
boundary_meter: apiid=AAAAAA apikey=BBBBBB state=absent name={{ inventory_hostname }}"
'''
......@@ -91,55 +80,55 @@ try:
except ImportError:
HAS_URLLIB2 = False
API_HOST = "api.boundary.com"
CONFIG_DIRECTORY = "/etc/bprobe"
api_host = "api.boundary.com"
config_directory = "/etc/bprobe"
# "resource" like thing or APIKEY?
def auth_encode(APIKEY):
auth = base64.standard_b64encode(APIKEY)
# "resource" like thing or apikey?
def auth_encode(apikey):
auth = base64.standard_b64encode(apikey)
auth.replace("\n", "")
return auth
def build_url(NAME, APIID, action, METER_ID=None, CERT_TYPE=None):
def build_url(name, apiid, action, meter_id=None, cert_type=None):
if action == "create":
return 'https://{API_HOST}/{APIID}/meters'.format(API_HOST=API_HOST, APIID=APIID)
return 'https://{api_host}/{apiid}/meters'.format(api_host=api_host, apiid=apiid)
elif action == "search":
return "https://{API_HOST}/{APIID}/meters?name={NAME}".format(API_HOST=API_HOST, APIID=APIID, NAME=NAME)
return "https://{api_host}/{apiid}/meters?name={name}".format(api_host=api_host, apiid=apiid, name=name)
elif action == "certificates":
return "https://{API_HOST}/{APIID}/meters/{METER_ID}/{CERT_TYPE}.pem".format(API_HOST=API_HOST, APIID=APIID, METER_ID=METER_ID, CERT_TYPE=CERT_TYPE)
return "https://{api_host}/{apiid}/meters/{meter_id}/{cert_type}.pem".format(api_host=api_host, apiid=apiid, meter_id=meter_id, cert_type=cert_type)
elif action == "tags":
return "https://{API_HOST}/{APIID}/meters/{METER_ID}/tags".format(API_HOST=API_HOST, APIID=APIID, METER_ID=METER_ID)
return "https://{api_host}/{apiid}/meters/{meter_id}/tags".format(api_host=api_host, apiid=apiid, meter_id=meter_id)
elif action == "delete":
return "https://{API_HOST}/{APIID}/meters/{METER_ID}".format(API_HOST=API_HOST, APIID=APIID, METER_ID=METER_ID)
return "https://{api_host}/{apiid}/meters/{meter_id}".format(api_host=api_host, apiid=apiid, meter_id=meter_id)
def http_request(NAME, APIID, APIKEY, action, METER_ID=None, CERT_TYPE=None):
def http_request(name, apiid, apikey, action, meter_id=None, cert_type=None):
if METER_ID is None:
url = build_url(NAME, APIID, action)
if meter_id is None:
url = build_url(name, apiid, action)
else:
if CERT_TYPE is None:
url = build_url(NAME, APIID, action, METER_ID)
if cert_type is None:
url = build_url(name, apiid, action, meter_id)
else:
url = build_url(NAME, APIID, action, METER_ID, CERT_TYPE)
url = build_url(name, apiid, action, meter_id, cert_type)
auth = auth_encode(APIKEY)
auth = auth_encode(apikey)
request = urllib2.Request(url)
request.add_header("Authorization", "Basic {auth}".format(auth=auth))
request.add_header("Content-Type", "application/json")
return request
def create_meter(module, NAME, APIID, APIKEY):
def create_meter(module, name, apiid, apikey):
meters = search_meter(module, NAME, APIID, APIKEY)
meters = search_meter(module, name, apiid, apikey)
if len(meters) > 0:
# If the meter already exists, do nothing
module.exit_json(status="Meter " + NAME + " already exists",changed=False)
module.exit_json(status="Meter " + name + " already exists",changed=False)
else:
# If it doesn't exist, create it
request = http_request(NAME, APIID, APIKEY, action="create")
request = http_request(name, apiid, apikey, action="create")
# A create request seems to need a json body with the name of the meter in it
body = '{"name":"' + NAME + '"}'
body = '{"name":"' + name + '"}'
request.add_data(body)
try:
......@@ -147,54 +136,58 @@ def create_meter(module, NAME, APIID, APIKEY):
except urllib2.URLError, e:
module.fail_json(msg="Failed to connect to api host to create meter")
# If the config dirctory doesn't exist, create it
if not os.path.exists(CONFIG_DIRECTORY):
os.makedirs(CONFIG_DIRECTORY)
# If the config directory doesn't exist, create it
if not os.path.exists(config_directory):
try:
os.makedirs(config_directory)
except:
module.fail_json("Could not create " + config_directory)
# Download both cert files from the api host
types = ['key', 'cert']
for cert_type in types:
try:
# If we can't open the file it's not there, so we should download it
cert_file = open('/etc/bprobe/{CERT_TYPE}.pem'.format(CERT_TYPE=cert_type))
cert_file = open('/etc/bprobe/{cert_type}.pem'.format(cert_type=cert_type))
except IOError:
# Now download the file...
rc = download_request(module, NAME, APIID, APIKEY, cert_type)
rc = download_request(module, name, apiid, apikey, cert_type)
if rc == False:
module.fail_json("Download request for " + cert_type + ".pem failed")
return 0, "Meter " + NAME + " created"
return 0, "Meter " + name + " created"
def search_meter(module, NAME, APIID, APIKEY):
def search_meter(module, name, apiid, apikey):
request = http_request(NAME, APIID, APIKEY, action="search")
request = http_request(name, apiid, apikey, action="search")
try:
result = urllib2.urlopen(request)
except urllib2.URLError, e:
module.fail_json("Failed to connect to api host for searching")
module.fail_json("Failed to connect to api host to search for meter")
# Return meters
return json.loads(result.read())
def get_meter_id(module, NAME, APIID, APIKEY):
def get_meter_id(module, name, apiid, apikey):
# In order to delete the meter we need its id
meters = search_meter(module, NAME, APIID, APIKEY)
meters = search_meter(module, name, apiid, apikey)
if len(meters) > 0:
return meters[0]['id']
else:
return None
def delete_meter(module, NAME, APIID, APIKEY):
def delete_meter(module, name, apiid, apikey):
meter_id = get_meter_id(module, NAME, APIID, APIKEY)
meter_id = get_meter_id(module, name, apiid, apikey)
if meter_id is None:
return 1, "Meter does not exist, so can't delete it"
else:
action = "delete"
request = http_request(NAME, APIID, APIKEY, action, meter_id)
request = http_request(name, apiid, apikey, action, meter_id)
# See http://stackoverflow.com/questions/4511598/how-to-make-http-delete-method-using-urllib2
# urllib2 only does GET or POST I believe, but here we need delete
request.get_method = lambda: 'DELETE'
......@@ -202,26 +195,35 @@ def delete_meter(module, NAME, APIID, APIKEY):
try:
result = urllib2.urlopen(request)
except urllib2.URLError, e:
module.fail_json("Failed to connect to api host for deleting")
module.fail_json("Failed to connect to api host to delete meter")
# Each new meter gets a new key.pem and ca.pem file, so they should be deleted
types = ['cert', 'key']
for cert_type in types:
try:
cert_file = '/{config_directory}/{cert_type}.pem'.format(config_directory=config_directory,cert_type=cert_type)
os.remove(cert_file)
except OSError, e: ## if failed, report it back to the user ##
module.fail_json("Failed to remove " + cert_type + ".pem file")
return 0, "Meter " + NAME + " deleted"
return 0, "Meter " + name + " deleted"
def download_request(module, NAME, APIID, APIKEY, CERT_TYPE):
def download_request(module, name, apiid, apikey, cert_type):
meter_id = get_meter_id(module, NAME, APIID, APIKEY)
meter_id = get_meter_id(module, name, apiid, apikey)
if meter_id is not None:
action = "certificates"
request = http_request(NAME, APIID, APIKEY, action, meter_id, CERT_TYPE)
request = http_request(name, apiid, apikey, action, meter_id, cert_type)
try:
result = urllib2.urlopen(request)
except urllib2.URLError, e:
module.fail_json("Failed to connect to api host for certificate download")
module.fail_json("Failed to connect to api host to download certificate")
if result:
try:
cert_file_path = '/{CONFIG_DIR}/{CERT_TYPE}.pem'.format(CONFIG_DIR=CONFIG_DIRECTORY,CERT_TYPE=CERT_TYPE)
cert_file_path = '/{config_directory}/{cert_type}.pem'.format(config_directory=config_directory,cert_type=cert_type)
body = result.read()
cert_file = open(cert_file_path, 'w')
cert_file.write(body)
......@@ -241,25 +243,23 @@ def main():
module = AnsibleModule(
argument_spec=dict(
state=dict(required=True, choices=['present', 'removed']),
state=dict(required=True, choices=['present', 'absent']),
name=dict(required=False),
apikey=dict(required=True),
apiid=dict(required=True),
tags=dict(required=False),
)
)
state = module.params['state']
NAME= module.params['name']
APIKEY = module.params['apikey']
APIID = module.params['apiid']
TAGS = module.params['tags']
name= module.params['name']
apikey = module.params['apikey']
apiid = module.params['apiid']
if state == "present":
(rc, result) = create_meter(module, NAME, APIID, APIKEY)
(rc, result) = create_meter(module, name, apiid, apikey)
if state == "removed":
(rc, result) = delete_meter(module, NAME, APIID, APIKEY)
if state == "absent":
(rc, result) = delete_meter(module, name, apiid, apikey)
if rc != 0:
module.fail_json(msg=result)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment