diff --git a/library/net_infrastructure/arista_interface b/library/net_infrastructure/arista_interface deleted file mode 100644 index 25af801ef6..0000000000 --- a/library/net_infrastructure/arista_interface +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013, Arista Networks -# -# This program 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. -# -# This program 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 this program. If not, see . -# -DOCUMENTATION = ''' ---- -module: arista_interface -version_added: "1.3" -author: Peter Sprygada -short_description: Manage physical Ethernet interfaces -requirements: - - Arista EOS 4.10 - - Netdev extension for EOS -description: - - Manage physical Ethernet interface resources on Arista EOS network devices -options: - interface_id: - description: - - the full name of the interface - required: true - logging: - description: - - enables or disables the syslog facility for this module - required: false - default: false - choices: [ 'true', 'false', 'yes', 'no' ] - admin: - description: - - controls the operational state of the interface - required: false - choices: [ 'up', 'down' ] - description: - description: - - a single line text string describing the interface - required: false - mtu: - description: - - configureds the maximum transmission unit for the interface - required: false - default: 1500 - speed: - description: - - sets the interface speed setting - required: false - default: 'auto' - choices: [ 'auto', '100m', '1g', '10g' ] - duplex: - description: - - sets the interface duplex setting - required: false - default: 'auto' - choices: [ 'auto', 'half', 'full' ] -notes: - - Requires EOS 4.10 or later - - The Netdev extension for EOS must be installed and active in the - available extensions (show extensions from the EOS CLI) - - See http://eos.aristanetworks.com for details -''' -EXAMPLES = ''' -Example playbook entries using the arista_interface module to manage resource -state. Note that interface names must be the full interface name not shortcut -names (ie Ethernet, not Et1) - - tasks: - - name: enable interface Ethernet 1 - action: arista_interface interface_id=Ethernet1 admin=up speed=10g duplex=full logging=true - - - name: set mtu on Ethernet 1 - action: arista_interface interface_id=Ethernet1 mtu=1600 speed=10g duplex=full logging=true - - - name: reset changes to Ethernet 1 - action: arista_interface interface_id=Ethernet1 admin=down mtu=1500 speed=10g duplex=full logging=true -''' -import syslog -import json - -class AristaInterface(object): - """ This is the base class for managing physcial Ethernet interface - resources in EOS network devices. This class acts as a wrapper around - the netdev extension in EOS. You must have the netdev extension - installed in order for this module to work properly. - - The following commands are implemented in this module: - * netdev interface list - * netdev interface show - * netdev interface edit - * netdev interface delete - - This module only allows for the management of physical Ethernet - interfaces. - """ - - attributes = ['interface_id', 'admin', 'description', 'mtu', 'speed', 'duplex'] - - def __init__(self, module): - self.module = module - self.interface_id = module.params['interface_id'] - self.admin = module.params['admin'] - self.description = module.params['description'] - self.mtu = module.params['mtu'] - self.speed = module.params['speed'] - self.duplex = module.params['duplex'] - self.logging = module.params['logging'] - - @property - def changed(self): - """ The changed property provides a boolean response if the currently - loaded resouces has changed from the resource running in EOS. - - Returns True if the object is not in sync - Returns False if the object is in sync. - """ - return len(self.updates()) > 0 - - def log(self, entry): - """ This method is responsible for sending log messages to the local - syslog. - """ - if self.logging: - syslog.openlog('ansible-%s' % os.path.basename(__file__)) - syslog.syslog(syslog.LOG_NOTICE, entry) - - def run_command(self, cmd): - """ Calls the Ansible module run_command method. This method will - directly return the results of the run_command method - """ - self.log(cmd) - return self.module.run_command(cmd.split()) - - def get(self): - """ This method will return a dictionary with the attributes of the - physical ethernet interface resource specified in interface_id. - The physcial ethernet interface resource has the following - structure: - - { - "interface_id": , - "description": , - "admin": [up | down], - "mtu": , - "speed": [auto | 100m | 1g | 10g] - "duplex": [auto | half | full] - } - - If the physical ethernet interface specified by interface_id does - not exist in the system, this method will return None. - """ - cmd = "netdev interface show %s" % self.interface_id - (rc, out, err) = self.run_command(cmd) - obj = json.loads(out) - if obj.get('status') != 200: - return None - return obj['result'] - - def update(self): - """ Updates an existing physical ethernet resource in the current - running configuration. If the physical ethernet resource does - not exist, this method will return an error. - - This method implements the following commands: - * netdev interface edit {interface_id} [attributes] - - Returns an updated physical ethernet interafce resoure if the - update method was successful - """ - attribs = list() - for attrib in self.updates(): - attribs.append("--%s" % attrib) - attribs.append(str(getattr(self, attrib))) - - if attribs: - cmd = "netdev interface edit %s " % self.interface_id - cmd += " ".join(attribs) - - (rc, out, err) = self.run_command(cmd) - resp = json.loads(out) - if resp.get('status') != 200: - rc = int(resp['status']) - err = resp['message'] - out = None - else: - out = resp['result'] - return (rc, out, err) - - return (0, None, "No attributes have been modified") - - def updates(self): - """ This method will check the current phy resource in the running - configuration and return a list of attribute that are not in sync - with the current resource from the running configuration. - """ - obj = self.get() - update = lambda a, z: a != z - - updates = list() - for attrib in self.attributes: - value = getattr(self, attrib) - if update(obj[attrib], value) and value is not None: - updates.append(attrib) - - self.log("updates: %s" % updates) - return updates - - - -def main(): - module = AnsibleModule( - argument_spec = dict( - interface_id=dict(default=None, type='str'), - admin=dict(default=None, choices=['up', 'down'], type='str'), - description=dict(default=None, type='str'), - mtu=dict(default=None, type='int'), - speed=dict(default=None, choices=['auto', '100m', '1g', '10g']), - duplex=dict(default=None, choices=['auto', 'half', 'full']), - logging=dict(default=False, type='bool') - ), - supports_check_mode = True - ) - - obj = AristaInterface(module) - - rc = None - result = dict() - - if module.check_mode: - module.exit_json(changed=obj.changed) - - else: - if obj.changed: - (rc, out, err) = obj.update() - result['results'] = out - if rc is not None and rc != 0: - module.fail_json(msg=err, rc=rc) - - if rc is None: - result['changed'] = False - else: - result['changed'] = True - - module.exit_json(**result) - - -# import module snippets -from ansible.module_utils.basic import * -main() diff --git a/library/net_infrastructure/arista_l2interface b/library/net_infrastructure/arista_l2interface deleted file mode 100644 index 0115ab15dd..0000000000 --- a/library/net_infrastructure/arista_l2interface +++ /dev/null @@ -1,337 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013, Arista Networks -# -# This program 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. -# -# This program 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 this program. If not, see . -# -DOCUMENTATION = ''' ---- -module: arista_l2interface -version_added: "1.2" -author: Peter Sprygada -short_description: Manage layer 2 interfaces -requirements: - - Arista EOS 4.10 - - Netdev extension for EOS -description: - - Manage layer 2 interface resources on Arista EOS network devices -options: - interface_id: - description: - - the full name of the interface - required: true - state: - description: - - describe the desired state of the interface related to the config - required: false - default: 'present' - choices: [ 'present', 'absent' ] - logging: - description: - - enables or disables the syslog facility for this module - required: false - default: false - choices: [ 'true', 'false', 'yes', 'no' ] - vlan_tagging: - description: - - specifies whether or not vlan tagging should be enabled for - this interface - required: false - default: true - choices: [ 'enable', 'disable' ] - tagged_vlans: - description: - - specifies the list of vlans that should be allowed to transit - this interface - required: false - untagged_vlan: - description: - - specifies the vlan that untagged traffic should be placed in for - transit across a vlan tagged link - required: false - default: 'default' -notes: - - Requires EOS 4.10 or later - - The Netdev extension for EOS must be installed and active in the - available extensions (show extensions from the EOS CLI) - - See http://eos.aristanetworks.com for details -''' -EXAMPLES = ''' -Example playbook entries using the arista_l2interface module to manage resource -state. Note that interface names must be the full interface name not shortcut -names (ie Ethernet, not Et1) - - tasks: - - name: create switchport ethernet1 access port - action: arista_l2interface interface_id=Ethernet1 logging=true - - - name: create switchport ethernet2 trunk port - action: arista_l2interface interface_id=Ethernet2 vlan_tagging=enable logging=true - - - name: add vlans to red and blue switchport ethernet2 - action: arista_l2interface interface_id=Ethernet2 tagged_vlans=red,blue logging=true - - - name: set untagged vlan for Ethernet1 - action: arista_l2interface interface_id=Ethernet1 untagged_vlan=red logging=true - - - name: convert access to trunk - action: arista_l2interface interface_id=Ethernet1 vlan_tagging=enable tagged_vlans=red,blue logging=true - - - name: convert trunk to access - action: arista_l2interface interface_id=Ethernet2 vlan_tagging=disable untagged_vlan=blue logging=true - - - name: delete switchport ethernet1 - action: arista_l2interface interface_id=Ethernet1 state=absent logging=true -''' -import syslog -import json - -class AristaL2Interface(object): - """ This is the base class managing layer 2 interfaces (switchport) - resources in Arista EOS network devices. This class provides an - implementation for creating, updating and deleting layer 2 interfaces. - - Note: The netdev extension for EOS must be installed in order of this - module to work properly. - - The following commands are implemented in this module: - * netdev l2interface list - * netdev l2interface show - * netdev l2interface edit - * netdev l2interface delete - - """ - - attributes= ['vlan_tagging', 'tagged_vlans', 'untagged_vlan'] - - def __init__(self, module): - self.module = module - self.interface_id = module.params['interface_id'] - self.state = module.params['state'] - self.vlan_tagging = module.params['vlan_tagging'] - self.tagged_vlans = module.params['tagged_vlans'] - self.untagged_vlan = module.params['untagged_vlan'] - self.logging = module.params['logging'] - - @property - def changed(self): - """ The changed property provides a boolean response if the currently - loaded resouces has changed from the resource running in EOS. - - Returns True if the object is not in sync - Returns False if the object is in sync. - """ - return len(self.updates()) > 0 - - def log(self, entry): - """ This method is responsible for sending log messages to the local - syslog. - """ - if self.logging: - syslog.openlog('ansible-%s' % os.path.basename(__file__)) - syslog.syslog(syslog.LOG_NOTICE, entry) - - def run_command(self, cmd): - """ Calls the Ansible module run_command method. This method will - directly return the results of the run_command method - """ - self.log("Command: %s" % cmd) - return self.module.run_command(cmd.split()) - - - def get(self): - """ This method will return a dictionary with the attributes of the - layer 2 interface resource specified in interface_id. The layer - 2 interface resource has the following structure: - - { - "interface_id": , - "vlan_tagging": [enable* | disable], - "tagged_vlans": , - "untagged_vlan": - } - - If the layer 2 interface specified by interface_id does not - exist in the system, this method will return None. - """ - cmd = "netdev l2interface show %s" % self.interface_id - (rc, out, err) = self.run_command(cmd) - obj = json.loads(out) - if obj.get('status') != 200: - return None - return obj['result'] - - def create(self): - """ Creates a layer 2 interface resource in the current running - configuration. If the layer 2 interface already exists, the - function will return successfully. - - This function implements the following commands: - * netdev l2interface create {interface_id} [attributes] - - Returns the layer 2 interface resource if the create method was - successful - Returns an error message if there as a problem creating the layer - 2 interface - """ - attribs = [] - for attrib in self.attributes: - if getattr(self, attrib): - attribs.append("--%s" % attrib) - attribs.append(getattr(self, attrib)) - - cmd = "netdev l2interface create %s " % self.interface_id - cmd += " ".join(attribs) - - (rc, out, err) = self.run_command(cmd) - resp = json.loads(out) - if resp.get('status') != 201: - rc = int(resp['status']) - err = resp['message'] - out = None - else: - out = resp['result'] - return (rc, out, err) - - def update(self): - """ Updates an existing VLAN resource in the current running - configuration. If the VLAN resource does not exist, this method - will return an error. - - This method implements the following commands: - * netdev l2interface edit {interface_id} [attributes] - - Returns an updated layer 2 interafce resoure if the update method - was successful - """ - attribs = list() - for attrib in self.updates(): - attribs.append("--%s" % attrib) - attribs.append(getattr(self, attrib)) - - cmd = "netdev l2interface edit %s " % self.interface_id - cmd += " ".join(attribs) - - (rc, out, err) = self.run_command(cmd) - resp = json.loads(out) - if resp.get('status') != 200: - rc = int(resp['status']) - err = resp['message'] - out = None - else: - out = resp['result'] - return (rc, out, err) - - return (0, None, "No attributes have been modified") - - def delete(self): - """ Deletes an existing layer 2 interface resource from the current - running configuration. A nonexistent layer 2 interface will - return successful for this operation. - - This method implements the following commands: - * netdev l2interface delete {interface_id} - - Returns nothing if the delete was successful - Returns error message if there was a problem deleting the resource - """ - cmd = "netdev l2interface delete %s" % self.interface_id - (rc, out, err) = self.run_command(cmd) - resp = json.loads(out) - if resp.get('status') != 200: - rc = resp['status'] - err = resp['message'] - out = None - return (rc, out, err) - - def updates(self): - """ This method will check the current layer 2 interface resource in - the running configuration and return a list of attributes that are - not in sync with the current resource. - """ - obj = self.get() - update = lambda a, z: a != z - - updates = list() - for attrib in self.attributes: - value = getattr(self, attrib) - if update(obj[attrib], value) and value is not None: - updates.append(attrib) - self.log("Updates: %s" % updates) - return updates - - def exists(self): - """ Returns True if the current layer 2 interface resource exists and - returns False if it does not. This method only checks for the - existence of the interface as specified in interface_id. - """ - (rc, out, err) = self.run_command("netdev l2interface list") - collection = json.loads(out) - return self.interface_id in collection.get('result') - - -def main(): - module = AnsibleModule( - argument_spec = dict( - interface_id=dict(default=None, type='str'), - state=dict(default='present', choices=['present', 'absent'], type='str'), - vlan_tagging=dict(default=None, choices=['enable', 'disable']), - tagged_vlans=dict(default=None, type='str'), - untagged_vlan=dict(default=None, type='str'), - logging=dict(default=False, type='bool') - ), - supports_check_mode = True - ) - - obj = AristaL2Interface(module) - - rc = None - result = dict() - - if obj.state == 'absent': - if obj.exists(): - if module.check_mode: - module.exit_json(changed=True) - (rc, out, err) = obj.delete() - if rc !=0: - module.fail_json(msg=err, rc=rc) - - elif obj.state == 'present': - if not obj.exists(): - if module.check_mode: - module.exit_json(changed=True) - (rc, out, err) = obj.create() - result['results'] = out - else: - if obj.changed: - if module.check_mode: - module.exit_json(changed=obj.changed) - (rc, out, err) = obj.update() - result['results'] = out - - if rc is not None and rc != 0: - module.fail_json(msg=err, rc=rc) - - if rc is None: - result['changed'] = False - else: - result['changed'] = True - - module.exit_json(**result) - - -# import module snippets -from ansible.module_utils.basic import * -main() diff --git a/library/net_infrastructure/arista_lag b/library/net_infrastructure/arista_lag deleted file mode 100644 index 5516dde83f..0000000000 --- a/library/net_infrastructure/arista_lag +++ /dev/null @@ -1,324 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013, Arista Networks -# -# This program 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. -# -# This program 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 this program. If not, see . -# -DOCUMENTATION = ''' ---- -module: arista_lag -version_added: "1.3" -author: Peter Sprygada -short_description: Manage port channel (lag) interfaces -requirements: - - Arista EOS 4.10 - - Netdev extension for EOS -description: - - Manage port channel interface resources on Arista EOS network devices -options: - interface_id: - description: - - the full name of the interface - required: true - state: - description: - - describe the desired state of the interface related to the config - required: false - default: 'present' - choices: [ 'present', 'absent' ] - logging: - description: - - enables or disables the syslog facility for this module - required: false - default: false - choices: [ 'true', 'false', 'yes', 'no' ] - links: - description: - - array of physical interface links to include in this lag - required: false - minimum_links: - description: - - the minimum number of physical interaces that must be operationally up to consider the lag operationally up - required: false - lacp: - description: - - enables the use of the LACP protocol for managing link bundles - required: false - default: 'active' - choices: [ 'active', 'passive', 'off' ] -notes: - - Requires EOS 4.10 or later - - The Netdev extension for EOS must be installed and active in the - available extensions (show extensions from the EOS CLI) - - See http://eos.aristanetworks.com for details -''' - -EXAMPLES = ''' -Example playbook entries using the arista_lag module to manage resource -state. Note that interface names must be the full interface name not shortcut -names (ie Ethernet, not Et1) - - tasks: - - name: create lag interface - action: arista_lag interface_id=Port-Channel1 links=Ethernet1,Ethernet2 logging=true - - - name: add member links - action: arista_lag interface_id=Port-Channel1 links=Ethernet1,Ethernet2,Ethernet3 logging=true - - - name: remove member links - action: arista_lag interface_id=Port-Channel1 links=Ethernet2,Ethernet3 logging=true - - - name: remove lag interface - action: arista_lag interface_id=Port-Channel1 state=absent logging=true -''' -import syslog -import json - -class AristaLag(object): - """ This is the base class managing port-channel (lag) interfaces - resources in Arista EOS network devices. This class provides an - implementation for creating, updating and deleting port-channel - interfaces. - - Note: The netdev extension for EOS must be installed in order of this - module to work properly. - - The following commands are implemented in this module: - * netdev lag list - * netdev lag show - * netdev lag edit - * netdev lag delete - - """ - - attributes = ['links', 'minimum_links', 'lacp'] - - def __init__(self, module): - self.module = module - self.interface_id = module.params['interface_id'] - self.state = module.params['state'] - self.links = module.params['links'] - self.minimum_links = module.params['minimum_links'] - self.lacp = module.params['lacp'] - self.logging = module.params['logging'] - - @property - def changed(self): - """ The changed property provides a boolean response if the currently - loaded resouces has changed from the resource running in EOS. - - Returns True if the object is not in sync - Returns False if the object is in sync. - """ - return len(self.updates()) > 0 - - def log(self, entry): - """ This method is responsible for sending log messages to the local - syslog. - """ - if self.logging: - syslog.openlog('ansible-%s' % os.path.basename(__file__)) - syslog.syslog(syslog.LOG_NOTICE, entry) - - def run_command(self, cmd): - """ Calls the Ansible module run_command method. This method will - directly return the results of the run_command method - """ - self.log("Command: %s" % cmd) - return self.module.run_command(cmd.split()) - - - def get(self): - """ This method will return a dictionary with the attributes of the - lag interface resource specified in interface_id. The lag - interface resource has the following structure: - - { - "interface_id": , - "links": , - "minimum_links": , - "lacp": [active* | passive | off] - } - - If the lag interface specified by interface_id does not - exist in the system, this method will return None. - """ - cmd = "netdev lag show %s" % self.interface_id - (rc, out, err) = self.run_command(cmd) - obj = json.loads(out) - if obj.get('status') != 200: - return None - return obj['result'] - - def create(self): - """ Creates a lag interface resource in the current running - configuration. If the lag interface already exists, the - function will return successfully. - - This function implements the following commands: - * netdev lag create {interface_id} [attributes] - - Returns the lag interface resource if the create method was - successful - Returns an error message if there as a problem creating the lag - interface - """ - attribs = [] - for attrib in self.attributes: - if getattr(self, attrib): - attribs.append("--%s" % attrib) - attribs.append(getattr(self, attrib)) - - cmd = "netdev lag create %s " % self.interface_id - cmd += " ".join(attribs) - - (rc, out, err) = self.run_command(cmd) - resp = json.loads(out) - if resp.get('status') != 201: - rc = int(resp['status']) - err = resp['message'] - out = None - else: - out = self.get() - return (rc, out, err) - - def update(self): - """ Updates an existing lag resource in the current running - configuration. If the lag resource does not exist, this method - will return an error. - - This method implements the following commands: - * netdev lag edit {interface_id} [attributes] - - Returns an updated lag interafce resoure if the update method - was successful - """ - attribs = list() - for attrib in self.updates(): - attribs.append("--%s" % attrib) - attribs.append(getattr(self, attrib)) - - cmd = "netdev lag edit %s " % self.interface_id - cmd += " ".join(attribs) - - (rc, out, err) = self.run_command(cmd) - resp = json.loads(out) - if resp.get('status') != 200: - rc = int(resp['status']) - err = resp['message'] - out = None - else: - out = resp['result'] - return (rc, out, err) - - return (2, None, "No attributes have been modified") - - def delete(self): - """ Deletes an existing lag interface resource from the current - running configuration. A nonexistent lag interface will - return successful for this operation. - - This method implements the following commands: - * netdev lag delete {interface_id} - - Returns nothing if the delete was successful - Returns error message if there was a problem deleting the resource - """ - cmd = "netdev lag delete %s" % self.interface_id - (rc, out, err) = self.run_command(cmd) - resp = json.loads(out) - if resp.get('status') != 200: - rc = resp['status'] - err = resp['message'] - out = None - return (rc, out, err) - - def updates(self): - """ This method will check the current lag interface resource in the - running configuration and return a list of attributes that are - not in sync with the current resource. - """ - obj = self.get() - update = lambda a, z: a != z - - updates = list() - for attrib in self.attributes: - if update(obj[attrib], getattr(self, attrib)): - updates.append(attrib) - - return updates - - def exists(self): - """ Returns True if the current lag interface resource exists and - returns False if it does not. This method only checks for the - existence of the interface as specified in interface_id. - """ - (rc, out, err) = self.run_command("netdev lag list") - collection = json.loads(out) - return self.interface_id in collection.get('result') - - -def main(): - module = AnsibleModule( - argument_spec = dict( - interface_id=dict(default=None, type='str'), - state=dict(default='present', choices=['present', 'absent'], type='str'), - links=dict(default=None, type='str'), - lacp=dict(default=None, choices=['active', 'passive', 'off'], type='str'), - minimum_links=dict(default=None, type='int'), - logging=dict(default=False, type='bool') - ), - supports_check_mode = True - ) - - obj = AristaLag(module) - - rc = None - result = dict() - - if obj.state == 'absent': - if obj.exists(): - if module.check_mode: - module.exit_json(changed=True) - (rc, out, err) = obj.delete() - if rc !=0: - module.fail_json(msg=err, rc=rc) - - elif obj.state == 'present': - if not obj.exists(): - if module.check_mode: - module.exit_json(changed=True) - (rc, out, err) = obj.create() - result['results'] = out - else: - if module.check_mode: - module.exit_json(changed=obj.changed) - (rc, out, err) = obj.update() - result['results'] = out - - if rc is not None and rc != 0: - module.fail_json(msg=err, rc=rc) - - if rc is None: - result['changed'] = False - else: - result['changed'] = True - - module.exit_json(**result) - - -# import module snippets -from ansible.module_utils.basic import * -main() diff --git a/library/net_infrastructure/arista_vlan b/library/net_infrastructure/arista_vlan deleted file mode 100644 index f1f28bcd4c..0000000000 --- a/library/net_infrastructure/arista_vlan +++ /dev/null @@ -1,307 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013, Arista Networks -# -# This program 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. -# -# This program 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 this program. If not, see . -# -DOCUMENTATION = ''' ---- -module: arista_vlan -version_added: "1.3" -author: Peter Sprygada -short_description: Manage VLAN resources -requirements: - - Arista EOS 4.10 - - Netdev extension for EOS -description: - - Manage VLAN resources on Arista EOS network devices. This module - requires the Netdev EOS extension to be installed in EOS. For detailed - instructions for installing and using the Netdev module please see - [link] -options: - vlan_id: - description: - - the vlan id - required: true - state: - description: - - describe the desired state of the vlan related to the config - required: false - default: 'present' - choices: [ 'present', 'absent' ] - logging: - description: - - enables or disables the syslog facility for this module - required: false - choices: [ 'true', 'false', 'yes', 'no' ] - name: - description: - - a descriptive name for the vlan - required: false -notes: - - Requires EOS 4.10 or later - - The Netdev extension for EOS must be installed and active in the - available extensions (show extensions from the EOS CLI) - - See http://eos.aristanetworks.com for details -''' - -EXAMPLES = ''' -Example playbook entries using the arista_vlan module to manage resource -state. - - tasks: - - name: create vlan 999 - action: arista_vlan vlan_id=999 logging=true - - - name: create / edit vlan 999 - action: arista_vlan vlan_id=999 name=test logging=true - - - name: remove vlan 999 - action: arista_vlan vlan_id=999 state=absent logging=true - -''' -import syslog -import json - -class AristaVlan(object): - """ This is the base class for managing VLAN resources in EOS network - devices. This class provides basic CRUD functions for VLAN - resources. This class acts as a wrapper around the netdev extension - in EOS. You must have the netdev extension installed in order for - this module to work properly. - - The following commands are implemented in this module: - * netdev vlan create - * netdev vlan list - * netdev vlan show - * netdev vlan edit - * netdev vlan delete - """ - - attributes = ['name'] - - def __init__(self, module): - self.module = module - self.vlan_id = module.params['vlan_id'] - self.name = module.params['name'] - self.state = module.params['state'] - self.logging = module.boolean(module.params['logging']) - - - @property - def changed(self): - """ The changed property provides a boolean response if the currently - loaded resouces has changed from the resource running in EOS. - - Returns True if the object is not in sync - Returns False if the object is in sync. - """ - return len(self.updates()) > 0 - - def log(self, entry): - """ This method is responsible for sending log messages to the local - syslog. - """ - if self.logging: - syslog.openlog('ansible-%s' % os.path.basename(__file__)) - syslog.syslog(syslog.LOG_INFO, entry) - - def run_command(self, cmd): - """ Calls the Ansible module run_command method. This method will - also send a message to syslog with the command name - """ - self.log("Command: %s" % cmd) - return self.module.run_command(cmd.split()) - - - def delete(self): - """ Deletes an existing VLAN resource from the current running - configuration. A nonexistent VLAN will return successful for this - operation. - - This method implements the following commands: - * netdev vlan delete {vlan_id} - - Returns nothing if the delete was successful - Returns error message if there was a problem deleting the vlan - """ - cmd = "netdev vlan delete %s" % self.vlan_id - (rc, out, err) = self.run_command(cmd) - resp = json.loads(out) - if resp.get('status') != 200: - rc = resp['status'] - err = resp['message'] - out = None - return (rc, out, err) - - def create(self): - """ Creates a VLAN resource in the current running configuration. If - the VLAN already exists, the function will return successfully. - - This function implements the following commands: - * netdev vlan create {vlan_id} [--name ] - - Returns the VLAN resource if the create function was successful - Returns an error message if there as a problem creating the vlan - """ - attribs = [] - for attrib in self.attributes: - if getattr(self, attrib): - attribs.append("--%s" % attrib) - attribs.append(getattr(self, attrib)) - - cmd = "netdev vlan create %s " % self.vlan_id - cmd += " ".join(attribs) - - (rc, out, err) = self.run_command(cmd) - resp = json.loads(out) - if resp.get('status') != 201: - rc = int(resp['status']) - err = resp['message'] - out = None - else: - out = resp['result'] - return (rc, out, err) - - def update(self): - """ Updates an existing VLAN resource in the current running - configuration. If the VLAN resource does not exist, this method - will return an error. - - This method implements the following commands: - * netdev vlan edit {vlan_id} [--name ] - - Returns an updated VLAN resoure if the create method was successful - """ - attribs = list() - for attrib in self.updates(): - attribs.append("--%s" % attrib) - attribs.append(getattr(self, attrib)) - - if attribs: - cmd = "netdev vlan edit %s " % self.vlan_id - cmd += " ".join(attribs) - - (rc, out, err) = self.run_command(cmd) - resp = json.loads(out) - if resp.get('status') != 200: - rc = int(resp['status']) - err = resp['message'] - out = None - else: - out = resp['result'] - return (rc, out, err) - - return (0, None, "No attributes have been modified") - - def updates(self): - """ This method will check the current VLAN resource in the running - configuration and return a list of attributes that are not in sync - with the current resource from the running configuration. - """ - obj = self.get() - update = lambda a, z: a != z - - updates = list() - for attrib in self.attributes: - value = getattr(self, attrib) - if update(obj[attrib], update) and value is not None: - updates.append(attrib) - self.log("updates: %s" % updates) - return updates - - def exists(self): - """ Returns True if the current VLAN resource exists and returns False - if it does not. This method only checks for the existence of the - VLAN ID. - """ - (rc, out, err) = self.run_command("netdev vlan list") - collection = json.loads(out) - return str(self.vlan_id) in collection.get('result') - - def get(self): - """ This method will return a dictionary with the attributes of the - VLAN resource identified in vlan_id. The VLAN resource has the - following structure: - - { - "vlan_id": , - "name": - } - - If the VLAN ID specified by vlan_id does not exist in the system, - this method will return None - """ - cmd = "netdev vlan show %s" % self.vlan_id - (rc, out, err) = self.run_command(cmd) - obj = json.loads(out) - if obj.get('status') != 200: - return None - return obj['result'] - - - -def main(): - - module = AnsibleModule( - argument_spec = dict( - vlan_id=dict(default=None, required=True, type='int'), - name=dict(default=None, type='str'), - state=dict(default='present', choices=['present', 'absent']), - logging=dict(default=False, type='bool') - ), - supports_check_mode = True - ) - - obj = AristaVlan(module) - - rc = None - result = dict() - - if obj.state == 'absent': - if obj.exists(): - if module.check_mode: - module.exit_json(changed=True) - (rc, out, err) = obj.delete() - if rc !=0: - module.fail_json(msg=err, rc=rc) - - elif obj.state == 'present': - if not obj.exists(): - if module.check_mode: - module.exit_json(changed=True) - (rc, out, err) = obj.create() - result['results'] = out - else: - if obj.changed: - if module.check_mode: - module.exit_json(changed=obj.changed) - (rc, out, err) = obj.update() - result['results'] = out - - if rc is not None and rc != 0: - module.fail_json(msg=err, rc=rc) - - if rc is None: - result['changed'] = False - else: - result['changed'] = True - - module.exit_json(**result) - - -# import module snippets -from ansible.module_utils.basic import * -main()