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 header
This commit is contained in:
parent
44fb104da3
commit
fd3ae0bf80
3 changed files with 247 additions and 0 deletions
88
lib/ansible/module_utils/bigswitch_utils.py
Executable file
88
lib/ansible/module_utils/bigswitch_utils.py
Executable file
|
@ -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
lib/ansible/modules/network/bigswitch/__init__.py
Normal file
0
lib/ansible/modules/network/bigswitch/__init__.py
Normal file
159
lib/ansible/modules/network/bigswitch/bigmon_chain.py
Executable file
159
lib/ansible/modules/network/bigswitch/bigmon_chain.py
Executable file
|
@ -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 a new issue