From 772f8f4854c634191db1b0c9348748b023ae4390 Mon Sep 17 00:00:00 2001
From: Ted <theodore.elhourani@gmail.com>
Date: Sun, 29 Jan 2017 07:31:37 -0800
Subject: [PATCH] Add bigmon policy module (#20584)

* Cleanup fork

* Add bigmon_policy module

* Remove docker files from commit, fix formatting, add CHANGELOG.md entry

* Put change in CHANGELOG.md in alph order and add the alias to access_token doc

* Fix access_token type, drop the alias, and fix doc

* Capitalize letter, delete redundant notes, make validates_certs True by default

* Add validate_certs to example

* Try fixing trailing space

* Try adding a trailing space

* Try removing trailing space at end of file

* Add newline at end of file and fix trailing space
---
 CHANGELOG.md                                  |   2 +
 .../network/bigswitch/bigmon_policy.py        | 213 ++++++++++++++++++
 2 files changed, 215 insertions(+)
 create mode 100755 lib/ansible/modules/network/bigswitch/bigmon_policy.py

diff --git a/CHANGELOG.md b/CHANGELOG.md
index fd896bf4450..5bae32e95a4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -47,6 +47,8 @@ Ansible Changes By Release
   * aws_kms
   * ecs_ecr
   * ec2_vpc_vgw_facts
+- bigswitch:
+  * bigmon_policy
 - cloudscale_server
 - cloudstack
   * cs_host
diff --git a/lib/ansible/modules/network/bigswitch/bigmon_policy.py b/lib/ansible/modules/network/bigswitch/bigmon_policy.py
new file mode 100755
index 00000000000..15fad032c15
--- /dev/null
+++ b/lib/ansible/modules/network/bigswitch/bigmon_policy.py
@@ -0,0 +1,213 @@
+#!/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_policy
+short_description: Create and remove a bigmon out-of-band policy.
+description:
+    - Create and remove a bigmon out-of-band policy.
+version_added: "2.3"
+options:
+  name:
+    description:
+     - The name of the policy.
+    required: true
+  policy_description:
+    description:
+     - Description of policy.
+  action:
+    description:
+     - Forward matching packets to delivery interfaces, Drop is for measure rate of matching packets,
+       but do not forward to delivery interfaces, capture packets and write to a PCAP file, or enable NetFlow generation.
+    default: forward
+    choices: ['forward', 'drop', 'flow-gen']
+  priority:
+    description:
+     - A priority associated with this policy. The higher priority policy takes precedence over a lower priority.
+    default: 100
+  duration:
+    description:
+     - Run policy for duration duration or until delivery_packet_count packets are delivered, whichever comes first.
+    default: 0
+  start_time:
+    description:
+     - Date the policy becomes active
+    default: ansible_date_time.iso8601
+  delivery_packet_count:
+    description:
+     - Run policy until delivery_packet_count packets are delivered.
+    default: 0
+  state:
+    description:
+     - Whether the policy should be present or absent.
+    default: present
+    choices: ['present', 'absent']
+  controller:
+    description:
+     - The controller 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. If this isn't set the the environment variable C(BIGSWITCH_ACCESS_TOKEN) is used.
+
+'''
+
+EXAMPLES = '''
+- name: policy to aggregate filter and deliver data center (DC) 1 traffic
+      bigmon_policy:
+        name: policy1
+        policy_description: DC 1 traffic policy
+        action: drop
+        controller: '{{ inventory_hostname }}'
+        state: present
+        validate_certs: false
+'''
+
+RETURN = '''
+{
+    "changed": false,
+    "invocation": {
+        "module_args": {
+            "access_token": null,
+            "action": "drop",
+            "controller": "192.168.86.221",
+            "delivery_packet_count": 0,
+            "duration": 0,
+            "name": "policy1",
+            "policy_description": "DC 1 traffic policy",
+            "priority": 100,
+            "start_time": "2017-01-13T23:10:41.978584+00:00",
+            "state": "present",
+            "validate_certs": false
+        },
+        "module_name": "bigmon_policy"
+    }
+}
+'''
+
+import os
+import datetime
+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 policy(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']
+    policy_description = module.params['policy_description']
+    action = module.params['action']
+    priority = module.params['priority']
+    duration = module.params['duration']
+    start_time = module.params['start_time']
+    delivery_packet_count = module.params['delivery_packet_count']
+    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/bigtap')
+
+    if name is None:
+        module.fail_json(msg='parameter `name` is missing')
+
+    response = rest.get('policy?config=true', data={})
+    if response.status_code != 200:
+        module.fail_json(msg="failed to obtain existing policy config: {}".format(response.json['description']))
+
+    config_present = False
+
+    matching = [policy for policy in response.json
+                if policy['name'] == name and
+                   policy['duration'] == duration and
+                   policy['delivery-packet-count'] == delivery_packet_count and
+                   policy['policy-description'] == policy_description and
+                   policy['action'] == action and
+                   policy['priority'] == priority]
+
+    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'):
+        data={'name': name, 'action': action, 'policy-description': policy_description,
+              'priority': priority, 'duration': duration, 'start-time': start_time,
+              'delivery-packet-count': delivery_packet_count }
+
+        response = rest.put('policy[name="%s"]' % name, data=data)
+        if response.status_code == 204:
+            module.exit_json(changed=True)
+        else:
+            module.fail_json(msg="error creating policy '{}': {}".format(name, response.json['description']))
+
+    if state in ('absent'):
+        response = rest.delete('policy[name="%s"]' % name, data={})
+        if response.status_code == 204:
+            module.exit_json(changed=True)
+        else:
+            module.fail_json(msg="error deleting policy '{}': {}".format(name, response.json['description']))
+
+def main():
+    module = AnsibleModule(
+        argument_spec=dict(
+            name=dict(type='str', required=True),
+            policy_description=dict(type='str', default=''),
+            action=dict(choices=['forward', 'drop', 'capture', 'flow-gen'], default='forward'),
+            priority=dict(type='int', default=100),
+            duration=dict(type='int', default=0),
+            start_time=dict(type='str', default=datetime.datetime.now().isoformat()+'+00:00'),
+            delivery_packet_count=dict(type='int', default=0),
+            controller=dict(type='str', required=True),
+            state=dict(choices=['present', 'absent'], default='present'),
+            validate_certs=dict(type='bool', default='True'),
+            access_token=dict(type='str', no_log=True)
+        )
+    )
+
+    try:
+        policy(module)
+    except Exception:
+        e = get_exception()
+        module.fail_json(msg=str(e))
+
+if __name__ == '__main__':
+    main()