Example #1
0
def main():
    module = AnsibleModule(argument_spec=dict(
        vxlan=dict(required=True, type='str'),
        vsi=dict(required=True, type='str'),
        tunnels=dict(required=False, type='list'),
        descr=dict(required=False),
        state=dict(choices=['present', 'absent'], default='present'),
        port=dict(default=830, type='int'),
        hostname=dict(required=True),
        username=dict(required=True),
        password=dict(required=True),
    ),
                           supports_check_mode=True)
    if not HAS_PYHP:
        module.fail_json(msg='There was a problem loading from the pyhpecw7 ' +
                         'module.',
                         error=str(ie))

    username = module.params['username']
    password = module.params['password']
    port = module.params['port']
    hostname = socket.gethostbyname(module.params['hostname'])

    device_args = dict(host=hostname,
                       username=username,
                       password=password,
                       port=port)

    device = HPCOM7(**device_args)

    vxlan = module.params['vxlan']
    vsi = module.params['vsi']
    descr = module.params['descr']
    tunnels = normalize_to_list(module.params['tunnels'])

    state = module.params['state']

    changed = False

    args = dict(vxlan=vxlan, vsi=vsi, descr=descr)
    proposed = dict((k, v) for k, v in args.iteritems() if v is not None)

    try:
        device.open()
    except ConnectionError as e:
        safe_fail(module,
                  device,
                  msg=str(e),
                  descr='error opening device conn')

    try:
        l2vpn = L2VPN(device)
        is_l2vpn_enabled = l2vpn.get_config()
    except PYHPError as e:
        safe_fail(module, device, msg=str(e), descr='L2VPN check failed')

    if is_l2vpn_enabled == 'disabled':
        safe_fail(module, device, msg='l2vpn needs to be enabled.')

    try:
        VXLAN = Vxlan(device, vxlan, vsi)
        existing = VXLAN.get_config()
    except PYHPError as e:
        safe_fail(module,
                  device,
                  msg=str(e),
                  descr='could not obtain existing')

    if state == 'present':
        checks(existing, proposed, module)

    if 'tunnels' in existing.keys():
        existing_tunnels = existing.pop('tunnels')
    else:
        existing_tunnels = []

    delta = dict(set(proposed.iteritems()).difference(existing.iteritems()))

    tunnels_to_add = list(set(tunnels).difference(existing_tunnels))
    tunnels_to_remove = list(set(existing_tunnels).difference(tunnels))
    if tunnels_to_add:
        delta['tunnels_to_add'] = tunnels_to_add
        for each in tunnels_to_add:
            tun = Tunnel(device, each)
            exists = tun.get_config()
            if not exists:
                safe_fail(module,
                          device,
                          msg='tunnel needs to exist first' +
                          ' before \nbefore adding it to a vxlan',
                          tunnel=each)
    if tunnels_to_remove:
        delta['tunnels_to_remove'] = tunnels_to_remove

    if state == 'present':
        if not existing.get('vxlan'):
            VXLAN.create(stage=True)
        if delta:
            VXLAN.build(stage=True, **delta)
    elif state == 'absent':
        if existing:
            # existing is based off the VXLAN ID
            # if it's not mapped to any VSI, it's not considered
            # existing although the VSI may exist
            if existing.get('vsi') != vsi:
                safe_fail(module,
                          device,
                          msg='vsi/vxlan mapping must exist' +
                          ' on switch to remove it',
                          current_vsi=existing.get('vsi'))
            else:
                VXLAN.remove_vsi(stage=True)

    commands = None
    end_state = existing

    if device.staged:
        commands = device.staged_to_string()
        if module.check_mode:
            device.close()
            safe_exit(module, device, changed=True, commands=commands)
        else:
            try:
                device.execute_staged()
                end_state = VXLAN.get_config()
            except PYHPError as e:
                safe_fail(module,
                          device,
                          msg=str(e),
                          descr='failed during execution')
            changed = True

    if tunnels:
        proposed.update(tunnels=tunnels)
    if existing_tunnels:
        existing.update(tunnels=existing_tunnels)

    results = {}
    results['proposed'] = proposed
    results['existing'] = existing
    results['state'] = state
    results['commands'] = commands
    results['changed'] = changed
    results['end_state'] = end_state

    safe_exit(module, device, **results)
Example #2
0
 def setUp(self,  mock_device):
     self.device = mock_device
     self.l2eth = L2EthService(self.device, INTERFACE, INSTANCE, VSI)
     self.vxlan = Vxlan(self.device, INSTANCE, vsi=VSI)
     self.tunnel = Tunnel(self.device, TUNNEL)
def main():
    module = AnsibleModule(argument_spec=dict(
        tunnel=dict(required=True, type='str'),
        src=dict(required=False, type='str'),
        dest=dict(required=False, type='str'),
        global_src=dict(required=False, type='str'),
        state=dict(choices=['present', 'absent'], default='present'),
        port=dict(default=830, type='int'),
        hostname=dict(required=True),
        username=dict(required=True),
        password=dict(required=True),
    ),
                           supports_check_mode=True)
    if not HAS_PYHP:
        module.fail_json(msg='There was a problem loading from the pyhpecw7 ' +
                         'module.',
                         error=str(ie))

    username = module.params['username']
    password = module.params['password']
    port = module.params['port']
    hostname = socket.gethostbyname(module.params['hostname'])

    device_args = dict(host=hostname,
                       username=username,
                       password=password,
                       port=port)

    device = HPCOM7(**device_args)

    tunnel = module.params['tunnel']
    src = module.params['src']
    dest = module.params['dest']
    global_src = module.params['global_src']

    state = module.params['state']

    changed = False

    args = dict(src=src, dest=dest)
    proposed = dict((k, v) for k, v in args.iteritems() if v is not None)

    try:
        device.open()
    except ConnectionError as e:
        safe_fail(module,
                  device,
                  msg=str(e),
                  descr='error opening device conn')

    try:
        l2vpn = L2VPN(device)
        is_l2vpn_enabled = l2vpn.get_config()
    except PYHPError as e:
        safe_fail(module, device, msg=str(e), descr='L2VPN check failed')

    if is_l2vpn_enabled == 'disabled':
        safe_fail(module, device, msg='l2vpn needs to be enabled.')

    try:
        tun = Tunnel(device, tunnel)
        existing = tun.get_config()
    except PYHPError as e:
        safe_fail(module,
                  device,
                  msg=str(e),
                  descr='could not get tunnel config')

    if state == 'present':
        if existing.get('mode') and existing.get('mode') != 'vxlan':
            safe_fail(module,
                      device,
                      msg='tunnel interface exists but is not a ' +
                      'vxlan \ntunnel interface. remove and re-add.')

    delta = dict(set(proposed.iteritems()).difference(existing.iteritems()))

    try:
        existing_gsrc = tun.get_global_source()
    except PYHPError as e:
        safe_fail(module,
                  device,
                  msg=str(e),
                  descr='could not get existing global src')

    if global_src:
        if existing_gsrc != global_src:
            delta['global_src'] = global_src
    if state == 'present':
        if delta or not existing:
            tun.build(stage=True, **delta)
    elif state == 'absent':
        if existing:
            tun.remove(stage=True)

    commands = None
    end_state = existing

    if device.staged:
        commands = device.staged_to_string()
        if module.check_mode:
            device.close()
            safe_exit(module, device, changed=True, commands=commands)
        else:
            try:
                device.execute_staged()
                end_state = tun.get_config()
            except PYHPError as e:
                safe_fail(module,
                          device,
                          msg=str(e),
                          descr='error during execution')
            end_state['global_src'] = tun.get_global_source()
            changed = True

    proposed['global_src'] = global_src
    existing['global_src'] = existing_gsrc

    results = {}
    results['proposed'] = proposed
    results['existing'] = existing
    results['state'] = state
    results['commands'] = commands
    results['changed'] = changed
    results['end_state'] = end_state

    safe_exit(module, device, **results)
Example #4
0
class VxlanTestCase(BaseFeatureCase):

    @mock.patch('pyhpecw7.comware.HPCOM7')
    def setUp(self,  mock_device):
        self.device = mock_device
        self.l2eth = L2EthService(self.device, INTERFACE, INSTANCE, VSI)
        self.vxlan = Vxlan(self.device, INSTANCE, vsi=VSI)
        self.tunnel = Tunnel(self.device, TUNNEL)


    def test_tunnel_get_config(self):
        self.device.cli_display.return_value = """<HP1>display current-configuration interface Tunnel 20
#
interface Tunnel20 mode vxlan
 source 10.1.1.1
 destination 10.1.1.2
#
return
"""
        expected = {'dest': '10.1.1.2', 'src': '10.1.1.1', 'mode': 'vxlan'}
        result = self.tunnel.get_config()

        self.assertEqual(result, expected)

    def test_tunnel_get_config_no_tunnel(self):
        self.device.cli_display.return_value = """                                                    ^
 % Wrong parameter found at '^' position.
"""
        expected = {}
        result = self.tunnel.get_config()

        self.assertEqual(result, expected)

    def test_tunnel_get_global_source(self):
        self.device.cli_display.return_value = """<HP1>display current-configuration | inc "tunnel global source"
 tunnel global source-address 10.10.10.10

"""
        expected = '10.10.10.10'
        result = self.tunnel.get_global_source()

        self.assertEqual(result, expected)

    def test_tunnel_build_config(self):
        self.tunnel._build_config('present', src='1.1.1.1', dest='2.2.2.2', global_src='1.1.1.2')
        expected_call = ['tunnel global source-address 1.1.1.2', 'interface tunnel 20 mode vxlan', 'source 1.1.1.1', 'destination 2.2.2.2']

        self.device.cli_config.assert_called_with(expected_call)

    def test_tunnel_build_config_stage(self):
        self.tunnel._build_config('present', src='1.1.1.1', dest='2.2.2.2', global_src='1.1.1.2', stage=True)
        expected_call = ['tunnel global source-address 1.1.1.2', 'interface tunnel 20 mode vxlan', 'source 1.1.1.1', 'destination 2.2.2.2']

        self.device.stage_config.assert_called_with(expected_call, 'cli_config')

    def test_tunnel_build_config_remove(self):
        self.tunnel._build_config('absent', src='1.1.1.1', dest='2.2.2.2', global_src='1.1.1.2')
        expected_call = ['undo interface tunnel 20']

        self.device.cli_config.assert_called_with(expected_call)

    @mock.patch.object(Tunnel, '_build_config')
    def test_tunnel_remove_stage(self, mock_build_config):
        self.tunnel.remove(stage=True)
        mock_build_config.assert_called_with(state='absent', stage=True)

    @mock.patch.object(Tunnel, '_build_config')
    def test_tunnel_remove(self, mock_build_config):
        self.tunnel.remove()
        mock_build_config.assert_called_with(state='absent', stage=False)

    @mock.patch.object(Tunnel, '_build_config')
    def test_tunnel_build_stage(self, mock_build_config):
        self.tunnel.build(stage=True)
        mock_build_config.assert_called_with(state='present', stage=True)

    @mock.patch.object(Tunnel, '_build_config')
    def test_tunnel_build(self, mock_build_config):
        self.tunnel.build()
        mock_build_config.assert_called_with(state='present', stage=False)

    @mock.patch.object(Vxlan, 'get_tunnels')
    def test_get_config(self, mock_get_tunnels):
        mock_get_tunnels.return_value = ['20']

        expected_get, get_reply = self.xml_get_and_reply('vxlan')
        self.device.get.return_value = get_reply

        expected = {'vsi': 'VSI_VXLAN_100', 'tunnels': ['20'], 'vxlan': '100'}

        result = self.vxlan.get_config()

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)

    def test_build_vsi(self):
        result = self.vxlan._build_vsi('merge')
        expected = self.read_config_xml('vxlan_vsi')

        self.assert_elements_equal(result, expected)

    def test_build_vxlan(self):
        result = self.vxlan._build_vxlan('merge')
        expected = self.read_config_xml('vxlan')

        self.assert_elements_equal(result, expected)

    def test_build_tunnels(self):
        result = self.vxlan._build_tunnels('merge', ['20', '3'])
        expected = self.read_config_xml('vxlan_tunnels')

        self.assert_elements_equal(result, expected)

    def test_build(self):
        result = self.vxlan.build(tunnels_to_add=['20', '3'])
        expected_add_call = self.read_config_xml('vxlan_tunnels')

        self.assert_config_request(expected_add_call)

        result = self.vxlan.build(tunnels_to_remove=['4', '5'], stage=True)
        expected_rmv_call = self.read_config_xml('vxlan_tunnels_delete')

        self.assert_stage_request(expected_rmv_call, 'edit_config')
        self.assertEqual(result, True)

    def test_create(self):
        expected_vsi_call = self.read_config_xml('vxlan_vsi')
        expected_vxlan_call = self.read_config_xml('vxlan')

        result = self.vxlan.create()
        self.assert_config_request(expected_vxlan_call)

        result = self.vxlan.create(stage=True)
        self.assert_stage_request(expected_vxlan_call, 'edit_config')

    def test_remove_vsi(self):
        expected_vsi_call = self.read_config_xml('vxlan_vsi_delete')
        result = self.vxlan.remove_vsi()

        self.assert_config_request(expected_vsi_call)
        self.assertTrue(result)

        result = self.vxlan.remove_vsi(stage=True)
        self.assert_stage_request(expected_vsi_call, 'edit_config')

    def test_remove_vxlan(self):
        expected_call = self.read_config_xml('vxlan_delete')
        result = self.vxlan.remove_vxlan()

        self.assert_config_request(expected_call)
        self.assertTrue(result)

        result = self.vxlan.remove_vxlan(stage=True)
        self.assert_stage_request(expected_call, 'edit_config')

    def test_get_tunnels(self):
        expected_get, get_reply = self.xml_get_and_reply('vxlan_tunnels')
        self.device.get.return_value = get_reply

        expected = ['20']

        result = self.vxlan.get_tunnels()

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)

    def test_l2eth_vsi_exist(self):
        expected_get, get_reply = self.xml_get_and_reply('l2eth_vsi_exist')
        self.device.get.return_value = get_reply

        expected = {'vsi': 'VSI_VXLAN_100'}

        result = self.l2eth.vsi_exist()

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)

    @mock.patch.object(L2EthService, '_index_from_interface')
    def test_l2eth_get_vsi_map(self, mock_index_from_interface):
        mock_index_from_interface.return_value = '125'

        expected_get, get_reply = self.xml_get_and_reply('l2eth_vsi_map')
        self.device.get.return_value = get_reply

        expected = {'vsi': 'VSI_VXLAN_100', 'access_mode': 'ethernet', 'index': '125', 'instance': '100'}

        result = self.l2eth.get_vsi_map()

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)

    @mock.patch.object(L2EthService, '_index_from_interface')
    @mock.patch.object(L2EthService, '_get_interface_from_index')
    def test_l2eth_get_vsi_encap(self, mock_iface_from_index, mock_index_from_interface):
        mock_iface_from_index.return_value = 'FortyGigE1/0/32'
        mock_index_from_interface.return_value = '125'

        expected_get, get_reply = self.xml_get_and_reply('l2eth_vsi_encap')
        self.device.get.return_value = get_reply

        expected = {'interface': 'FortyGigE1/0/32', 'index': '125', 'encap': 'tagged', 'instance': '100'}

        result = self.l2eth.get_vsi_encap()

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)


    @mock.patch.object(L2EthService, '_index_from_interface')
    def test_l2eth_build_encap_default(self, mock_index_from_interface):
        mock_index_from_interface.return_value = '125'
        expected_call = self.read_config_xml('l2eth_build_encap_default')

        self.l2eth._build_encap('merge', encap='default')
        self.assert_config_request(expected_call)

        self.l2eth._build_encap('merge', stage=True, encap='default')
        self.assert_stage_request(expected_call, 'edit_config')

    @mock.patch.object(L2EthService, '_index_from_interface')
    def test_l2eth_build_encap_tagged(self, mock_index_from_interface):
        mock_index_from_interface.return_value = '125'
        expected_call = self.read_config_xml('l2eth_build_encap_tagged')

        self.l2eth._build_encap('merge', encap='tagged')
        self.assert_config_request(expected_call)

        self.l2eth._build_encap('merge', stage=True, encap='tagged')
        self.assert_stage_request(expected_call, 'edit_config')

    @mock.patch.object(L2EthService, '_index_from_interface')
    def test_l2eth_build_encap_only_tagged(self, mock_index_from_interface):
        mock_index_from_interface.return_value = '125'
        expected_call = self.read_config_xml('l2eth_build_encap_only_tagged')

        self.l2eth._build_encap('merge', encap='only-tagged', vlanid='10')
        self.assert_config_request(expected_call)

        self.l2eth._build_encap('merge', stage=True, encap='only-tagged', vlanid='10')
        self.assert_stage_request(expected_call, 'edit_config')

    @mock.patch.object(L2EthService, '_index_from_interface')
    def test_l2eth_build_encap_only_delete(self, mock_index_from_interface):
        mock_index_from_interface.return_value = '125'
        expected_call = self.read_config_xml('l2eth_build_encap_delete')

        self.l2eth._build_encap('delete')
        self.assert_config_request(expected_call)

        self.l2eth._build_encap('delete', stage=True)
        self.assert_stage_request(expected_call, 'edit_config')

    def test_l2eth_build_xconnect(self):
        expected_call = self.read_config_xml('l2eth_build_xconnect')

        self.l2eth._build_xconnect('merge', '125', access_mode='ethernet')
        self.assert_config_request(expected_call)

        self.l2eth._build_xconnect('merge', '125', stage=True, access_mode='ethernet')
        self.assert_stage_request(expected_call, 'edit_config')

    @mock.patch.object(L2EthService, '_build_encap')
    @mock.patch.object(L2EthService, '_build_xconnect')
    def test_l2eth_build_config(self, mock_xconnect, mock_encap):
        self.l2eth.jindex = '999'

        self.l2eth._build_config('present', encap='tagged', access_mode='vlan')
        mock_encap.assert_called_with('merge', access_mode='vlan', encap='tagged', stage=False)
        mock_xconnect.assert_called_with('merge', '999', access_mode='vlan', encap='tagged', stage=False)

    @mock.patch.object(L2EthService, '_build_encap')
    @mock.patch.object(L2EthService, '_build_xconnect')
    def test_l2eth_build_config_absent(self, mock_xconnect, mock_encap):
        self.l2eth.jindex = '999'

        self.l2eth._build_config('absent', encap='tagged', access_mode='vlan')
        mock_encap.assert_called_with('delete', access_mode='vlan', encap='tagged', stage=False)
        mock_xconnect.assert_not_called()

    @mock.patch.object(L2EthService, '_build_config')
    def test_l2eth_build(self, mock_build_config):
        self.l2eth.build(vsi='abc', encap='tagged', access_mode='ethernet')
        mock_build_config.assert_called_with(access_mode='ethernet', encap='tagged', stage=False, state='present', vsi='abc')

    @mock.patch.object(L2EthService, '_build_config')
    def test_l2eth_remove(self, mock_build_config):
        self.l2eth.remove()
        mock_build_config.assert_called_with(stage=False, state='absent')

    def test_l2eth_get_interface_from_index(self):
        expected_get, get_reply = self.xml_get_and_reply('l2eth_get_interface_from_index')
        self.device.get.return_value = get_reply

        expected = 'FortyGigE1/0/32'

        result = self.l2eth._get_interface_from_index('125')

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)
Example #5
0
 def setUp(self,  mock_device):
     self.device = mock_device
     self.l2eth = L2EthService(self.device, INTERFACE, INSTANCE, VSI)
     self.vxlan = Vxlan(self.device, INSTANCE, vsi=VSI)
     self.tunnel = Tunnel(self.device, TUNNEL)
Example #6
0
class VxlanTestCase(BaseFeatureCase):

    @mock.patch('pyhpecw7.comware.HPCOM7')
    def setUp(self,  mock_device):
        self.device = mock_device
        self.l2eth = L2EthService(self.device, INTERFACE, INSTANCE, VSI)
        self.vxlan = Vxlan(self.device, INSTANCE, vsi=VSI)
        self.tunnel = Tunnel(self.device, TUNNEL)


    def test_tunnel_get_config(self):
        self.device.cli_display.return_value = """<HP1>display current-configuration interface Tunnel 20
#
interface Tunnel20 mode vxlan
 source 10.1.1.1
 destination 10.1.1.2
#
return
"""
        expected = {'dest': '10.1.1.2', 'src': '10.1.1.1', 'mode': 'vxlan'}
        result = self.tunnel.get_config()

        self.assertEqual(result, expected)

    def test_tunnel_get_config_no_tunnel(self):
        self.device.cli_display.return_value = """                                                    ^
 % Wrong parameter found at '^' position.
"""
        expected = {}
        result = self.tunnel.get_config()

        self.assertEqual(result, expected)

    def test_tunnel_get_global_source(self):
        self.device.cli_display.return_value = """<HP1>display current-configuration | inc "tunnel global source"
 tunnel global source-address 10.10.10.10

"""
        expected = '10.10.10.10'
        result = self.tunnel.get_global_source()

        self.assertEqual(result, expected)

    def test_tunnel_build_config(self):
        self.tunnel._build_config('present', src='1.1.1.1', dest='2.2.2.2', global_src='1.1.1.2')
        expected_call = ['tunnel global source-address 1.1.1.2', 'interface tunnel 20 mode vxlan', 'source 1.1.1.1', 'destination 2.2.2.2']

        self.device.cli_config.assert_called_with(expected_call)

    def test_tunnel_build_config_stage(self):
        self.tunnel._build_config('present', src='1.1.1.1', dest='2.2.2.2', global_src='1.1.1.2', stage=True)
        expected_call = ['tunnel global source-address 1.1.1.2', 'interface tunnel 20 mode vxlan', 'source 1.1.1.1', 'destination 2.2.2.2']

        self.device.stage_config.assert_called_with(expected_call, 'cli_config')

    def test_tunnel_build_config_remove(self):
        self.tunnel._build_config('absent', src='1.1.1.1', dest='2.2.2.2', global_src='1.1.1.2')
        expected_call = ['undo interface tunnel 20']

        self.device.cli_config.assert_called_with(expected_call)

    @mock.patch.object(Tunnel, '_build_config')
    def test_tunnel_remove_stage(self, mock_build_config):
        self.tunnel.remove(stage=True)
        mock_build_config.assert_called_with(state='absent', stage=True)

    @mock.patch.object(Tunnel, '_build_config')
    def test_tunnel_remove(self, mock_build_config):
        self.tunnel.remove()
        mock_build_config.assert_called_with(state='absent', stage=False)

    @mock.patch.object(Tunnel, '_build_config')
    def test_tunnel_build_stage(self, mock_build_config):
        self.tunnel.build(stage=True)
        mock_build_config.assert_called_with(state='present', stage=True)

    @mock.patch.object(Tunnel, '_build_config')
    def test_tunnel_build(self, mock_build_config):
        self.tunnel.build()
        mock_build_config.assert_called_with(state='present', stage=False)

    @mock.patch.object(Vxlan, 'get_tunnels')
    def test_get_config(self, mock_get_tunnels):
        mock_get_tunnels.return_value = ['20']

        expected_get, get_reply = self.xml_get_and_reply('vxlan')
        self.device.get.return_value = get_reply

        expected = {'vsi': 'VSI_VXLAN_100', 'tunnels': ['20'], 'vxlan': '100'}

        result = self.vxlan.get_config()

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)

    def test_build_vsi(self):
        result = self.vxlan._build_vsi('merge')
        expected = self.read_config_xml('vxlan_vsi')

        self.assert_elements_equal(result, expected)

    def test_build_vxlan(self):
        result = self.vxlan._build_vxlan('merge')
        expected = self.read_config_xml('vxlan')

        self.assert_elements_equal(result, expected)

    def test_build_tunnels(self):
        result = self.vxlan._build_tunnels('merge', ['20', '3'])
        expected = self.read_config_xml('vxlan_tunnels')

        self.assert_elements_equal(result, expected)

    def test_build(self):
        result = self.vxlan.build(tunnels_to_add=['20', '3'])
        expected_add_call = self.read_config_xml('vxlan_tunnels')

        self.assert_config_request(expected_add_call)

        result = self.vxlan.build(tunnels_to_remove=['4', '5'], stage=True)
        expected_rmv_call = self.read_config_xml('vxlan_tunnels_delete')

        self.assert_stage_request(expected_rmv_call, 'edit_config')
        self.assertEqual(result, True)

    def test_create(self):
        expected_vsi_call = self.read_config_xml('vxlan_vsi')
        expected_vxlan_call = self.read_config_xml('vxlan')

        result = self.vxlan.create()
        self.assert_config_request(expected_vxlan_call)

        result = self.vxlan.create(stage=True)
        self.assert_stage_request(expected_vxlan_call, 'edit_config')

    def test_remove_vsi(self):
        expected_vsi_call = self.read_config_xml('vxlan_vsi_delete')
        result = self.vxlan.remove_vsi()

        self.assert_config_request(expected_vsi_call)
        self.assertTrue(result)

        result = self.vxlan.remove_vsi(stage=True)
        self.assert_stage_request(expected_vsi_call, 'edit_config')

    def test_remove_vxlan(self):
        expected_call = self.read_config_xml('vxlan_delete')
        result = self.vxlan.remove_vxlan()

        self.assert_config_request(expected_call)
        self.assertTrue(result)

        result = self.vxlan.remove_vxlan(stage=True)
        self.assert_stage_request(expected_call, 'edit_config')

    def test_get_tunnels(self):
        expected_get, get_reply = self.xml_get_and_reply('vxlan_tunnels')
        self.device.get.return_value = get_reply

        expected = ['20']

        result = self.vxlan.get_tunnels()

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)

    def test_l2eth_vsi_exist(self):
        expected_get, get_reply = self.xml_get_and_reply('l2eth_vsi_exist')
        self.device.get.return_value = get_reply

        expected = {'vsi': 'VSI_VXLAN_100'}

        result = self.l2eth.vsi_exist()

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)

    @mock.patch.object(L2EthService, '_index_from_interface')
    def test_l2eth_get_vsi_map(self, mock_index_from_interface):
        mock_index_from_interface.return_value = '125'

        expected_get, get_reply = self.xml_get_and_reply('l2eth_vsi_map')
        self.device.get.return_value = get_reply

        expected = {'vsi': 'VSI_VXLAN_100', 'access_mode': 'ethernet', 'index': '125', 'instance': '100'}

        result = self.l2eth.get_vsi_map()

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)

    @mock.patch.object(L2EthService, '_index_from_interface')
    @mock.patch.object(L2EthService, '_get_interface_from_index')
    def test_l2eth_get_vsi_encap(self, mock_iface_from_index, mock_index_from_interface):
        mock_iface_from_index.return_value = 'FortyGigE1/0/32'
        mock_index_from_interface.return_value = '125'

        expected_get, get_reply = self.xml_get_and_reply('l2eth_vsi_encap')
        self.device.get.return_value = get_reply

        expected = {'interface': 'FortyGigE1/0/32', 'index': '125', 'encap': 'tagged', 'instance': '100'}

        result = self.l2eth.get_vsi_encap()

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)


    @mock.patch.object(L2EthService, '_index_from_interface')
    def test_l2eth_build_encap_default(self, mock_index_from_interface):
        mock_index_from_interface.return_value = '125'
        expected_call = self.read_config_xml('l2eth_build_encap_default')

        self.l2eth._build_encap('merge', encap='default')
        self.assert_config_request(expected_call)

        self.l2eth._build_encap('merge', stage=True, encap='default')
        self.assert_stage_request(expected_call, 'edit_config')

    @mock.patch.object(L2EthService, '_index_from_interface')
    def test_l2eth_build_encap_tagged(self, mock_index_from_interface):
        mock_index_from_interface.return_value = '125'
        expected_call = self.read_config_xml('l2eth_build_encap_tagged')

        self.l2eth._build_encap('merge', encap='tagged')
        self.assert_config_request(expected_call)

        self.l2eth._build_encap('merge', stage=True, encap='tagged')
        self.assert_stage_request(expected_call, 'edit_config')

    @mock.patch.object(L2EthService, '_index_from_interface')
    def test_l2eth_build_encap_only_tagged(self, mock_index_from_interface):
        mock_index_from_interface.return_value = '125'
        expected_call = self.read_config_xml('l2eth_build_encap_only_tagged')

        self.l2eth._build_encap('merge', encap='only-tagged', vlanid='10')
        self.assert_config_request(expected_call)

        self.l2eth._build_encap('merge', stage=True, encap='only-tagged', vlanid='10')
        self.assert_stage_request(expected_call, 'edit_config')

    @mock.patch.object(L2EthService, '_index_from_interface')
    def test_l2eth_build_encap_only_delete(self, mock_index_from_interface):
        mock_index_from_interface.return_value = '125'
        expected_call = self.read_config_xml('l2eth_build_encap_delete')

        self.l2eth._build_encap('delete')
        self.assert_config_request(expected_call)

        self.l2eth._build_encap('delete', stage=True)
        self.assert_stage_request(expected_call, 'edit_config')

    def test_l2eth_build_xconnect(self):
        expected_call = self.read_config_xml('l2eth_build_xconnect')

        self.l2eth._build_xconnect('merge', '125', access_mode='ethernet')
        self.assert_config_request(expected_call)

        self.l2eth._build_xconnect('merge', '125', stage=True, access_mode='ethernet')
        self.assert_stage_request(expected_call, 'edit_config')

    @mock.patch.object(L2EthService, '_build_encap')
    @mock.patch.object(L2EthService, '_build_xconnect')
    def test_l2eth_build_config(self, mock_xconnect, mock_encap):
        self.l2eth.jindex = '999'

        self.l2eth._build_config('present', encap='tagged', access_mode='vlan')
        mock_encap.assert_called_with('merge', access_mode='vlan', encap='tagged', stage=False)
        mock_xconnect.assert_called_with('merge', '999', access_mode='vlan', encap='tagged', stage=False)

    @mock.patch.object(L2EthService, '_build_encap')
    @mock.patch.object(L2EthService, '_build_xconnect')
    def test_l2eth_build_config_absent(self, mock_xconnect, mock_encap):
        self.l2eth.jindex = '999'

        self.l2eth._build_config('absent', encap='tagged', access_mode='vlan')
        mock_encap.assert_called_with('delete', access_mode='vlan', encap='tagged', stage=False)
        mock_xconnect.assert_not_called()

    @mock.patch.object(L2EthService, '_build_config')
    def test_l2eth_build(self, mock_build_config):
        self.l2eth.build(vsi='abc', encap='tagged', access_mode='ethernet')
        mock_build_config.assert_called_with(access_mode='ethernet', encap='tagged', stage=False, state='present', vsi='abc')

    @mock.patch.object(L2EthService, '_build_config')
    def test_l2eth_remove(self, mock_build_config):
        self.l2eth.remove()
        mock_build_config.assert_called_with(stage=False, state='absent')

    def test_l2eth_get_interface_from_index(self):
        expected_get, get_reply = self.xml_get_and_reply('l2eth_get_interface_from_index')
        self.device.get.return_value = get_reply

        expected = 'FortyGigE1/0/32'

        result = self.l2eth._get_interface_from_index('125')

        self.assertEqual(result, expected)
        self.assert_get_request(expected_get)
def main():
    module = AnsibleModule(
        argument_spec=dict(
            vxlan=dict(required=True, type='str'),
            vsi=dict(required=True, type='str'),
            tunnels=dict(required=False),
            descr=dict(required=False),
            state=dict(choices=['present', 'absent'], default='present'),
            port=dict(default=830, type='int'),
            hostname=dict(required=True),
            username=dict(required=True),
            password=dict(required=True),
        ),
        supports_check_mode=True
    )
    if not HAS_PYHP:
        module.fail_json(msg='There was a problem loading from the pyhpecw7 '
                         + 'module.', error=str(ie))

    username = module.params['username']
    password = module.params['password']
    port = module.params['port']
    hostname = socket.gethostbyname(module.params['hostname'])

    device_args = dict(host=hostname, username=username,
                       password=password, port=port)

    device = HPCOM7(**device_args)

    vxlan = module.params['vxlan']
    vsi = module.params['vsi']
    descr = module.params['descr']
    tunnels = normalize_to_list(module.params['tunnels'])

    state = module.params['state']

    changed = False

    args = dict(vxlan=vxlan, vsi=vsi, descr=descr)
    proposed = dict((k, v) for k, v in args.iteritems() if v is not None)

    try:
        device.open()
    except ConnectionError as e:
        safe_fail(module, device, msg=str(e), descr='error opening device conn')

    try:
        l2vpn = L2VPN(device)
        is_l2vpn_enabled = l2vpn.get_config()
    except PYHPError as e:
        safe_fail(module, device, msg=str(e), descr='L2VPN check failed')

    if is_l2vpn_enabled == 'disabled':
        safe_fail(module, device, msg='l2vpn needs to be enabled.')

    try:
        VXLAN = Vxlan(device, vxlan, vsi)
        existing = VXLAN.get_config()
    except PYHPError as e:
        safe_fail(module, device, msg=str(e), descr='could not obtain existing')

    if state == 'present':
        checks(existing, proposed, module)

    if 'tunnels' in existing.keys():
        existing_tunnels = existing.pop('tunnels')
    else:
        existing_tunnels = []

    delta = dict(set(proposed.iteritems()).difference(
        existing.iteritems()))

    tunnels_to_add = list(set(tunnels).difference(existing_tunnels))
    tunnels_to_remove = list(set(existing_tunnels).difference(tunnels))
    if tunnels_to_add:
        delta['tunnels_to_add'] = tunnels_to_add
        for each in tunnels_to_add:
            tun = Tunnel(device, each)
            exists = tun.get_config()
            if not exists:
                safe_fail(module, device, msg='tunnel needs to exist first'
                          + ' before \nbefore adding it to a vxlan',
                          tunnel=each)
    if tunnels_to_remove:
        delta['tunnels_to_remove'] = tunnels_to_remove

    if state == 'present':
        if not existing.get('vxlan'):
            VXLAN.create(stage=True)
        if delta:
            VXLAN.build(stage=True, **delta)
    elif state == 'absent':
        if existing:
            # existing is based off the VXLAN ID
            # if it's not mapped to any VSI, it's not considered
            # existing although the VSI may exist
            if existing.get('vsi') != vsi:
                safe_fail(module, device, msg='vsi/vxlan mapping must exist'
                          + ' on switch to remove it', current_vsi=existing.get('vsi'))
            else:
                VXLAN.remove_vsi(stage=True)

    commands = None
    end_state = existing

    if device.staged:
        commands = device.staged_to_string()
        if module.check_mode:
            device.close()
            safe_exit(module, device, changed=True,
                      commands=commands)
        else:
            try:
                device.execute_staged()
                end_state = VXLAN.get_config()
            except PYHPError as e:
                safe_fail(module, device, msg=str(e),
                          descr='failed during execution')
            changed = True

    if tunnels:
        proposed.update(tunnels=tunnels)
    if existing_tunnels:
        existing.update(tunnels=existing_tunnels)

    results = {}
    results['proposed'] = proposed
    results['existing'] = existing
    results['state'] = state
    results['commands'] = commands
    results['changed'] = changed
    results['end_state'] = end_state

    safe_exit(module, device, **results)
def main():
    module = AnsibleModule(
        argument_spec=dict(
            tunnel=dict(required=True, type='str'),
            src=dict(required=False, type='str'),
            dest=dict(required=False, type='str'),
            global_src=dict(required=False, type='str'),
            state=dict(choices=['present', 'absent'], default='present'),
            port=dict(default=830, type='int'),
            hostname=dict(required=True),
            username=dict(required=True),
            password=dict(required=True),
        ),
        supports_check_mode=True
    )
    if not HAS_PYHP:
        module.fail_json(msg='There was a problem loading from the pyhpecw7 '
                         + 'module.', error=str(ie))

    username = module.params['username']
    password = module.params['password']
    port = module.params['port']
    hostname = socket.gethostbyname(module.params['hostname'])

    device_args = dict(host=hostname, username=username,
                       password=password, port=port)

    device = HPCOM7(**device_args)

    tunnel = module.params['tunnel']
    src = module.params['src']
    dest = module.params['dest']
    global_src = module.params['global_src']

    state = module.params['state']

    changed = False

    args = dict(src=src, dest=dest)
    proposed = dict((k, v) for k, v in args.iteritems() if v is not None)

    try:
        device.open()
    except ConnectionError as e:
        safe_fail(module, device, msg=str(e), descr='error opening device conn')

    try:
        l2vpn = L2VPN(device)
        is_l2vpn_enabled = l2vpn.get_config()
    except PYHPError as e:
        safe_fail(module, device, msg=str(e), descr='L2VPN check failed')

    if is_l2vpn_enabled == 'disabled':
        safe_fail(module, device, msg='l2vpn needs to be enabled.')

    try:
        tun = Tunnel(device, tunnel)
        existing = tun.get_config()
    except PYHPError as e:
        safe_fail(module, device, msg=str(e), descr='could not get tunnel config')

    if state == 'present':
        if existing.get('mode') and existing.get('mode') != 'vxlan':
            safe_fail(module, device, msg='tunnel interface exists but is not a '
                      + 'vxlan \ntunnel interface. remove and re-add.')

    delta = dict(set(proposed.iteritems()).difference(
        existing.iteritems()))

    try:
        existing_gsrc = tun.get_global_source()
    except PYHPError as e:
        safe_fail(module, device, msg=str(e),
                  descr='could not get existing global src')

    if global_src:
        if existing_gsrc != global_src:
            delta['global_src'] = global_src
    if state == 'present':
        if delta or not existing:
            tun.build(stage=True, **delta)
    elif state == 'absent':
        if existing:
            tun.remove(stage=True)

    commands = None
    end_state = existing

    if device.staged:
        commands = device.staged_to_string()
        if module.check_mode:
            device.close()
            safe_exit(module, device, changed=True,
                      commands=commands)
        else:
            try:
                device.execute_staged()
                end_state = tun.get_config()
            except PYHPError as e:
                safe_fail(module, device, msg=str(e),
                          descr='error during execution')
            end_state['global_src'] = tun.get_global_source()
            changed = True

    proposed['global_src'] = global_src
    existing['global_src'] = existing_gsrc

    results = {}
    results['proposed'] = proposed
    results['existing'] = existing
    results['state'] = state
    results['commands'] = commands
    results['changed'] = changed
    results['end_state'] = end_state

    safe_exit(module, device, **results)