mirror of https://github.com/ansible/ansible.git
Add bigswitch big mon inline chain module (#18631)
* Add bigswitch util * Add big switch big mon inline chain module * Add required to access_token doc * Add controller to doc * Add validate_certs to doc * Add author & metadata * Add BSD license headerpull/19266/merge
parent
44fb104da3
commit
fd3ae0bf80
@ -0,0 +1,88 @@
|
|||||||
|
# This code is part of Ansible, but is an independent component.
|
||||||
|
# This particular file snippet, and this file snippet only, is BSD licensed.
|
||||||
|
# Modules you write using this snippet, which is embedded dynamically by Ansible
|
||||||
|
# still belong to the author of the module, and may assign their own license
|
||||||
|
# to the complete work.
|
||||||
|
#
|
||||||
|
# (c) 2016, Ted Elhourani <ted@bigswitch.com>
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
import json
|
||||||
|
from ansible.module_utils.urls import fetch_url
|
||||||
|
|
||||||
|
class Response(object):
|
||||||
|
|
||||||
|
def __init__(self, resp, info):
|
||||||
|
self.body = None
|
||||||
|
if resp:
|
||||||
|
self.body = resp.read()
|
||||||
|
self.info = info
|
||||||
|
|
||||||
|
@property
|
||||||
|
def json(self):
|
||||||
|
if not self.body:
|
||||||
|
if "body" in self.info:
|
||||||
|
return json.loads(self.info["body"])
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return json.loads(self.body)
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status_code(self):
|
||||||
|
return self.info["status"]
|
||||||
|
|
||||||
|
|
||||||
|
class Rest(object):
|
||||||
|
|
||||||
|
def __init__(self, module, headers, baseurl):
|
||||||
|
self.module = module
|
||||||
|
self.headers = headers
|
||||||
|
self.baseurl = baseurl
|
||||||
|
|
||||||
|
def _url_builder(self, path):
|
||||||
|
if path[0] == '/':
|
||||||
|
path = path[1:]
|
||||||
|
return '%s/%s' % (self.baseurl, path)
|
||||||
|
|
||||||
|
def send(self, method, path, data=None, headers=None):
|
||||||
|
url = self._url_builder(path)
|
||||||
|
data = self.module.jsonify(data)
|
||||||
|
|
||||||
|
resp, info = fetch_url(self.module, url, data=data, headers=self.headers, method=method)
|
||||||
|
|
||||||
|
return Response(resp, info)
|
||||||
|
|
||||||
|
def get(self, path, data=None, headers=None):
|
||||||
|
return self.send('GET', path, data, headers)
|
||||||
|
|
||||||
|
def put(self, path, data=None, headers=None):
|
||||||
|
return self.send('PUT', path, data, headers)
|
||||||
|
|
||||||
|
def post(self, path, data=None, headers=None):
|
||||||
|
return self.send('POST', path, data, headers)
|
||||||
|
|
||||||
|
def patch(self, path, data=None, headers=None):
|
||||||
|
return self.send('PATCH', path, data, headers)
|
||||||
|
|
||||||
|
def delete(self, path, data=None, headers=None):
|
||||||
|
return self.send('DELETE', path, data, headers)
|
@ -0,0 +1,159 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Ansible module to manage Big Monitoring Fabric service chains
|
||||||
|
# (c) 2016, Ted Elhourani <ted@bigswitch.com>,
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'status': ['preview'],
|
||||||
|
'supported_by': 'community',
|
||||||
|
'version': '1.0'}
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: bigmon_chain
|
||||||
|
short_description: Create and remove a bigmon inline service chain.
|
||||||
|
description:
|
||||||
|
- Create and remove a bigmon inline service chain.
|
||||||
|
version_added: "2.3"
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the chain.
|
||||||
|
required: true
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Whether the service chain should be present or absent.
|
||||||
|
default: present
|
||||||
|
choices: ['present', 'absent']
|
||||||
|
controller:
|
||||||
|
description:
|
||||||
|
- The controller IP address.
|
||||||
|
required: true
|
||||||
|
validate_certs:
|
||||||
|
description:
|
||||||
|
- If C(false), SSL certificates will not be validated. This should only be used
|
||||||
|
on personally controlled devices using self-signed certificates.
|
||||||
|
required: false
|
||||||
|
default: true
|
||||||
|
choices: [true, false]
|
||||||
|
access_token:
|
||||||
|
description:
|
||||||
|
- Bigmon access token.
|
||||||
|
required: false
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- An environment variable can be used, BIGSWITCH_ACCESS_TOKEN.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: bigmon inline service chain
|
||||||
|
bigmon_chain:
|
||||||
|
name: MyChain
|
||||||
|
controller: '{{ inventory_hostname }}'
|
||||||
|
state: present
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
{
|
||||||
|
"changed": true,
|
||||||
|
"invocation": {
|
||||||
|
"module_args": {
|
||||||
|
"access_token": null,
|
||||||
|
"controller": "192.168.86.221",
|
||||||
|
"name": "MyChain",
|
||||||
|
"state": "present",
|
||||||
|
"validate_certs": false
|
||||||
|
},
|
||||||
|
"module_name": "bigmon_chain"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
import os
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.bigswitch_utils import Rest, Response
|
||||||
|
from ansible.module_utils.pycompat24 import get_exception
|
||||||
|
|
||||||
|
def chain(module):
|
||||||
|
try:
|
||||||
|
access_token = module.params['access_token'] or os.environ['BIGSWITCH_ACCESS_TOKEN']
|
||||||
|
except KeyError:
|
||||||
|
e = get_exception()
|
||||||
|
module.fail_json(msg='Unable to load %s' % e.message )
|
||||||
|
|
||||||
|
name = module.params['name']
|
||||||
|
state = module.params['state']
|
||||||
|
controller = module.params['controller']
|
||||||
|
|
||||||
|
rest = Rest(module,
|
||||||
|
{'content-type': 'application/json', 'Cookie': 'session_cookie='+access_token},
|
||||||
|
'https://'+controller+':8443/api/v1/data/controller/applications/bigchain')
|
||||||
|
|
||||||
|
if None in (name, state, controller):
|
||||||
|
module.fail_json(msg='parameter `name` is missing')
|
||||||
|
|
||||||
|
response = rest.get('chain?config=true', data={})
|
||||||
|
if response.status_code != 200:
|
||||||
|
module.fail_json(msg="failed to obtain existing chain config: {}".format(response.json['description']))
|
||||||
|
|
||||||
|
config_present = False
|
||||||
|
matching = [chain for chain in response.json if chain['name'] == name]
|
||||||
|
if matching:
|
||||||
|
config_present = True
|
||||||
|
|
||||||
|
if state in ('present') and config_present:
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
|
||||||
|
if state in ('absent') and not config_present:
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
|
||||||
|
if state in ('present'):
|
||||||
|
response = rest.put('chain[name="%s"]' % name, data={'name': name})
|
||||||
|
if response.status_code == 204:
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="error creating chain '{}': {}".format(name, response.json['description']))
|
||||||
|
|
||||||
|
if state in ('absent'):
|
||||||
|
response = rest.delete('chain[name="%s"]' % name, data={})
|
||||||
|
if response.status_code == 204:
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="error deleting chain '{}': {}".format(name, response.json['description']))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
name=dict(type='str', required=True),
|
||||||
|
controller=dict(type='str', required=True),
|
||||||
|
state=dict(choices=['present', 'absent'], default='present'),
|
||||||
|
validate_certs=dict(type='bool', default='False'),
|
||||||
|
access_token=dict(aliases=['BIGSWITCH_ACCESS_TOKEN'], no_log=True)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
chain(module)
|
||||||
|
except Exception:
|
||||||
|
e = get_exception()
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue