# -*- coding: utf-8 -*- ''' :codeauthor: :email:`Jayesh Kariya ` :codeauthor: :email:`Joe Julian ` ''' # Import Python libs from __future__ import absolute_import # Import Salt Testing Libs from salttesting import TestCase, skipIf from salttesting.mock import ( MagicMock, patch, NO_MOCK, NO_MOCK_REASON ) # Import Salt Libs from salt.modules import glusterfs import salt.utils.cloud as suc from salt.exceptions import CommandExecutionError, SaltInvocationError # Globals glusterfs.__salt__ = {} class GlusterResults(object): ''' This class holds the xml results from gluster cli transactions ''' class v34(object): ''' This is for version 3.4 results ''' class list_peers(object): ''' results from "peer status" ''' pass class peer_probe(object): fail_cant_connect = fail_bad_hostname = '\n'.join([ '', '', ' -1', ' 107', ' Probe returned with unknown errno 107', '', '']) success_self = '\n'.join([ '' ' ', ' 0', ' 1', ' (null)', ' success: on localhost not needed', '', '']) success_other = '\n'.join([ '' ' ', ' 0', ' 0', ' (null)', ' success', '', '']) success_hostname_after_ip = success_other success_ip_after_hostname = success_other success_already_peer = { 'ip': '\n'.join([ '' ' ', ' 0', ' 2', ' (null)', ' success: host 10.0.0.2 port 24007 already in peer list', '', '']), 'hostname': '\n'.join([ '' ' ', ' 0', ' 2', ' (null)', ' success: host server2 port 24007 already in peer list', '', ''])} success_reverse_already_peer = { 'ip': '\n'.join([ '' ' ', ' 0', ' 2', ' (null)', ' success: host 10.0.0.1 port 24007 already in peer list', '', '']), 'hostname': '\n'.join([ '' ' ', ' 0', ' 2', ' (null)', ' success: host server1 port 24007 already in peer list', '', ''])} success_first_hostname_from_second_first_time = success_other success_first_hostname_from_second_second_time = success_reverse_already_peer[ 'hostname'] success_first_ip_from_second_first_time = success_reverse_already_peer[ 'ip'] class v37(object): class peer_probe(object): fail_cant_connect = fail_bad_hostname = '\n'.join([ '', '', ' -1', ' 107', ' Probe returned with Transport endpoint is not connected', '', '']) success_self = '\n'.join([ '' ' ', ' 0', ' 1', ' ', ' Probe on localhost not needed', '', '']) success_other = '\n'.join([ '' ' ', ' 0', ' 0', ' ', ' ', '', '']) success_hostname_after_ip = success_other success_ip_after_hostname = success_other success_already_peer = { 'ip': '\n'.join([ '' ' ', ' 0', ' 2', ' ', ' Host 10.0.0.2 port 24007 already in peer list', '', '']), 'hostname': '\n'.join([ '' ' ', ' 0', ' 2', ' ', ' Host server2 port 24007 already in peer list', '', ''])} success_reverse_already_peer = { 'ip': '\n'.join([ '' ' ', ' 0', ' 2', ' ', ' Host 10.0.0.1 port 24007 already in peer list', '', '']), 'hostname': '\n'.join([ '' ' ', ' 0', ' 2', ' ', ' Host server1 port 24007 already in peer list', '', ''])} success_first_hostname_from_second_first_time = success_reverse_already_peer[ 'hostname'] success_first_ip_from_second_first_time = success_other success_first_ip_from_second_second_time = success_reverse_already_peer[ 'ip'] xml_peer_present = """ 0 node02 node02.domain.dom 10.0.0.2 """ xml_volume_present = """ 0 Newvolume1 Newvolume2 """ xml_volume_absent = """ 0 0 """ xml_volume_status = """ 0 myvol1 3 node01 /tmp/foo 830700d7-0684-497c-a12c-c02e365fb90b 1 49155 49155 N/A 2470 NFS Server localhost 830700d7-0684-497c-a12c-c02e365fb90b 0 N/A N/A N/A -1 """ xml_volume_info_running = """ 0 myvol1 f03c2180-cf55-4f77-ae0b-3650f57c82a1 1 Started 1 1 1 1 0 0 0 Distribute 0 node01:/tmp/foonode01:/tmp/foo830700d7-0684-497c-a12c-c02e365fb90b 1 1 """ xml_volume_info_stopped = """ 0 myvol1 1 """ xml_command_success = """ 0 """ xml_command_fail = """ -1 0 Command Failed """ @skipIf(NO_MOCK, NO_MOCK_REASON) class GlusterfsTestCase(TestCase): ''' Test cases for salt.modules.glusterfs ''' # 'list_peers' function tests: 1 maxDiff = None def test_list_peers(self): ''' Test if it return a list of gluster peers ''' mock = MagicMock(return_value=xml_peer_present) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertDictEqual(glusterfs.list_peers(), { 'node02': ['node02.domain.dom', '10.0.0.2']}) mock = MagicMock(return_value=xml_command_success) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertIsNone(glusterfs.list_peers()) # 'peer' function tests: 1 def test_peer(self): ''' Test if it adds another node into the peer list. ''' # invalid characters mock = MagicMock(return_value=True) with patch.object(suc, 'check_name', mock): self.assertRaises(SaltInvocationError, glusterfs.peer, 'a') # version 3.4 # by hostname # peer failed unknown hostname # peer failed can't connect mock = MagicMock( return_value=GlusterResults.v34.peer_probe.fail_cant_connect) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises(CommandExecutionError, glusterfs.peer, 'server2') # peer self mock = MagicMock( return_value=GlusterResults.v34.peer_probe.success_self) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('server1'), {'exitval': '1', 'output': 'success: on localhost not needed'}) # peer added mock = MagicMock( return_value=GlusterResults.v34.peer_probe.success_other) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('server2'), {'exitval': '0', 'output': 'success'}) # peer already member mock = MagicMock( return_value=GlusterResults.v34.peer_probe.success_already_peer['hostname']) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('server2'), {'exitval': '2', 'output': 'success: host server2 port 24007 already in peer list'}) mock = MagicMock( return_value=GlusterResults.v34.peer_probe.success_already_peer['ip']) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('10.0.0.2'), {'exitval': '2', 'output': 'success: host 10.0.0.2 port 24007 already in peer list'}) # peer in reverse (probe server1 from server2) mock = MagicMock( return_value=GlusterResults.v34.peer_probe.success_first_hostname_from_second_first_time) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('server1'), {'exitval': '0', 'output': 'success'}) mock = MagicMock( return_value=GlusterResults.v34.peer_probe.success_first_hostname_from_second_second_time) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('server1'), {'exitval': '2', 'output': 'success: host server1 port 24007 already in peer list'}) # peer in reverse using ip address instead of hostname mock = MagicMock( return_value=GlusterResults.v34.peer_probe.success_reverse_already_peer['ip']) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('10.0.0.1'), {'exitval': '2', 'output': 'success: host 10.0.0.1 port 24007 already in peer list'}) # by ip address # peer self mock = MagicMock( return_value=GlusterResults.v34.peer_probe.success_self) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('10.0.0.1'), {'exitval': '1', 'output': 'success: on localhost not needed'}) # peer added mock = MagicMock( return_value=GlusterResults.v34.peer_probe.success_other) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('10.0.0.2'), {'exitval': '0', 'output': 'success'}) # peer already member mock = MagicMock( return_value=GlusterResults.v34.peer_probe.success_already_peer['ip']) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('10.0.0.2'), {'exitval': '2', 'output': 'success: host 10.0.0.2 port 24007 already in peer list'}) # version 3.7 # peer failed unknown hostname # peer failed can't connect mock = MagicMock( return_value=GlusterResults.v37.peer_probe.fail_cant_connect) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises(CommandExecutionError, glusterfs.peer, 'server2') # peer self mock = MagicMock( return_value=GlusterResults.v37.peer_probe.success_self) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('server1'), {'exitval': '1', 'output': 'Probe on localhost not needed'}) # peer added mock = MagicMock( return_value=GlusterResults.v37.peer_probe.success_other) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('server2'), {'exitval': '0', 'output': None}) # peer already member mock = MagicMock( return_value=GlusterResults.v37.peer_probe.success_already_peer['hostname']) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('server2'), {'exitval': '2', 'output': 'Host server2 port 24007 already in peer list'}) # peer in reverse # by ip address # peer added mock = MagicMock( return_value=GlusterResults.v37.peer_probe.success_other) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('10.0.0.2'), {'exitval': '0', 'output': None}) # peer already member mock = MagicMock( return_value=GlusterResults.v37.peer_probe.success_already_peer['ip']) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('10.0.0.2'), {'exitval': '2', 'output': 'Host 10.0.0.2 port 24007 already in peer list'}) # peer self mock = MagicMock( return_value=GlusterResults.v37.peer_probe.success_self) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('10.0.0.1'), {'exitval': '1', 'output': 'Probe on localhost not needed'}) # peer in reverse (probe server1 from server2) mock = MagicMock( return_value=GlusterResults.v37.peer_probe.success_first_hostname_from_second_first_time) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('server1'), {'exitval': '2', 'output': 'Host server1 port 24007 already in peer list'}) # peer in reverse using ip address instead of hostname first time mock = MagicMock( return_value=GlusterResults.v37.peer_probe.success_first_ip_from_second_first_time) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('10.0.0.1'), {'exitval': '0', 'output': None}) mock = MagicMock( return_value=GlusterResults.v37.peer_probe.success_first_ip_from_second_second_time) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.peer('10.0.0.1'), {'exitval': '2', 'output': 'Host 10.0.0.1 port 24007 already in peer list'}) # 'create' function tests: 1 def test_create(self): ''' Test if it create a glusterfs volume. ''' mock = MagicMock(return_value='') with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises( SaltInvocationError, glusterfs.create, 'newvolume', 'host1:brick') mock = MagicMock(return_value='') with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises( SaltInvocationError, glusterfs.create, 'newvolume', 'host1/brick') mock = MagicMock(return_value=xml_command_fail) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises( CommandExecutionError, glusterfs.create, 'newvolume', 'host1:/brick', True, True, True, 'tcp', True) mock = MagicMock(return_value=xml_command_success) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.create('newvolume', 'host1:/brick', True, True, True, 'tcp', True), 'Volume newvolume created and started') with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.create('newvolume', 'host1:/brick'), 'Volume newvolume created. Start volume to use') # 'list_volumes' function tests: 1 def test_list_volumes(self): ''' Test if it list configured volumes ''' mock = MagicMock(return_value=xml_volume_absent) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertListEqual(glusterfs.list_volumes(), []) mock = MagicMock(return_value=xml_volume_present) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertListEqual(glusterfs.list_volumes(), ['Newvolume1', 'Newvolume2']) # 'status' function tests: 1 def test_status(self): ''' Test if it check the status of a gluster volume. ''' mock = MagicMock(return_value=xml_command_fail) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises( CommandExecutionError, glusterfs.status, 'myvol1') res = {'bricks': { 'node01:/tmp/foo': { 'host': 'node01', 'hostname': 'node01', 'online': True, 'path': '/tmp/foo', 'peerid': '830700d7-0684-497c-a12c-c02e365fb90b', 'pid': '2470', 'port': '49155', 'ports': { 'rdma': 'N/A', 'tcp': '49155'}, 'status': '1'}}, 'healers': {}, 'nfs': { 'node01': { 'host': 'NFS Server', 'hostname': 'NFS Server', 'online': False, 'path': 'localhost', 'peerid': '830700d7-0684-497c-a12c-c02e365fb90b', 'pid': '-1', 'port': 'N/A', 'ports': { 'rdma': 'N/A', 'tcp': 'N/A'}, 'status': '0'}}} mock = MagicMock(return_value=xml_volume_status) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertDictEqual(glusterfs.status('myvol1'), res) # 'start_volume' function tests: 1 def test_volume_info(self): ''' Test if it returns the volume info. ''' res = {'myvol1': { 'brickCount': '1', 'bricks': { 'brick1': { 'hostUuid': '830700d7-0684-497c-a12c-c02e365fb90b', 'path': 'node01:/tmp/foo', 'uuid': '830700d7-0684-497c-a12c-c02e365fb90b'}}, 'disperseCount': '0', 'distCount': '1', 'id': 'f03c2180-cf55-4f77-ae0b-3650f57c82a1', 'name': 'myvol1', 'optCount': '1', 'options': { 'performance.readdir-ahead': 'on'}, 'redundancyCount': '0', 'replicaCount': '1', 'status': '1', 'statusStr': 'Started', 'stripeCount': '1', 'transport': '0', 'type': '0', 'typeStr': 'Distribute'}} mock = MagicMock(return_value=xml_volume_info_running) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertDictEqual(glusterfs.info('myvol1'), res) def test_start_volume(self): ''' Test if it start a gluster volume. ''' mock_list = MagicMock(return_value=['Newvolume1', 'Newvolume2']) with patch.object(glusterfs, 'list_volumes', mock_list): mock_status = MagicMock(return_value={'status': '1'}) with patch.object(glusterfs, 'info', mock_status): mock = MagicMock(return_value=xml_command_success) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.start_volume('Newvolume1'), 'Volume already started') mock_status = MagicMock(return_value={'status': '0'}) with patch.object(glusterfs, 'info', mock_status): mock_run = MagicMock(return_value=xml_command_success) with patch.dict(glusterfs.__salt__, {'cmd.run': mock_run}): self.assertEqual(glusterfs.start_volume('Newvolume1'), 'Volume Newvolume1 started') mock = MagicMock(return_value=xml_command_fail) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises( CommandExecutionError, glusterfs.start_volume, 'Newvolume1') # 'stop_volume' function tests: 1 def test_stop_volume(self): ''' Test if it stop a gluster volume. ''' mock = MagicMock(return_value={}) with patch.object(glusterfs, 'status', mock): mock = MagicMock(return_value=xml_command_success) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.stop_volume('Newvolume1'), 'Volume Newvolume1 stopped') mock = MagicMock(return_value=xml_command_fail) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises( CommandExecutionError, glusterfs.stop_volume, 'Newvolume1') mock = MagicMock(return_value=xml_command_fail) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises( CommandExecutionError, glusterfs.stop_volume, 'Newvolume1') # 'delete' function tests: 1 def test_delete(self): ''' Test if it deletes a gluster volume. ''' mock = MagicMock(return_value=['Newvolume1', 'Newvolume2']) with patch.object(glusterfs, 'list_volumes', mock): # volume doesn't exist self.assertRaises( SaltInvocationError, glusterfs.delete, 'Newvolume3') mock = MagicMock(return_value={'status': '1'}) with patch.object(glusterfs, 'info', mock): mock = MagicMock(return_value=xml_command_success) # volume exists, should not be stopped, and is started with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises( SaltInvocationError, glusterfs.delete, 'Newvolume1', False) # volume exists, should be stopped, and is started with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.delete('Newvolume1'), 'Volume Newvolume1 stopped and deleted') # volume exists and isn't started mock = MagicMock(return_value={'status': '0'}) with patch.object(glusterfs, 'info', mock): mock = MagicMock(return_value=xml_command_success) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.delete('Newvolume1'), 'Volume Newvolume1 deleted') # 'add_volume_bricks' function tests: 1 def test_add_volume_bricks(self): ''' Test if it add brick(s) to an existing volume ''' # volume does not exist mock = MagicMock(return_value=xml_command_fail) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertRaises( CommandExecutionError, glusterfs.add_volume_bricks, 'Newvolume1', ['bricks']) ret = '1 bricks successfully added to the volume Newvolume1' # volume does exist mock = MagicMock(return_value={'bricks': {}}) with patch.object(glusterfs, 'info', mock): mock = MagicMock(return_value=xml_command_success) # ... and the added brick does not exist with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): self.assertEqual(glusterfs.add_volume_bricks('Newvolume1', ['bricks']), ret) mock = MagicMock( return_value={'bricks': {'brick1': {'path': 'bricks'}}}) with patch.object(glusterfs, 'info', mock): # ... and the added brick does exist with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): # As a list self.assertEqual( glusterfs.add_volume_bricks( 'Newvolume1', ['bricks']), 'Bricks already in volume Newvolume1') # As a string self.assertEqual( glusterfs.add_volume_bricks( 'Newvolume1', 'bricks'), 'Bricks already in volume Newvolume1') # And empty list self.assertEqual(glusterfs.add_volume_bricks('Newvolume1', []), 'Bricks already in volume Newvolume1') if __name__ == '__main__': from integration import run_tests run_tests(GlusterfsTestCase, needs_daemon=False)