PR to start support for Skydive integration with Ansible (#50857)

* skydive modules

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* skydive modules

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* skydive modules

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* skydive modules

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* skydive modules

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* skydive modules

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* skydive modules

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix shippable

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* modifying file name

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix shippable

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* renamed

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* skydive lookup

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* change in str

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* change in str

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix shippable error

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* renamed file

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix shippable error

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* change in str

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix shippable error

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix shippable error

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix review comments

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix review comments

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* deleting file to add to new PR

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix review comments

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* shippable and doc fix

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* placing doc at correct path

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* shippable and doc fix

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* placing doc at correct path

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* updated with review and shippable fix

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* updated with review and shippable fix

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* updated with review and shippable fix

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* updated with review and shippable fix

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fixing review comment

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fixing review comment

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fixing review comment

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fixing review comment

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fixing review comment

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix shippable errors

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix shippable error

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix review comments

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fixing shippable errors

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* fix review comments

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* review comments

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* shippable fix

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* review comment

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>
This commit is contained in:
Sumit Jaiswal 2019-02-19 16:18:40 +05:30 committed by GitHub
parent 57d85031d7
commit 8a2ff1cde6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 475 additions and 0 deletions

View file

@ -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

View file

@ -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()

View file

@ -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 <http://www.gnu.org/licenses/>.
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)."
"""

View file

@ -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 <http://www.gnu.org/licenses/>.
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]