diff --git a/lib/ansible/module_utils/network/skydive/__init__.py b/lib/ansible/module_utils/network/skydive/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/lib/ansible/module_utils/network/skydive/api.py b/lib/ansible/module_utils/network/skydive/api.py
new file mode 100644
index 0000000000..d110a391d0
--- /dev/null
+++ b/lib/ansible/module_utils/network/skydive/api.py
@@ -0,0 +1,163 @@
+# 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) 2019 Red Hat Inc.
+#
+# 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 os
+
+from ansible.module_utils.six import iteritems
+from ansible.module_utils.six import iterkeys
+from ansible.module_utils._text import to_text
+from ansible.module_utils.basic import env_fallback
+
+try:
+ from skydive.rest.client import RESTClient
+ HAS_SKYDIVE_CLIENT = True
+except ImportError:
+ HAS_SKYDIVE_CLIENT = False
+
+# defining skydive constants
+SKYDIVE_GREMLIN_QUERY = 'G.V().Has'
+
+SKYDIVE_PROVIDER_SPEC = {
+ 'endpoint': dict(fallback=(env_fallback, ['SKYDIVE_ENDPOINT'])),
+ 'username': dict(fallback=(env_fallback, ['SKYDIVE_USERNAME'])),
+ 'password': dict(fallback=(env_fallback, ['SKYDIVE_PASSWORD']), no_log=True),
+ 'insecure': dict(type='bool', default=False, fallback=(env_fallback, ['SKYDIVE_INSECURE'])),
+ 'ssl': dict(type='bool', default=False, fallback=(env_fallback, ['SKYDIVE_SSL']))
+}
+
+
+class skydive_restclient(object):
+ ''' Base class for implementing Skydive Rest API '''
+ provider_spec = {'provider': dict(type='dict', options=SKYDIVE_PROVIDER_SPEC)}
+
+ def __init__(self, **kwargs):
+ if not HAS_SKYDIVE_CLIENT:
+ raise Exception('skydive-client is required but does not appear '
+ 'to be installed. It can be installed using the '
+ 'command `pip install skydive-client`')
+
+ if not set(kwargs.keys()).issubset(SKYDIVE_PROVIDER_SPEC.keys()):
+ raise Exception('invalid or unsupported keyword argument for skydive_restclient connection.')
+ for key, value in iteritems(SKYDIVE_PROVIDER_SPEC):
+ if key not in kwargs:
+ # apply default values from SKYDIVE_PROVIDER_SPEC since we cannot just
+ # assume the provider values are coming from AnsibleModule
+ if 'default' in value:
+ kwargs[key] = value['default']
+ # override any values with env variables unless they were
+ # explicitly set
+ env = ('SKYDIVE_%s' % key).upper()
+ if env in os.environ:
+ kwargs[key] = os.environ.get(env)
+ kwargs['scheme'] = "http"
+ if 'ssl' in kwargs:
+ if kwargs['ssl']:
+ kwargs['scheme'] = "https"
+ if 'insecure' not in kwargs:
+ kwargs['insecure'] = False
+ self.restclient_object = RESTClient(kwargs['endpoint'],
+ scheme=kwargs['scheme'],
+ insecure=kwargs['insecure'],
+ username=kwargs['username'],
+ password=kwargs['password'])
+
+
+class skydive_lookup(skydive_restclient):
+ provider_spec = {'provider': dict(type='dict', options=SKYDIVE_PROVIDER_SPEC)}
+
+ def __init__(self, provider):
+ super(skydive_lookup, self).__init__(**provider)
+ self.query_str = ""
+
+ def lookup_query(self, filter_data):
+ query_key = filter_data.keys()[0]
+ self.query_str = filter_data[query_key]
+ nodes = self.restclient_object.lookup_nodes(self.query_str)
+ result = []
+ for each in nodes:
+ result.append(each.__dict__)
+ if len(result) == 0:
+ raise Exception("Cannot find any entry for the input Gremlin query!")
+ return result
+
+
+class skydive_flow_capture(skydive_restclient):
+ ''' Implements Skydive Flow capture modules '''
+ def __init__(self, module):
+ self.module = module
+ provider = module.params['provider']
+
+ super(skydive_flow_capture, self).__init__(**provider)
+
+ def run(self, ib_spec):
+ state = self.module.params['state']
+ if state not in ('present', 'absent'):
+ self.module.fail_json(msg='state must be one of `present`, `absent`, got `%s`' % state)
+
+ result = {'changed': False}
+ obj_filter = dict([(k, self.module.params[k]) for k, v in iteritems(ib_spec) if v.get('ib_req')])
+
+ proposed_object = {}
+ for key in iterkeys(ib_spec):
+ if self.module.params[key] is not None:
+ proposed_object[key] = self.module.params[key]
+
+ if obj_filter['query']:
+ cature_query = obj_filter['query']
+ elif obj_filter['interface_name'] and obj_filter['type']:
+ cature_query = SKYDIVE_GREMLIN_QUERY + "('Name', '{0}', 'Type', '{1}')".format(obj_filter['interface_name'],
+ obj_filter['type'])
+ else:
+ raise self.module.fail_json(msg="Interface name and Type is required if gremlin query is not defined!")
+
+ # to check current object ref for idempotency
+ captured_list_objs = self.restclient_object.capture_list()
+ current_ref_uuid = None
+ for each_capture in captured_list_objs:
+ if cature_query == each_capture.__dict__['query']:
+ current_ref_uuid = each_capture.__dict__['uuid']
+ break
+ if state == 'present':
+ if not current_ref_uuid:
+ try:
+ self.restclient_object.capture_create(cature_query, obj_filter['capture_name'],
+ obj_filter['description'], obj_filter['extra_tcp_metric'],
+ obj_filter['ip_defrag'], obj_filter['reassemble_tcp'],
+ obj_filter['layer_key_mode'])
+ except Exception as e:
+ self.module.fail_json(msg=to_text(e))
+ result['changed'] = True
+ if state == 'absent':
+ if current_ref_uuid:
+ try:
+ self.restclient_object.capture_delete(current_ref_uuid)
+ except Exception as e:
+ self.module.fail_json(msg=to_text(e))
+ result['changed'] = True
+
+ return result
diff --git a/lib/ansible/modules/network/skydive/__init__.py b/lib/ansible/modules/network/skydive/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/lib/ansible/modules/network/skydive/skydive_capture.py b/lib/ansible/modules/network/skydive/skydive_capture.py
new file mode 100644
index 0000000000..2e6a2a2f01
--- /dev/null
+++ b/lib/ansible/modules/network/skydive/skydive_capture.py
@@ -0,0 +1,180 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2019, Ansible by Red Hat, inc
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+ANSIBLE_METADATA = {'metadata_version': '1.1',
+ 'status': ['preview'],
+ 'supported_by': 'network'}
+
+DOCUMENTATION = """
+---
+module: skydive_capture
+version_added: "2.8"
+author:
+ - "Sumit Jaiswal (@sjaiswal)"
+short_description: Module which manages flow capture on interfaces
+description:
+ - This module manages flow capture on interfaces. The Gremlin
+ expression is continuously evaluated which means that it is
+ possible to define a capture on nodes that do not exist yet.
+ - It is useful when you want to start a capture on all OpenvSwitch
+ whatever the number of Skydive agents you will start.
+ - While starting the capture, user can specify the capture name,
+ capture description and capture type optionally.
+requirements:
+ - skydive-client
+extends_documentation_fragment: skydive
+options:
+ query:
+ description:
+ - It's the complete gremlin query which the users can input,
+ I(G.V().Has('Name', 'eth0', 'Type', 'device')), to create
+ the capture. And, if the user directly inputs the gremlin
+ query then user is not required to input any other module
+ parameter as gremlin query takes care of creating the flow
+ capture.
+ required: false
+ interface_name:
+ description:
+ - To define flow capture interface name.
+ required: false
+ type:
+ description:
+ - To define flow capture interface type.
+ required: false
+ capture_name:
+ description:
+ - To define flow capture name.
+ required: false
+ default: ""
+ description:
+ description:
+ - Configures a text string to be associated with the instance
+ of this object.
+ default: ""
+ extra_tcp_metric:
+ description:
+ - To define flow capture ExtraTCPMetric.
+ type: bool
+ default: false
+ ip_defrag:
+ description:
+ - To define flow capture IPDefrag.
+ type: bool
+ default: false
+ reassemble_tcp:
+ description:
+ - To define flow capture ReassembleTCP.
+ type: bool
+ default: false
+ layer_key_mode:
+ description:
+ - To define flow capture Layer KeyMode.
+ type: str
+ default: L2
+ state:
+ description:
+ - State of the flow capture. If value is I(present) flow capture
+ will be created else if it is I(absent) it will be deleted.
+ default: present
+ choices:
+ - present
+ - absent
+"""
+
+EXAMPLES = """
+- name: start a new flow capture directly from gremlin query
+ skydive_capture:
+ query: G.V().Has('Name', 'eth0', 'Type', 'device')
+ state: present
+ provider:
+ endpoint: localhost:8082
+ username: admin
+ password: admin
+
+- name: stop the flow capture directly from gremlin query
+ skydive_capture:
+ query: G.V().Has('Name', 'eth0', 'Type', 'device')
+ state: absent
+ provider:
+ endpoint: localhost:8082
+ username: admin
+ password: admin
+
+- name: start a new flow capture from user's input
+ skydive_capture:
+ interface_name: Node1
+ type: myhost
+ capture_name: test_capture
+ description: test description
+ extra_tcp_metric: true
+ ip_defrag: true
+ reassemble_tcp: true
+ state: present
+ provider:
+ endpoint: localhost:8082
+ username: admin
+ password: admin
+
+- name: stop the flow capture
+ skydive_capture:
+ interface_name: Node1
+ type: myhost
+ capture_name: test_capture
+ description: test description
+ extra_tcp_metric: true
+ ip_defrag: true
+ reassemble_tcp: true
+ state: absent
+ provider:
+ endpoint: localhost:8082
+ username: admin
+ password: admin
+"""
+
+RETURN = """ # """
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.network.skydive.api import skydive_flow_capture
+
+
+def main():
+ ''' Main entry point for module execution
+ '''
+ ib_spec = dict(
+ query=dict(required=False, ib_req=True),
+ interface_name=dict(required=False, ib_req=True),
+ type=dict(required=False, ib_req=True),
+ capture_name=dict(required=False, default='', ib_req=True),
+ description=dict(default='', ib_req=True),
+ extra_tcp_metric=dict(type='bool', required=False, ib_req=True, default=False),
+ ip_defrag=dict(type='bool', required=False, ib_req=True, default=False),
+ reassemble_tcp=dict(type='bool', required=False, ib_req=True, default=False),
+ layer_key_mode=dict(required=False, ib_req=True, default='L2')
+ )
+
+ argument_spec = dict(
+ provider=dict(required=False),
+ state=dict(default='present', choices=['present', 'absent'])
+ )
+
+ argument_spec.update(ib_spec)
+ argument_spec.update(skydive_flow_capture.provider_spec)
+
+ module = AnsibleModule(argument_spec=argument_spec,
+ supports_check_mode=True)
+
+ skydive_obj = skydive_flow_capture(module)
+ result = skydive_obj.run(ib_spec)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/ansible/plugins/doc_fragments/skydive.py b/lib/ansible/plugins/doc_fragments/skydive.py
new file mode 100644
index 0000000000..c4abb7ed21
--- /dev/null
+++ b/lib/ansible/plugins/doc_fragments/skydive.py
@@ -0,0 +1,55 @@
+#
+# (c) 2019, Sumit Jaiswal (@sjaiswal)
+#
+# 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 .
+
+
+class ModuleDocFragment(object):
+
+ # Standard files documentation fragment
+ DOCUMENTATION = """
+options:
+ provider:
+ description:
+ - A dict object containing connection details.
+ suboptions:
+ endpoint:
+ description:
+ - Specifies the hostname/address along with the port as C(localhost:8082)for
+ connecting to the remote instance of SKYDIVE client over the REST API.
+ required: true
+ user:
+ description:
+ - Configures the username to use to authenticate the connection to
+ the remote instance of SKYDIVE client.
+ password:
+ description:
+ - Specifies the password to use to authenticate the connection to
+ the remote instance of SKYDIVE client.
+ insecure:
+ description:
+ - Ignore SSL certification verification.
+ type: bool
+ default: false
+ ssl:
+ description:
+ - Specifies the ssl parameter that decides if the connection type shall be
+ http or https.
+ type: bool
+ default: false
+notes:
+ - "This module must be run locally, which can be achieved by specifying C(connection: local)."
+"""
diff --git a/lib/ansible/plugins/lookup/skydive.py b/lib/ansible/plugins/lookup/skydive.py
new file mode 100644
index 0000000000..e043001715
--- /dev/null
+++ b/lib/ansible/plugins/lookup/skydive.py
@@ -0,0 +1,77 @@
+#
+# Copyright 2018 Red Hat | Ansible
+#
+# 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 .
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+---
+lookup: skydive
+version_added: "2.8"
+short_description: Query Skydive objects
+description:
+ - Uses the Skydive python REST client to return the queried object from
+ Skydive network analyzer.
+requirements:
+ - skydive-client
+extends_documentation_fragment: skydive
+options:
+ filter:
+ description: a dict object that is used to filter the return objects
+"""
+
+EXAMPLES = r"""
+- name: return skydive metdata if present based on Name
+ set_fact:
+ skydive_meta: "{{ lookup('skydive', filter={'query': \"G.V().Has('Name', 'sumit-VirtualBox')\"}) }}"
+
+- name: return all the skydive metdata having parameter Name
+ set_fact:
+ skydive: "{{ lookup('skydive', filter={'query': \"G.V().Has('Name')\"},
+ provider={'endpoint': 'localhost:8082', 'username': 'admin', 'password': 'password'}) }}"
+"""
+
+RETURN = """
+_list:
+ description:
+ - The list of queried object metadata
+ returned: always
+ type: list
+"""
+
+
+from ansible.plugins.lookup import LookupBase
+from ansible.module_utils.network.skydive.api import skydive_lookup
+from ansible.module_utils._text import to_text
+from ansible.errors import AnsibleError
+
+
+class LookupModule(LookupBase):
+
+ def run(self, terms, variables=None, **kwargs):
+
+ provider = kwargs.pop('provider', {})
+ filter_data = kwargs.pop('filter', {})
+ try:
+ skydive_obj = skydive_lookup(provider)
+ result = skydive_obj.lookup_query(filter_data)
+ except Exception as exc:
+ raise AnsibleError(to_text(exc))
+
+ return [result]