Ejemplo n.º 1
0
def main():
    module = AnsibleModule(
        argument_spec=dict(
            file=dict(required=True),
            remote_path=dict(),
            hostname=dict(required=True),
            username=dict(required=True),
            password=dict(required=True),
            port=dict(type='int', default=830)
        ),
        supports_check_mode=False
    )

    if not HAS_PYHP:
        safe_fail(module, msg='There was a problem loading from the pyhpecw7 '
                  + 'module.', error=str(ie))

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

    device = HPCOM7(host=hostname, username=username,
                    password=password, port=port, timeout=120)

    src = module.params.get('file')
    dst = module.params.get('remote_path')

    changed = False

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

    try:
        file_copy = FileCopy(device, src, dst)
        if not file_copy.file_already_exists():
            if not file_copy.remote_dir_exists:
                file_copy.create_remote_dir()
            file_copy.transfer_file()
            changed = True
    except PYHPError as fe:
        safe_fail(module, device, msg=str(fe),
                  descr='Error transferring file.')

    results = {}
    results['source_file'] = file_copy.src
    results['destination_file'] = file_copy.dst
    results['changed'] = changed

    safe_exit(module, device, **results)
Ejemplo n.º 2
0
def main():
    module = AnsibleModule(
        argument_spec=dict(
            ipe_package=dict(),
            boot=dict(),
            system=dict(),
            remote_dir=dict(default="flash:/"),
            delete_ipe=dict(choices=BOOLEANS, type="bool", default=False),
            reboot=dict(required=True, choices=BOOLEANS, type="bool"),
            delay=dict(type="str"),
            hostname=dict(required=True),
            username=dict(required=True),
            password=dict(required=True),
            port=dict(type="int", default=830),
        ),
        supports_check_mode=True,
    )

    if not HAS_PYHP:
        safe_fail(module, msg="There was a problem loading from the pyhpecw7 " + "module.", error=str(ie))

    ipe_package = module.params.get("ipe_package")
    boot = module.params.get("boot")
    system = module.params.get("system")

    if ipe_package:
        if boot or system:
            module.fail_json(msg="ipe_package and boot/system parameters are mutually exclusive")
    else:
        if not (boot and system):
            module.fail_json(msg="boot and system parameters must be provided if ipe_package is not")

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

    device = HPCOM7(host=hostname, username=username, password=password, port=port, timeout=150)

    changed = False

    reboot = module.params.get("reboot")
    delay = module.params.get("delay")
    already_set = False
    transfered = False

    try:
        device.open()
    except ConnectionError as e:
        safe_fail(module, device, msg=str(e), descr="Error opening connection to device.")

    try:
        ios = InstallOs(device)
        existing = ios.get_config()
    except PYHPError:
        safe_fail(module, device, msg=str(e), descr="Error getting current config.")

    existing_boot = existing["startup-primary"]["boot"]
    existing_system = existing["startup-primary"]["system"]
    remote_dir = module.params["remote_dir"]

    if ipe_package:
        ipe_basename = os.path.basename(ipe_package)
        ipe_boot_sys = re.split("-|\.", ipe_basename)[-3:-1]
        if ipe_boot_sys:
            if (
                ipe_boot_sys[0].lower() in existing_boot.lower()
                and ipe_boot_sys[0].lower() in existing_system.lower()
                and ipe_boot_sys[1].lower() in existing_boot.lower()
                and ipe_boot_sys[1].lower() in existing_system.lower()
            ):
                already_set = True

        ipe_dst = remote_dir + ipe_basename
        try:
            # preps transfer and checks if source file exists
            ipe_file_copy = FileCopy(device, ipe_package, ipe_dst)
        except PYHPError as fe:
            safe_fail(module, device, msg=str(fe), descr="Error preparing IPE file transfer.")

        if not ipe_file_copy.file_already_exists():
            try:
                ipe_file_copy.transfer_file()
                transfered = True
            except PYHPError as fe:
                safe_fail(module, device, msg=str(fe), descr="Error transfering IPE file.")

        if not already_set:
            delete_ipe = module.params.get("delete_ipe")
            ios.build("ipe", ipe=ipe_file_copy.dst, delete_ipe=delete_ipe, stage=True)
    elif boot:
        boot_basename = os.path.basename(boot)
        system_basename = os.path.basename(system)
        if boot_basename in existing_boot and system_basename in existing_system:
            already_set = True

        boot_dst = remote_dir + boot_basename
        try:
            # preps transfer and checks if source file exists
            boot_file_copy = FileCopy(device, boot, boot_dst)
        except PYHPError as fe:
            safe_fail(module, device, msg=str(fe), descr="Error preparing boot file transfer.")

        system_dst = remote_dir + system_basename
        try:
            # preps transfer and checks if source file exists
            system_file_copy = FileCopy(device, system, system_dst)
        except PYHPError as fe:
            safe_fail(module, device, msg=str(fe), descr="Error preparing system file transfer.")

        if not boot_file_copy.file_already_exists():
            try:
                boot_file_copy.transfer_file()
                transfered = True
            except PYHPError as fe:
                safe_fail(module, device, msg=str(fe), descr="Error transfering boot file.")

        if not system_file_copy.file_already_exists():
            try:
                system_file_copy.transfer_file()
                transfered = True
            except PYHPError as fe:
                safe_fail(module, device, msg=str(fe), descr="Error transfering system file.")

        if not already_set:
            ios.build("bootsys", boot=boot_file_copy.dst, system=system_file_copy.dst, stage=True)

    commands = None
    end_state = existing

    reboot_attempt = "no"
    if device.staged or transfered:
        if reboot and delay:
            reboot_attempt = "yes"
            os_reboot = Reboot(device)
            os_reboot.build(stage=True, reboot=True, delay=delay)
        commands = device.staged_to_string()
        if module.check_mode:
            safe_exit(module, device, changed=True, commands=commands, transfered=transfered, end_state=end_state)
        else:
            try:
                device.execute_staged()
                end_state = ios.get_config()
            except PYHPError as e:
                safe_fail(module, device, msg=str(e), descr="Error executing commands.")
            changed = True

    results = {}
    results["commands"] = commands
    results["transfered"] = transfered
    results["changed"] = changed
    results["end_state"] = end_state

    if reboot and not delay:
        reboot_attempt = "yes"
        try:
            device.reboot()
            changed = True

            # for some reason,
            # this is needed to activate the reboot
            try:
                device.close()
            except PYHPError:
                pass
        except PYHPError as e:
            safe_fail(module, device, msg=str(e), descr="Error rebooting the device.")

    results["reboot_attempt"] = reboot_attempt
    safe_exit(module, device, **results)
def main():
    module = AnsibleModule(argument_spec=dict(
        ipe_package=dict(),
        boot=dict(),
        system=dict(),
        remote_dir=dict(default='flash:/'),
        delete_ipe=dict(choices=BOOLEANS, type='bool', default=False),
        reboot=dict(required=True, choices=BOOLEANS, type='bool'),
        delay=dict(type='str'),
        hostname=dict(required=True),
        username=dict(required=True),
        password=dict(required=True),
        port=dict(type='int', default=830)),
                           supports_check_mode=True)

    if not HAS_PYHP:
        safe_fail(module,
                  msg='There was a problem loading from the pyhpecw7 ' +
                  'module.',
                  error=str(ie))

    ipe_package = module.params.get('ipe_package')
    boot = module.params.get('boot')
    system = module.params.get('system')

    if ipe_package:
        if boot or system:
            module.fail_json(
                msg=
                'ipe_package and boot/system parameters are mutually exclusive'
            )
    else:
        if not (boot and system):
            module.fail_json(
                msg=
                'boot and system parameters must be provided if ipe_package is not'
            )

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

    device = HPCOM7(host=hostname,
                    username=username,
                    password=password,
                    port=port,
                    timeout=150)

    changed = False

    reboot = module.params.get('reboot')
    delay = module.params.get('delay')
    already_set = False
    transfered = False

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

    try:
        ios = InstallOs(device)
        existing = ios.get_config()
    except PYHPError:
        safe_fail(module,
                  device,
                  msg=str(e),
                  descr='Error getting current config.')

    existing_boot = existing['startup-primary']['boot']
    existing_system = existing['startup-primary']['system']
    remote_dir = module.params['remote_dir']
    current_boot_file = remote_dir + existing_boot
    current_sys_file = remote_dir + existing_system

    if ipe_package:
        ipe_basename = os.path.basename(ipe_package)
        ipe_boot_sys = re.split('-|\.', ipe_basename)[-3:-1]
        if ipe_boot_sys:
            if ipe_boot_sys[0].lower() in existing_boot.lower()\
                    and ipe_boot_sys[0].lower() in existing_system.lower()\
                    and ipe_boot_sys[1].lower() in existing_boot.lower()\
                    and ipe_boot_sys[1].lower() in existing_system.lower():
                already_set = True

        ipe_dst = remote_dir + ipe_basename
        try:
            # preps transfer and checks if source file exists
            ipe_file_copy = FileCopy(device, ipe_package, ipe_dst)
        except PYHPError as fe:
            safe_fail(module,
                      device,
                      msg=str(fe),
                      descr='Error preparing IPE file transfer.')

        if not ipe_file_copy.file_already_exists():
            try:
                ipe_file_copy.transfer_file()
                transfered = True
            except PYHPError as fe:
                safe_fail(module,
                          device,
                          msg=str(fe),
                          descr='Error transfering IPE file.')

        if not already_set:
            delete_ipe = module.params.get('delete_ipe')
            ios.build('ipe',
                      ipe=ipe_file_copy.dst,
                      delete_ipe=delete_ipe,
                      stage=True)
            # set current boot/sys files as backup startup images
            ios.build('bootsys',
                      boot=current_boot_file,
                      system=current_sys_file,
                      startup_type='2',
                      stage=True)
    elif boot:
        boot_basename = os.path.basename(boot)
        system_basename = os.path.basename(system)
        if boot_basename in existing_boot\
                and system_basename in existing_system:
            already_set = True

        boot_dst = remote_dir + boot_basename
        try:
            # preps transfer and checks if source file exists
            boot_file_copy = FileCopy(device, boot, boot_dst)
        except PYHPError as fe:
            safe_fail(module,
                      device,
                      msg=str(fe),
                      descr='Error preparing boot file transfer.')

        system_dst = remote_dir + system_basename
        try:
            # preps transfer and checks if source file exists
            system_file_copy = FileCopy(device, system, system_dst)
        except PYHPError as fe:
            safe_fail(module,
                      device,
                      msg=str(fe),
                      descr='Error preparing system file transfer.')

        if not boot_file_copy.file_already_exists():
            try:
                boot_file_copy.transfer_file()
                transfered = True
            except PYHPError as fe:
                safe_fail(module,
                          device,
                          msg=str(fe),
                          descr='Error transfering boot file.')

        if not system_file_copy.file_already_exists():
            try:
                system_file_copy.transfer_file()
                transfered = True
            except PYHPError as fe:
                safe_fail(module,
                          device,
                          msg=str(fe),
                          descr='Error transfering system file.')

        if not already_set:
            ios.build('bootsys',
                      boot=boot_file_copy.dst,
                      system=system_file_copy.dst,
                      stage=True)
            # set current boot/sys files as backup startup images
            ios.build('bootsys',
                      boot=current_boot_file,
                      system=current_sys_file,
                      startup_type='2',
                      stage=True)

    commands = None
    end_state = existing

    reboot_attempt = 'no'
    if device.staged or transfered:
        if reboot and delay:
            reboot_attempt = 'yes'
            os_reboot = Reboot(device)
            os_reboot.build(stage=True, reboot=True, delay=delay)
        commands = device.staged_to_string()
        if module.check_mode:
            safe_exit(module,
                      device,
                      changed=True,
                      commands=commands,
                      transfered=transfered,
                      end_state=end_state)
        else:
            try:
                device.execute_staged()
                end_state = ios.get_config()
            except PYHPError as e:
                safe_fail(module,
                          device,
                          msg=str(e),
                          descr='Error executing commands.')
            changed = True

    results = {}
    results['commands'] = commands
    results['transfered'] = transfered
    results['changed'] = changed
    results['end_state'] = end_state

    if reboot and not delay:
        reboot_attempt = 'yes'
        try:
            device.reboot()
            changed = True

            # for some reason,
            # this is needed to activate the reboot
            try:
                device.close()
            except PYHPError:
                pass
        except PYHPError as e:
            safe_fail(module,
                      device,
                      msg=str(e),
                      descr='Error rebooting the device.')

    results['reboot_attempt'] = reboot_attempt
    safe_exit(module, device, **results)
Ejemplo n.º 4
0
class FileCopyTestCase(BaseFeatureCase):

    @mock.patch('pyhpecw7.comware.HPCOM7')
    def setUp(self, mock_device):
        self.device = mock_device
        self.file_copy = FileCopy(self.device, SOURCE_FILE)

    def test_init(self):
        self.assertEqual(self.file_copy._remote_dir, 'flash:/')
        self.assertEqual(self.file_copy.src, SOURCE_FILE)
        self.assertEqual(self.file_copy.dst, 'flash:/file.txt')
        self.assertEqual(self.file_copy.port, 22)
        self.assertEqual(self.file_copy.remote_dir_exists, True)

    def test_get_flash_size(self):
        self.device.cli_display.return_value = self.read_cli_display('dir_flash')
        result = self.file_copy._get_flash_size()

        self.assertEqual(result, 742204000)

        self.device.cli_display.return_value = 'garbaldigook'
        result = self.file_copy._get_flash_size()

        self.assertEqual(result, 0)

    @mock.patch.object(FileCopy, '_get_flash_size')
    @mock.patch('os.path.getsize')
    def test_enough_space(self, mock_getsize, mock_get_flash_size):
        mock_getsize.return_value = 2
        mock_get_flash_size.return_value = 1

        with self.assertRaises(FileNotEnoughSpaceError):
            self.file_copy._enough_space()

        mock_getsize.return_value = 1
        mock_get_flash_size.return_value = 2

        result = self.file_copy._enough_space()
        self.assertEqual(result, None)

    @mock.patch.object(FileCopy, '_get_remote_md5')
    @mock.patch.object(FileCopy, '_get_local_md5')
    def test_file_already_exists(self, mock_local_md5, mock_remote_md5):
        mock_local_md5.return_value = 'abc123'
        mock_remote_md5.return_value = 'abc123'

        result = self.file_copy.file_already_exists()
        self.assertEqual(result, True)

        self.file_copy.remote_dir_exists = False
        result = self.file_copy.file_already_exists()
        self.assertEqual(result, False)

        self.file_copy.remote_dir_exists = True
        mock_remote_md5.return_value = None
        result = self.file_copy.file_already_exists()
        self.assertEqual(result, False)

        mock_remote_md5.side_effect = NCError
        result = self.file_copy.file_already_exists()
        self.assertEqual(result, False)

    @mock.patch.object(__builtin__, 'open')
    def test_safety_checks_file_not_readable(self, mock_open):
        mock_open.side_effect = IOError
        with self.assertRaises(FileNotReadableError):
            self.file_copy._safety_checks()

    @mock.patch.object(__builtin__, 'open')
    def test_safety_checks_no_remote_dir(self, mock_open):
        self.file_copy.remote_dir_exists = False
        with self.assertRaises(FileRemoteDirDoesNotExist):
            self.file_copy._safety_checks()

    @mock.patch.object(__builtin__, 'open')
    def test_safety_checks_no_remote_dir(self, mock_open):
        self.file_copy.remote_dir_exists = False
        with self.assertRaises(FileRemoteDirDoesNotExist):
            self.file_copy._safety_checks()

    @mock.patch.object(FileCopy, 'file_already_exists')
    @mock.patch.object(FileCopy, '_enough_space')
    @mock.patch.object(__builtin__, 'open')
    def test_safety_checks_no_remote_dir(self, mock_open, mock_enough_space, mock_file_already_exists):
        mock_file_already_exists.return_value = False
        self.file_copy._safety_checks()
        mock_enough_space.assert_called_with()

    def test_remote_md5(self):
        expected_get, get_reply = self.xml_action_and_reply('file_copy_remote_md5')
        self.device.action.return_value = get_reply

        expected = '44d5527772e1b9841f99cb03f31cbc1c'
        result = self.file_copy._get_remote_md5()

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

    def test_local_md5(self):
        test_file = NamedTemporaryFile()
        self.file_copy.src = test_file.name

        test_file.write('Test content.')
        test_file.flush()

        result = self.file_copy._get_local_md5()
        self.assertEqual(result, 'bcb898f62d9e1ac765c77e6804cbd872')

        test_file.close()

    def test_remote_dir(self):
        expected_get, get_reply = self.xml_get_and_reply('file_copy_remote_dir')
        self.device.get.return_value = get_reply

        expected = True
        result = self.file_copy._remote_dir_exists()

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


    @mock.patch('pyhpecw7.features.file_copy.paramiko')
    @mock.patch('pyhpecw7.features.file_copy.SCPClient')
    @mock.patch.object(FileCopy, '_safety_checks')
    @mock.patch.object(FileCopy, '_get_local_md5')
    @mock.patch.object(FileCopy, '_get_remote_md5')
    def test_transfer_file(self, mock_remote_md5, mock_local_md5, mock_safety_checks, mock_SCP, mock_paramiko):
        mock_remote_md5.return_value = 'abc'
        mock_local_md5.return_value = 'abc'

        mock_ssh = mock_paramiko.SSHClient.return_value

        self.file_copy.transfer_file()

        mock_paramiko.SSHClient.assert_called_with()

        mock_ssh.set_missing_host_key_policy.assert_called_with(mock_paramiko.AutoAddPolicy.return_value)
        mock_ssh.connect.assert_called_with(allow_agent=False,
                                             hostname=self.device.host,
                                             look_for_keys=False,
                                             password=self.device.password,
                                             port=22,
                                             username=self.device.username)

        mock_SCP.assert_called_with(mock_ssh.get_transport.return_value)
        mock_SCP.return_value.put.assert_called_with('/path/to/source/file.txt', 'flash:/file.txt')
        mock_SCP.return_value.close.assert_called_with()

    @mock.patch('pyhpecw7.features.file_copy.paramiko')
    @mock.patch('pyhpecw7.features.file_copy.SCPClient')
    @mock.patch.object(FileCopy, '_safety_checks')
    @mock.patch.object(FileCopy, '_get_local_md5')
    @mock.patch.object(FileCopy, '_get_remote_md5')
    def test_transfer_file_mismatch_hash(self, mock_remote_md5, mock_local_md5, mock_safety_checks, mock_SCP, mock_paramiko):
        mock_remote_md5.return_value = 'abc'
        mock_local_md5.return_value = 'def'

        mock_ssh = mock_paramiko.SSHClient.return_value

        with self.assertRaises(FileHashMismatchError):
            self.file_copy.transfer_file()

        mock_paramiko.SSHClient.assert_called_with()

        mock_ssh.set_missing_host_key_policy.assert_called_with(mock_paramiko.AutoAddPolicy.return_value)
        mock_ssh.connect.assert_called_with(allow_agent=False,
                                             hostname=self.device.host,
                                             look_for_keys=False,
                                             password=self.device.password,
                                             port=22,
                                             username=self.device.username)

        mock_SCP.assert_called_with(mock_ssh.get_transport.return_value)
        mock_SCP.return_value.put.assert_called_with('/path/to/source/file.txt', 'flash:/file.txt')
        mock_SCP.return_value.close.assert_called_with()

    @mock.patch('pyhpecw7.features.file_copy.paramiko')
    @mock.patch('pyhpecw7.features.file_copy.SCPClient')
    @mock.patch.object(FileCopy, '_safety_checks')
    @mock.patch.object(FileCopy, '_get_local_md5')
    @mock.patch.object(FileCopy, '_get_remote_md5')
    def test_transfer_file_error(self, mock_remote_md5, mock_local_md5, mock_safety_checks, mock_SCP, mock_paramiko):
        mock_remote_md5.return_value = 'abc'
        mock_local_md5.return_value = 'def'

        mock_ssh = mock_paramiko.SSHClient.return_value

        mock_SCP.return_value.put.side_effect = Exception

        with self.assertRaises(FileTransferError):
            self.file_copy.transfer_file()

        mock_paramiko.SSHClient.assert_called_with()

        mock_ssh.set_missing_host_key_policy.assert_called_with(mock_paramiko.AutoAddPolicy.return_value)
        mock_ssh.connect.assert_called_with(allow_agent=False,
                                             hostname=self.device.host,
                                             look_for_keys=False,
                                             password=self.device.password,
                                             port=22,
                                             username=self.device.username)

        mock_SCP.assert_called_with(mock_ssh.get_transport.return_value)
        mock_SCP.return_value.put.assert_called_with('/path/to/source/file.txt', 'flash:/file.txt')


    def test_create_dir(self):
        self.file_copy._remote_dir = 'flash:/unit/'

        expected_get, get_reply = self.xml_action_and_reply('file_copy_create_remote_dir')
        self.device.action.return_value = get_reply

        expected = None
        result = self.file_copy.create_remote_dir()

        self.assertEqual(result, expected)
        self.assert_action_request(expected_get)
Ejemplo n.º 5
0
class FileCopyTestCase(BaseFeatureCase):
    @mock.patch('pyhpecw7.comware.HPCOM7')
    def setUp(self, mock_device):
        self.device = mock_device
        self.file_copy = FileCopy(self.device, SOURCE_FILE)

    def test_init(self):
        self.assertEqual(self.file_copy._remote_dir, 'flash:/')
        self.assertEqual(self.file_copy.src, SOURCE_FILE)
        self.assertEqual(self.file_copy.dst, 'flash:/file.txt')
        self.assertEqual(self.file_copy.port, 22)
        self.assertEqual(self.file_copy.remote_dir_exists, True)

    def test_get_flash_size(self):
        self.device.cli_display.return_value = self.read_cli_display(
            'dir_flash')
        result = self.file_copy._get_flash_size()

        self.assertEqual(result, 742204000)

        self.device.cli_display.return_value = 'garbaldigook'
        result = self.file_copy._get_flash_size()

        self.assertEqual(result, 0)

    @mock.patch.object(FileCopy, '_get_flash_size')
    @mock.patch('os.path.getsize')
    def test_enough_space(self, mock_getsize, mock_get_flash_size):
        mock_getsize.return_value = 2
        mock_get_flash_size.return_value = 1

        with self.assertRaises(FileNotEnoughSpaceError):
            self.file_copy._enough_space()

        mock_getsize.return_value = 1
        mock_get_flash_size.return_value = 2

        result = self.file_copy._enough_space()
        self.assertEqual(result, None)

    @mock.patch.object(FileCopy, '_get_remote_md5')
    @mock.patch.object(FileCopy, '_get_local_md5')
    def test_file_already_exists(self, mock_local_md5, mock_remote_md5):
        mock_local_md5.return_value = 'abc123'
        mock_remote_md5.return_value = 'abc123'

        result = self.file_copy.file_already_exists()
        self.assertEqual(result, True)

        self.file_copy.remote_dir_exists = False
        result = self.file_copy.file_already_exists()
        self.assertEqual(result, False)

        self.file_copy.remote_dir_exists = True
        mock_remote_md5.return_value = None
        result = self.file_copy.file_already_exists()
        self.assertEqual(result, False)

        mock_remote_md5.side_effect = NCError
        result = self.file_copy.file_already_exists()
        self.assertEqual(result, False)

    @mock.patch.object(__builtin__, 'open')
    def test_safety_checks_file_not_readable(self, mock_open):
        mock_open.side_effect = IOError
        with self.assertRaises(FileNotReadableError):
            self.file_copy._safety_checks()

    @mock.patch.object(__builtin__, 'open')
    def test_safety_checks_no_remote_dir(self, mock_open):
        self.file_copy.remote_dir_exists = False
        with self.assertRaises(FileRemoteDirDoesNotExist):
            self.file_copy._safety_checks()

    @mock.patch.object(__builtin__, 'open')
    def test_safety_checks_no_remote_dir(self, mock_open):
        self.file_copy.remote_dir_exists = False
        with self.assertRaises(FileRemoteDirDoesNotExist):
            self.file_copy._safety_checks()

    @mock.patch.object(FileCopy, 'file_already_exists')
    @mock.patch.object(FileCopy, '_enough_space')
    @mock.patch.object(__builtin__, 'open')
    def test_safety_checks_no_remote_dir(self, mock_open, mock_enough_space,
                                         mock_file_already_exists):
        mock_file_already_exists.return_value = False
        self.file_copy._safety_checks()
        mock_enough_space.assert_called_with()

    def test_remote_md5(self):
        expected_get, get_reply = self.xml_action_and_reply(
            'file_copy_remote_md5')
        self.device.action.return_value = get_reply

        expected = '44d5527772e1b9841f99cb03f31cbc1c'
        result = self.file_copy._get_remote_md5()

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

    def test_local_md5(self):
        test_file = NamedTemporaryFile()
        self.file_copy.src = test_file.name

        test_file.write('Test content.'.encode('ascii'))
        test_file.flush()

        result = self.file_copy._get_local_md5()
        self.assertEqual(result, 'bcb898f62d9e1ac765c77e6804cbd872')

        test_file.close()

    def test_remote_dir(self):
        expected_get, get_reply = self.xml_get_and_reply(
            'file_copy_remote_dir')
        self.device.get.return_value = get_reply

        expected = True
        result = self.file_copy._remote_dir_exists()

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

    @mock.patch('pyhpecw7.features.file_copy.paramiko')
    @mock.patch('pyhpecw7.features.file_copy.SCPClient')
    @mock.patch.object(FileCopy, '_safety_checks')
    @mock.patch.object(FileCopy, '_get_local_md5')
    @mock.patch.object(FileCopy, '_get_remote_md5')
    def test_transfer_file(self, mock_remote_md5, mock_local_md5,
                           mock_safety_checks, mock_SCP, mock_paramiko):
        mock_remote_md5.return_value = 'abc'
        mock_local_md5.return_value = 'abc'

        mock_ssh = mock_paramiko.SSHClient.return_value

        self.file_copy.transfer_file()

        mock_paramiko.SSHClient.assert_called_with()

        mock_ssh.set_missing_host_key_policy.assert_called_with(
            mock_paramiko.AutoAddPolicy.return_value)
        mock_ssh.connect.assert_called_with(allow_agent=False,
                                            hostname=self.device.host,
                                            look_for_keys=False,
                                            password=self.device.password,
                                            port=22,
                                            username=self.device.username)

        mock_SCP.assert_called_with(mock_ssh.get_transport.return_value)
        mock_SCP.return_value.put.assert_called_with(
            '/path/to/source/file.txt', 'flash:/file.txt')
        mock_SCP.return_value.close.assert_called_with()

    @mock.patch('pyhpecw7.features.file_copy.paramiko')
    @mock.patch('pyhpecw7.features.file_copy.SCPClient')
    @mock.patch.object(FileCopy, '_safety_checks')
    @mock.patch.object(FileCopy, '_get_local_md5')
    @mock.patch.object(FileCopy, '_get_remote_md5')
    def test_transfer_file_mismatch_hash(self, mock_remote_md5, mock_local_md5,
                                         mock_safety_checks, mock_SCP,
                                         mock_paramiko):
        mock_remote_md5.return_value = 'abc'
        mock_local_md5.return_value = 'def'

        mock_ssh = mock_paramiko.SSHClient.return_value

        with self.assertRaises(FileHashMismatchError):
            self.file_copy.transfer_file()

        mock_paramiko.SSHClient.assert_called_with()

        mock_ssh.set_missing_host_key_policy.assert_called_with(
            mock_paramiko.AutoAddPolicy.return_value)
        mock_ssh.connect.assert_called_with(allow_agent=False,
                                            hostname=self.device.host,
                                            look_for_keys=False,
                                            password=self.device.password,
                                            port=22,
                                            username=self.device.username)

        mock_SCP.assert_called_with(mock_ssh.get_transport.return_value)
        mock_SCP.return_value.put.assert_called_with(
            '/path/to/source/file.txt', 'flash:/file.txt')
        mock_SCP.return_value.close.assert_called_with()

    @mock.patch('pyhpecw7.features.file_copy.paramiko')
    @mock.patch('pyhpecw7.features.file_copy.SCPClient')
    @mock.patch.object(FileCopy, '_safety_checks')
    @mock.patch.object(FileCopy, '_get_local_md5')
    @mock.patch.object(FileCopy, '_get_remote_md5')
    def test_transfer_file_error(self, mock_remote_md5, mock_local_md5,
                                 mock_safety_checks, mock_SCP, mock_paramiko):
        mock_remote_md5.return_value = 'abc'
        mock_local_md5.return_value = 'def'

        mock_ssh = mock_paramiko.SSHClient.return_value

        mock_SCP.return_value.put.side_effect = Exception

        with self.assertRaises(FileTransferError):
            self.file_copy.transfer_file()

        mock_paramiko.SSHClient.assert_called_with()

        mock_ssh.set_missing_host_key_policy.assert_called_with(
            mock_paramiko.AutoAddPolicy.return_value)
        mock_ssh.connect.assert_called_with(allow_agent=False,
                                            hostname=self.device.host,
                                            look_for_keys=False,
                                            password=self.device.password,
                                            port=22,
                                            username=self.device.username)

        mock_SCP.assert_called_with(mock_ssh.get_transport.return_value)
        mock_SCP.return_value.put.assert_called_with(
            '/path/to/source/file.txt', 'flash:/file.txt')

    def test_create_dir(self):
        self.file_copy._remote_dir = 'flash:/unit/'

        expected_get, get_reply = self.xml_action_and_reply(
            'file_copy_create_remote_dir')
        self.device.action.return_value = get_reply

        expected = None
        result = self.file_copy.create_remote_dir()

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