Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR to start support for Skydive integration with Ansible #50857

Merged
merged 45 commits into from Feb 19, 2019
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
dd036be
skydive modules
justjais Jan 14, 2019
606dd7a
skydive modules
justjais Jan 14, 2019
c7b3485
skydive modules
justjais Jan 14, 2019
359b83b
skydive modules
justjais Jan 14, 2019
61b6cc2
skydive modules
justjais Jan 14, 2019
4029d4f
skydive modules
justjais Jan 14, 2019
d7a8e6c
skydive modules
justjais Jan 14, 2019
3d939e0
fix shippable
justjais Jan 14, 2019
422c04a
modifying file name
justjais Jan 14, 2019
d43d245
fix shippable
justjais Jan 14, 2019
ac3ceda
renamed
justjais Jan 14, 2019
42488c1
skydive lookup
justjais Jan 17, 2019
3c8b063
change in str
justjais Jan 18, 2019
b8679f1
change in str
justjais Jan 18, 2019
ea12a45
fix shippable error
justjais Jan 18, 2019
6cbbd53
renamed file
justjais Jan 18, 2019
173d517
fix shippable error
justjais Jan 18, 2019
5fca791
change in str
justjais Jan 18, 2019
450f513
fix shippable error
justjais Jan 18, 2019
fb7c376
fix shippable error
justjais Jan 18, 2019
41705a6
fix review comments
justjais Jan 28, 2019
1269594
fix review comments
justjais Jan 28, 2019
f2a2f17
deleting file to add to new PR
justjais Jan 28, 2019
2ae8b66
fix review comments
justjais Jan 28, 2019
ddcf199
shippable and doc fix
justjais Jan 28, 2019
d076f59
placing doc at correct path
justjais Jan 28, 2019
2c49a73
shippable and doc fix
justjais Jan 28, 2019
e7c8cc0
placing doc at correct path
justjais Jan 28, 2019
125f9da
updated with review and shippable fix
justjais Jan 29, 2019
e4c559f
updated with review and shippable fix
justjais Jan 29, 2019
3a09e61
updated with review and shippable fix
justjais Jan 29, 2019
766f613
updated with review and shippable fix
justjais Jan 29, 2019
bb2ddc7
fixing review comment
justjais Feb 12, 2019
7bc98e2
fixing review comment
justjais Feb 12, 2019
30a7ba6
fixing review comment
justjais Feb 12, 2019
e97cfaf
fixing review comment
justjais Feb 12, 2019
5cced5f
fixing review comment
justjais Feb 12, 2019
8155726
fix shippable errors
justjais Feb 13, 2019
bfc7fd2
fix shippable error
justjais Feb 13, 2019
38f676d
fix review comments
justjais Feb 14, 2019
34bcab1
fixing shippable errors
justjais Feb 14, 2019
7d9ec75
fix review comments
justjais Feb 14, 2019
9c5a0bb
review comments
justjais Feb 15, 2019
38685e2
shippable fix
justjais Feb 15, 2019
eaad57f
review comment
justjais Feb 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Empty file.
163 changes: 163 additions & 0 deletions 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
Empty file.
180 changes: 180 additions & 0 deletions 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()