def rpc(module, items):

    responses = list()

    for item in items:
        name = item['name']
        xattrs = item['xattrs']
        fetch_config = False

        #args = item.get('args')
        text = item.get('text')

        #name = str(name).replace('_', '-')
        name = str(name)

        #if all((module.check_mode, not name.startswith('get'))):
        #module.fail_json(msg='invalid rpc for running in check_mode')

        if name == 'command' and text.startswith(
                'show configuration') or name == 'get-configuration':
            fetch_config = True

        element = Element(name, xattrs)

        if text:
            element.text = text

        if fetch_config:
            reply = get_configuration(module, format=xattrs['format'])
        else:
            reply = send_request(module, element, ignore_warning=False)

        responses.append(tostring(reply))

    return responses
示例#2
0
def rpc(module, items):

    responses = list()

    for item in items:
        name = item['name']
        xattrs = item['xattrs']
        fetch_config = False
        text = item.get('text')
        name = str(name)
        if name == 'command' and text.startswith(
                'show configuration') or name == 'get-configuration':
            fetch_config = True

        element = Element(name, xattrs)

        if text:
            element.text = text
        if fetch_config:
            reply = get_configuration(module, format=xattrs['format'])
        else:
            reply = send_request(module, element, ignore_warning=False)
        responses.append(tostring(reply))

    return responses
示例#3
0
def main():
    """main entry point for Ansible module
    """
    argument_spec = dict(
        rpc=dict(required=True),
        args=dict(type='dict'),
        output=dict(default='xml', choices=['xml', 'json', 'text']),
    )

    argument_spec.update(junos_argument_spec)

    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=False)

    warnings = list()
    check_args(module, warnings)

    result = {'changed': False, 'warnings': warnings}

    rpc = str(module.params['rpc']).replace('_', '-')

    if all((module.check_mode, not rpc.startswith('get'))):
        module.fail_json(msg='invalid rpc for running in check_mode')

    args = module.params['args'] or {}

    xattrs = {'format': module.params['output']}

    element = Element(module.params['rpc'], xattrs)

    for key, value in iteritems(args):
        key = str(key).replace('_', '-')
        if isinstance(value, list):
            for item in value:
                child = SubElement(element, key)
                if item is not True:
                    child.text = item
        else:
            child = SubElement(element, key)
            if value is not True:
                child.text = value

    reply = send_request(module, element)

    result['xml'] = str(tostring(reply))

    if module.params['output'] == 'text':
        data = reply.find('.//output')
        result['output'] = data.text.strip()
        result['output_lines'] = result['output'].split('\n')

    elif module.params['output'] == 'json':
        result['output'] = module.from_json(reply.text.strip())

    else:
        result['output'] = str(tostring(reply)).split('\n')

    module.exit_json(**result)
示例#4
0
def main():
    """main entry point for Ansible module
    """
    argument_spec = dict(
        rpc=dict(required=True),
        args=dict(type='dict'),
        output=dict(default='xml', choices=['xml', 'json', 'text']),
    )

    argument_spec.update(junos_argument_spec)

    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=False)

    warnings = list()
    check_args(module, warnings)

    result = {'changed': False, 'warnings': warnings}

    rpc = str(module.params['rpc']).replace('_', '-')

    if all((module.check_mode, not rpc.startswith('get'))):
        module.fail_json(msg='invalid rpc for running in check_mode')

    args = module.params['args'] or {}

    xattrs = {'format': module.params['output']}

    element = Element(module.params['rpc'], xattrs)

    for key, value in iteritems(args):
        key = str(key).replace('_', '-')
        if isinstance(value, list):
            for item in value:
                child = SubElement(element, key)
                if item is not True:
                    child.text = item
        else:
            child = SubElement(element, key)
            if value is not True:
                child.text = value

    reply = send_request(module, element)

    result['xml'] = str(tostring(reply))

    if module.params['output'] == 'text':
        data = reply.find('.//output')
        result['output'] = data.text.strip()
        result['output_lines'] = result['output'].split('\n')

    elif module.params['output'] == 'json':
        result['output'] = module.from_json(reply.text.strip())

    else:
        result['output'] = str(tostring(reply)).split('\n')

    module.exit_json(**result)
示例#5
0
文件: junos.py 项目: ernstp/ansible
def get_configuration(module, compare=False, format='xml', rollback='0'):
    if format not in CONFIG_FORMATS:
        module.fail_json(msg='invalid config format specified')
    xattrs = {'format': format}
    if compare:
        _validate_rollback_id(module, rollback)
        xattrs['compare'] = 'rollback'
        xattrs['rollback'] = str(rollback)
    return send_request(module, Element('get-configuration', xattrs))
示例#6
0
def get_configuration(module, compare=False, format='xml', rollback='0'):
    if format not in CONFIG_FORMATS:
        module.fail_json(msg='invalid config format specified')
    xattrs = {'format': format}
    if compare:
        _validate_rollback_id(module, rollback)
        xattrs['compare'] = 'rollback'
        xattrs['rollback'] = str(rollback)
    return send_request(module, Element('get-configuration', xattrs))
示例#7
0
文件: junos.py 项目: ernstp/ansible
def commit_configuration(module, confirm=False, check=False, comment=None, confirm_timeout=None):
    obj = Element('commit-configuration')
    if confirm:
        SubElement(obj, 'confirmed')
    if check:
        SubElement(obj, 'check')
    if comment:
        subele = SubElement(obj, 'log')
        subele.text = str(comment)
    if confirm_timeout:
        subele = SubElement(obj, 'confirm-timeout')
        subele.text = str(confirm_timeout)
    return send_request(module, obj)
示例#8
0
def commit_configuration(module, confirm=False, check=False, comment=None, confirm_timeout=None):
    obj = Element('commit-configuration')
    if confirm:
        SubElement(obj, 'confirmed')
    if check:
        SubElement(obj, 'check')
    if comment:
        subele = SubElement(obj, 'log')
        subele.text = str(comment)
    if confirm_timeout:
        subele = SubElement(obj, 'confirm-timeout')
        subele.text = str(confirm_timeout)
    return send_request(module, obj)
示例#9
0
def load_configuration(module,
                       candidate=None,
                       action='merge',
                       rollback=None,
                       format='xml'):

    if all((candidate is None, rollback is None)):
        module.fail_json(msg='one of candidate or rollback must be specified')

    elif all((candidate is not None, rollback is not None)):
        module.fail_json(msg='candidate and rollback are mutually exclusive')

    if format not in FORMATS:
        module.fail_json(msg='invalid format specified')

    if format == 'json' and action not in JSON_ACTIONS:
        module.fail_json(msg='invalid action for format json')
    elif format in ('text', 'xml') and action not in ACTIONS:
        module.fail_json(msg='invalid action format %s' % format)
    if action == 'set' and not format == 'text':
        module.fail_json(msg='format must be text when action is set')

    if rollback is not None:
        _validate_rollback_id(module, rollback)
        xattrs = {'rollback': str(rollback)}
    else:
        xattrs = {'action': action, 'format': format}

    obj = Element('load-configuration', xattrs)

    if candidate is not None:
        lookup = {
            'xml': 'configuration',
            'text': 'configuration-text',
            'set': 'configuration-set',
            'json': 'configuration-json'
        }

        if action == 'set':
            cfg = SubElement(obj, 'configuration-set')
        else:
            cfg = SubElement(obj, lookup[format])

        if isinstance(candidate, string_types):
            if format == 'xml':
                cfg.append(fromstring(candidate))
            else:
                cfg.text = to_text(candidate, encoding='latin1')
        else:
            cfg.append(candidate)
    return send_request(module, obj)
示例#10
0
def handle_purge(module, want):
    want_users = [item['name'] for item in want]
    element = Element('system')
    login = SubElement(element, 'login')

    reply = send_request(module, Element('get-configuration'), ignore_warning=False)
    users = reply.xpath('configuration/system/login/user/name')
    if users:
        for item in users:
            name = item.text
            if name not in want_users and name != 'root':
                user = SubElement(login, 'user', {'operation': 'delete'})
                SubElement(user, 'name').text = name
    if element.xpath('/system/login/user/name'):
        return element
示例#11
0
def commit_configuration(module,
                         confirm=False,
                         check=False,
                         comment=None,
                         confirm_timeout=None):
    obj = new_ele('commit-configuration')
    if confirm:
        sub_ele(obj, 'confirmed')
    if check:
        sub_ele(obj, 'check')
    if comment:
        children(obj, ('log', str(comment)))
    if confirm_timeout:
        children(obj, ('confirm-timeout', int(confirm_timeout)))
    return send_request(module, obj)
示例#12
0
def rpc(module, items):

    responses = list()

    for item in items:
        name = item['name']
        xattrs = item['xattrs']

        args = item.get('args')
        text = item.get('text')

        name = str(name).replace('_', '-')

        if all((module.check_mode, not name.startswith('get'))):
            module.fail_json(msg='invalid rpc for running in check_mode')

        element = Element(name, xattrs)

        if text:
            element.text = text

        elif args:
            for key, value in iteritems(args):
                key = str(key).replace('_', '-')
                if isinstance(value, list):
                    for item in value:
                        child = SubElement(element, key)
                        if item is not True:
                            child.text = item
                else:
                    child = SubElement(element, key)
                    if value is not True:
                        child.text = value

        reply = send_request(module, element)

        if xattrs['format'] == 'text':
            data = reply.find('.//output')
            responses.append(data.text.strip())

        elif xattrs['format'] == 'json':
            responses.append(module.from_json(reply.text.strip()))

        else:
            responses.append(tostring(reply))

    return responses
def handle_purge(module, want):
    want_users = [item['name'] for item in want]
    element = Element('system')
    login = SubElement(element, 'login')

    reply = send_request(module,
                         Element('get-configuration'),
                         ignore_warning=False)
    users = reply.xpath('configuration/system/login/user/name')
    if users:
        for item in users:
            name = item.text
            if name not in want_users and name != 'root':
                user = SubElement(login, 'user', {'operation': 'delete'})
                SubElement(user, 'name').text = name
    if element.xpath('/system/login/user/name'):
        return element
示例#14
0
文件: junos.py 项目: ernstp/ansible
def load_configuration(module, candidate=None, action='merge', rollback=None, format='xml'):

    if all((candidate is None, rollback is None)):
        module.fail_json(msg='one of candidate or rollback must be specified')

    elif all((candidate is not None, rollback is not None)):
        module.fail_json(msg='candidate and rollback are mutually exclusive')

    if format not in FORMATS:
        module.fail_json(msg='invalid format specified')

    if format == 'json' and action not in JSON_ACTIONS:
        module.fail_json(msg='invalid action for format json')
    elif format in ('text', 'xml') and action not in ACTIONS:
        module.fail_json(msg='invalid action format %s' % format)
    if action == 'set' and not format == 'text':
        module.fail_json(msg='format must be text when action is set')

    if rollback is not None:
        _validate_rollback_id(module, rollback)
        xattrs = {'rollback': str(rollback)}
    else:
        xattrs = {'action': action, 'format': format}

    obj = Element('load-configuration', xattrs)

    if candidate is not None:
        lookup = {'xml': 'configuration', 'text': 'configuration-text',
                  'set': 'configuration-set', 'json': 'configuration-json'}

        if action == 'set':
            cfg = SubElement(obj, 'configuration-set')
        else:
            cfg = SubElement(obj, lookup[format])

        if isinstance(candidate, string_types):
            if format == 'xml':
                cfg.append(fromstring(candidate))
            else:
                cfg.text = to_text(candidate, encoding='latin-1')
        else:
            cfg.append(candidate)
    return send_request(module, obj)
示例#15
0
    def populate(self):
        ele = Element('get-interface-information')
        SubElement(ele, 'detail')
        reply = send_request(self.module, ele)

        interfaces = {}

        for item in reply[0]:
            name = self.get_text(item, 'name')
            obj = {
                'oper-status': self.get_text(item, 'oper-status'),
                'admin-status': self.get_text(item, 'admin-status'),
                'speed': self.get_text(item, 'speed'),
                'macaddress': self.get_text(item, 'hardware-physical-address'),
                'mtu': self.get_text(item, 'mtu'),
                'type': self.get_text(item, 'if-type'),
            }

            interfaces[name] = obj

        self.facts['interfaces'] = interfaces
示例#16
0
    def populate(self):
        ele = Element('get-interface-information')
        SubElement(ele, 'detail')
        reply = send_request(self.module, ele)

        interfaces = {}

        for item in reply[0]:
            name = self.get_text(item, 'name')
            obj = {
                'oper-status': self.get_text(item, 'oper-status'),
                'admin-status': self.get_text(item, 'admin-status'),
                'speed': self.get_text(item, 'speed'),
                'macaddress': self.get_text(item, 'hardware-physical-address'),
                'mtu': self.get_text(item, 'mtu'),
                'type': self.get_text(item, 'if-type'),
            }

            interfaces[name] = obj

        self.facts['interfaces'] = interfaces
示例#17
0
文件: junos.py 项目: ernstp/ansible
def unlock_configuration(x):
    return send_request(x, Element('unlock-configuration'))
示例#18
0
def unlock_configuration(x):
    return send_request(x, Element('unlock-configuration'))
示例#19
0
def command(module, command, format='text', rpc_only=False):
    xattrs = {'format': format}
    if rpc_only:
        command += ' | display xml rpc'
        xattrs['format'] = 'text'
    return send_request(module, Element('command', xattrs, text=command))
示例#20
0
 def rpc(self, rpc):
     return send_request(self.module, Element(rpc))
示例#21
0
from ansible.module_utils.junos import check_args as junos_check_args
from ansible.module_utils.netconf import send_request
from ansible.module_utils.six import string_types

USE_PERSISTENT_CONNECTION = True
DEFAULT_COMMENT = 'configured by junos_config'


def check_args(module, warnings):
    junos_check_args(module, warnings)

    if module.params['replace'] is not None:
        module.fail_json(msg='argument replace is deprecated, use update')


zeroize = lambda x: send_request(x,
                                 ElementTree.Element('request-system-zeroize'))
rollback = lambda x: get_diff(x)


def guess_format(config):
    try:
        json.loads(config)
        return 'json'
    except ValueError:
        pass

    try:
        ElementTree.fromstring(config)
        return 'xml'
    except ElementTree.ParseError:
        pass
示例#22
0
def zeroize(ele):
    return send_request(ele, Element('request-system-zeroize'))
示例#23
0
        subele.text = str(comment)
    if confirm_timeout:
        subele = SubElement(obj, 'confirm-timeout')
        subele.text = str(confirm_timeout)
    return send_request(module, obj)


def command(module, command, format='text', rpc_only=False):
    xattrs = {'format': format}
    if rpc_only:
        command += ' | display xml rpc'
        xattrs['format'] = 'text'
    return send_request(module, Element('command', xattrs, text=command))


lock_configuration = lambda x: send_request(x, Element('lock-configuration'))
unlock_configuration = lambda x: send_request(x, Element('unlock-configuration'
                                                         ))


@contextmanager
def locked_config(module):
    try:
        lock_configuration(module)
        yield
    finally:
        unlock_configuration(module)


def get_diff(module):
示例#24
0
def zeroize(ele):
    return send_request(ele, Element('request-system-zeroize'))
示例#25
0
def rpc(module, items):

    responses = list()

    for item in items:
        name = item['name']
        xattrs = item['xattrs']
        fetch_config = False

        args = item.get('args')
        text = item.get('text')

        name = str(name).replace('_', '-')

        if all((module.check_mode, not name.startswith('get'))):
            module.fail_json(msg='invalid rpc for running in check_mode')

        if name == 'command' and text.startswith('show configuration') or name == 'get-configuration':
            fetch_config = True

        element = Element(name, xattrs)

        if text:
            element.text = text

        elif args:
            for key, value in iteritems(args):
                key = str(key).replace('_', '-')
                if isinstance(value, list):
                    for item in value:
                        child = SubElement(element, key)
                        if item is not True:
                            child.text = item
                else:
                    child = SubElement(element, key)
                    if value is not True:
                        child.text = value

        if fetch_config:
            reply = get_configuration(module, format=xattrs['format'])
        else:
            reply = send_request(module, element, ignore_warning=False)

        if xattrs['format'] == 'text':
            if fetch_config:
                data = reply.find('.//configuration-text')
            else:
                data = reply.find('.//output')

            if data is None:
                module.fail_json(msg=tostring(reply))

            responses.append(data.text.strip())

        elif xattrs['format'] == 'json':
            responses.append(module.from_json(reply.text.strip()))

        elif xattrs['format'] == 'set':
            data = reply.find('.//configuration-set')
            if data is None:
                module.fail_json(msg="Display format 'set' is not supported by remote device.")
            responses.append(data.text.strip())

        else:
            responses.append(tostring(reply))

    return responses
def main():
    """ main entry point for module execution
    """
    element_spec = dict(
        name=dict(),
        description=dict(),
        enabled=dict(default=True, type='bool'),
        speed=dict(),
        mtu=dict(type='int'),
        duplex=dict(choices=['full', 'half', 'auto']),
        tx_rate=dict(),
        rx_rate=dict(),
        delay=dict(default=10, type='int'),
        state=dict(default='present', choices=['present', 'absent', 'up', 'down']),
        active=dict(default=True, type='bool')
    )

    aggregate_spec = deepcopy(element_spec)
    aggregate_spec['name'] = dict(required=True)

    # remove default in aggregate spec, to handle common arguments
    remove_default_spec(aggregate_spec)

    argument_spec = dict(
        aggregate=dict(type='list', elements='dict', options=aggregate_spec),
    )

    argument_spec.update(element_spec)
    argument_spec.update(junos_argument_spec)

    required_one_of = [['name', 'aggregate']]
    mutually_exclusive = [['name', 'aggregate']]

    module = AnsibleModule(argument_spec=argument_spec,
                           required_one_of=required_one_of,
                           mutually_exclusive=mutually_exclusive,
                           supports_check_mode=True)

    warnings = list()
    check_args(module, warnings)

    result = {'changed': False}

    if warnings:
        result['warnings'] = warnings

    top = 'interfaces/interface'

    param_to_xpath_map = collections.OrderedDict()
    param_to_xpath_map.update([
        ('name', {'xpath': 'name', 'is_key': True}),
        ('description', 'description'),
        ('speed', 'speed'),
        ('mtu', 'mtu'),
        ('duplex', 'link-mode'),
        ('disable', {'xpath': 'disable', 'tag_only': True})
    ])

    choice_to_value_map = {
        'link-mode': {'full': 'full-duplex', 'half': 'half-duplex', 'auto': 'automatic'}
    }

    params = to_param_list(module)

    requests = list()
    for param in params:
        # if key doesn't exist in the item, get it from module.params
        for key in param:
            if param.get(key) is None:
                param[key] = module.params[key]

        item = param.copy()
        state = item.get('state')
        item['disable'] = True if not item.get('enabled') else False

        if state in ('present', 'up', 'down'):
            item['state'] = 'present'

        validate_param_values(module, param_to_xpath_map, param=item)
        want = map_params_to_obj(module, param_to_xpath_map, param=item)
        requests.append(map_obj_to_ele(module, want, top, value_map=choice_to_value_map, param=item))

    diff = None
    with locked_config(module):
        for req in requests:
            diff = load_config(module, tostring(req), warnings, action='merge')

        # issue commit after last configuration change is done
        commit = not module.check_mode
        if diff:
            if commit:
                commit_configuration(module)
            else:
                discard_changes(module)
            result['changed'] = True

            if module._diff:
                result['diff'] = {'prepared': diff}

    failed_conditions = []
    for item in params:
        state = item.get('state')
        tx_rate = item.get('tx_rate')
        rx_rate = item.get('rx_rate')

        if state not in ('up', 'down') and tx_rate is None and rx_rate is None:
            continue

        element = Element('get-interface-information')
        intf_name = SubElement(element, 'interface-name')
        intf_name.text = item.get('name')

        if result['changed']:
            sleep(item.get('delay'))

        reply = send_request(module, element, ignore_warning=False)

        if state in ('up', 'down'):
            admin_status = reply.xpath('interface-information/physical-interface/admin-status')
            if not admin_status or not conditional(state, admin_status[0].text.strip()):
                failed_conditions.append('state ' + 'eq(%s)' % state)

        if tx_rate:
            output_bps = reply.xpath('interface-information/physical-interface/traffic-statistics/output-bps')
            if not output_bps or not conditional(tx_rate, output_bps[0].text.strip(), cast=int):
                failed_conditions.append('tx_rate ' + tx_rate)

        if rx_rate:
            input_bps = reply.xpath('interface-information/physical-interface/traffic-statistics/input-bps')
            if not input_bps or not conditional(rx_rate, input_bps[0].text.strip(), cast=int):
                failed_conditions.append('rx_rate ' + rx_rate)

    if failed_conditions:
        msg = 'One or more conditional statements have not be satisfied'
        module.fail_json(msg=msg, failed_conditions=failed_conditions)

    module.exit_json(**result)
示例#27
0
 def rpc(self, rpc):
     return send_request(self.module, Element(rpc))
示例#28
0
文件: junos.py 项目: ernstp/ansible
def command(module, command, format='text', rpc_only=False):
    xattrs = {'format': format}
    if rpc_only:
        command += ' | display xml rpc'
        xattrs['format'] = 'text'
    return send_request(module, Element('command', xattrs, text=command))
示例#29
0
                         check=False,
                         comment=None,
                         confirm_timeout=None):
    obj = new_ele('commit-configuration')
    if confirm:
        sub_ele(obj, 'confirmed')
    if check:
        sub_ele(obj, 'check')
    if comment:
        children(obj, ('log', str(comment)))
    if confirm_timeout:
        children(obj, ('confirm-timeout', int(confirm_timeout)))
    return send_request(module, obj)


lock_configuration = lambda x: send_request(x, new_ele('lock-configuration'))
unlock_configuration = lambda x: send_request(x, new_ele('unlock-configuration'
                                                         ))


@contextmanager
def locked_config(module):
    try:
        lock_configuration(module)
        yield
    finally:
        unlock_configuration(module)


def get_diff(module):
    reply = get_configuration(module, compare=True, format='text')
示例#30
0
def rpc(module, items):

    responses = list()

    for item in items:
        name = item['name']
        xattrs = item['xattrs']
        fetch_config = False

        args = item.get('args')
        text = item.get('text')

        name = str(name).replace('_', '-')

        if all((module.check_mode, not name.startswith('get'))):
            module.fail_json(msg='invalid rpc for running in check_mode')

        if name == 'command' and text.startswith('show configuration') or name == 'get-configuration':
            fetch_config = True

        element = Element(name, xattrs)

        if text:
            element.text = text

        elif args:
            for key, value in iteritems(args):
                key = str(key).replace('_', '-')
                if isinstance(value, list):
                    for item in value:
                        child = SubElement(element, key)
                        if item is not True:
                            child.text = item
                else:
                    child = SubElement(element, key)
                    if value is not True:
                        child.text = value

        if fetch_config:
            reply = get_configuration(module, format=xattrs['format'])
        else:
            reply = send_request(module, element, ignore_warning=False)

        if xattrs['format'] == 'text':
            if fetch_config:
                data = reply.find('.//configuration-text')
            else:
                data = reply.find('.//output')

            if data is None:
                module.fail_json(msg=tostring(reply))

            responses.append(data.text.strip())

        elif xattrs['format'] == 'json':
            responses.append(module.from_json(reply.text.strip()))

        elif xattrs['format'] == 'set':
            data = reply.find('.//configuration-set')
            if data is None:
                module.fail_json(msg="Display format 'set' is not supported by remote device.")
            responses.append(data.text.strip())

        else:
            responses.append(tostring(reply))

    return responses
示例#31
0
def main():
    """ main entry point for module execution
    """
    neighbors_spec = dict(
        host=dict(),
        port=dict()
    )

    element_spec = dict(
        name=dict(),
        description=dict(),
        enabled=dict(default=True, type='bool'),
        speed=dict(),
        mtu=dict(type='int'),
        duplex=dict(choices=['full', 'half', 'auto']),
        tx_rate=dict(),
        rx_rate=dict(),
        neighbors=dict(type='list', elements='dict', options=neighbors_spec),
        delay=dict(default=10, type='int'),
        state=dict(default='present', choices=['present', 'absent', 'up', 'down']),
        active=dict(default=True, type='bool')
    )

    aggregate_spec = deepcopy(element_spec)
    aggregate_spec['name'] = dict(required=True)

    # remove default in aggregate spec, to handle common arguments
    remove_default_spec(aggregate_spec)

    argument_spec = dict(
        aggregate=dict(type='list', elements='dict', options=aggregate_spec),
    )

    argument_spec.update(element_spec)
    argument_spec.update(junos_argument_spec)

    required_one_of = [['name', 'aggregate']]
    mutually_exclusive = [['name', 'aggregate']]

    module = AnsibleModule(argument_spec=argument_spec,
                           required_one_of=required_one_of,
                           mutually_exclusive=mutually_exclusive,
                           supports_check_mode=True)

    warnings = list()
    check_args(module, warnings)

    result = {'changed': False}

    if warnings:
        result['warnings'] = warnings

    top = 'interfaces/interface'

    param_to_xpath_map = collections.OrderedDict()
    param_to_xpath_map.update([
        ('name', {'xpath': 'name', 'is_key': True}),
        ('description', 'description'),
        ('speed', 'speed'),
        ('mtu', 'mtu'),
        ('duplex', 'link-mode'),
        ('disable', {'xpath': 'disable', 'tag_only': True})
    ])

    choice_to_value_map = {
        'link-mode': {'full': 'full-duplex', 'half': 'half-duplex', 'auto': 'automatic'}
    }

    params = to_param_list(module)

    requests = list()
    for param in params:
        # if key doesn't exist in the item, get it from module.params
        for key in param:
            if param.get(key) is None:
                param[key] = module.params[key]

        item = param.copy()
        state = item.get('state')
        item['disable'] = True if not item.get('enabled') else False

        if state in ('present', 'up', 'down'):
            item['state'] = 'present'

        validate_param_values(module, param_to_xpath_map, param=item)
        want = map_params_to_obj(module, param_to_xpath_map, param=item)
        requests.append(map_obj_to_ele(module, want, top, value_map=choice_to_value_map, param=item))

    diff = None
    with locked_config(module):
        for req in requests:
            diff = load_config(module, tostring(req), warnings, action='merge')

        # issue commit after last configuration change is done
        commit = not module.check_mode
        if diff:
            if commit:
                commit_configuration(module)
            else:
                discard_changes(module)
            result['changed'] = True

            if module._diff:
                result['diff'] = {'prepared': diff}

    failed_conditions = []
    neighbors = None
    for item in params:
        state = item.get('state')
        tx_rate = item.get('tx_rate')
        rx_rate = item.get('rx_rate')
        want_neighbors = item.get('neighbors')

        if state not in ('up', 'down') and tx_rate is None and rx_rate is None and want_neighbors is None:
            continue

        element = Element('get-interface-information')
        intf_name = SubElement(element, 'interface-name')
        intf_name.text = item.get('name')

        if result['changed']:
            sleep(item.get('delay'))

        reply = send_request(module, element, ignore_warning=False)

        if state in ('up', 'down'):
            admin_status = reply.xpath('interface-information/physical-interface/admin-status')
            if not admin_status or not conditional(state, admin_status[0].text.strip()):
                failed_conditions.append('state ' + 'eq(%s)' % state)

        if tx_rate:
            output_bps = reply.xpath('interface-information/physical-interface/traffic-statistics/output-bps')
            if not output_bps or not conditional(tx_rate, output_bps[0].text.strip(), cast=int):
                failed_conditions.append('tx_rate ' + tx_rate)

        if rx_rate:
            input_bps = reply.xpath('interface-information/physical-interface/traffic-statistics/input-bps')
            if not input_bps or not conditional(rx_rate, input_bps[0].text.strip(), cast=int):
                failed_conditions.append('rx_rate ' + rx_rate)

        if want_neighbors:
            if neighbors is None:
                element = Element('get-lldp-interface-neighbors')
                intf_name = SubElement(element, 'interface-device')
                intf_name.text = item.get('name')

                reply = send_request(module, element, ignore_warning=False)
                have_host = [item.text for item in reply.xpath('lldp-neighbors-information/lldp-neighbor-information/lldp-remote-system-name')]
                have_port = [item.text for item in reply.xpath('lldp-neighbors-information/lldp-neighbor-information/lldp-remote-port-id')]

            for neighbor in want_neighbors:
                host = neighbor.get('host')
                port = neighbor.get('port')
                if host and host not in have_host:
                    failed_conditions.append('host ' + host)
                if port and port not in have_port:
                    failed_conditions.append('port ' + port)
    if failed_conditions:
        msg = 'One or more conditional statements have not be satisfied'
        module.fail_json(msg=msg, failed_conditions=failed_conditions)

    module.exit_json(**result)