-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add sftp storage * update readme * add unit test sample config * clean unit test * add sftp documentation, improve gcs documentation * hide progess bar for write_file_command + fix raise ValueError
- Loading branch information
1 parent
2e9e3ab
commit 6622f52
Showing
11 changed files
with
302 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
SFTP | ||
==================== | ||
|
||
Accessing a SFTP drive. | ||
|
||
Installation | ||
------------ | ||
|
||
Use extras `sftp` to install all required packages. | ||
|
||
|
||
.. code-block:: shell | ||
$ pip install mara-storage[sftp] | ||
Configuration examples | ||
---------------------- | ||
|
||
.. tabs:: | ||
|
||
.. group-tab:: User and password login | ||
|
||
.. code-block:: python | ||
import mara_storage.storages | ||
mara_storage.config.storages = lambda: { | ||
'data': mara_storage.storages.SftpStorage( | ||
host="<your_sftp_host>", | ||
user="<your_login_user>", | ||
password="<your_secure_user_password>", | ||
# optional: | ||
insecure = True # allow insegure SSL connections and transfers | ||
} | ||
.. group-tab:: Private key file | ||
.. code-block:: python | ||
import mara_storage.storages | ||
mara_storage.config.storages = lambda: { | ||
'data': mara_storage.storages.SftpStorage( | ||
host="<your_sftp_host>", | ||
user="<your_login_user>", | ||
identity_file="~/.ssh/id_rsa", # path to your private key file | ||
public_identity_file="~/.ssh/id_rsa.pub", # path to your public key file | ||
# optional: | ||
insecure = True # allow insegure SSL connections and transfers | ||
} | ||
| | ||
| | ||
API reference | ||
------------- | ||
This section contains database specific API in the module. | ||
Configuration | ||
~~~~~~~~~~~~~ | ||
.. module:: mara_storage.storages | ||
:noindex: | ||
.. autoclass:: SftpStorage | ||
:special-members: __init__ | ||
:inherited-members: | ||
:members: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import pysftp | ||
|
||
from mara_storage import storages | ||
|
||
|
||
def connection(storage: storages.SftpStorage): | ||
return pysftp.Connection(host=storage.host, | ||
port=storage.port if storage.port else 22, | ||
username=storage.user, | ||
password=storage.password) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import datetime | ||
import pathlib | ||
import pytest | ||
import subprocess | ||
|
||
from mara_storage.compression import Compression, compressor, file_extension as compression_file_extension | ||
from mara_storage.client import StorageClient | ||
from mara_storage import storages, info, shell, manage | ||
|
||
|
||
from .local_config import SFTP_HOST, SFTP_PORT, SFTP_USERNAME, SFTP_PASSWORD, SFTP_INSECURE, SFTP_IDENTITY_FILE, SFTP_PUBLIC_IDENTITY_FILE | ||
|
||
TEST_TOUCH_FILE_NAME = 'empty-file.txt' | ||
TEST_FILE_NOT_EXISTS_FILE_NAME = 'file-does-not-exist.txt' | ||
TEST_READ_FILE_NAME = 'read_test.txt' | ||
TEST_WRITE_FILE_NAME = 'write_test.txt' | ||
TEST_CONTENT = 'THIS IS A TEST CONTENT' | ||
|
||
if not SFTP_HOST: | ||
pytest.skip("skipping SFTP tests: variable SFTP_HOST not set in tests/local_config.py", allow_module_level=True) | ||
|
||
|
||
@pytest.fixture | ||
def storage(): | ||
return storages.SftpStorage(host=SFTP_HOST, port=SFTP_PORT, user=SFTP_USERNAME, password=SFTP_PASSWORD, | ||
insecure=SFTP_INSECURE, identity_file=SFTP_IDENTITY_FILE, | ||
public_identity_file=SFTP_PUBLIC_IDENTITY_FILE) | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
def test_before_and_after(storage: object): | ||
#manage.ensure_storage(storage) | ||
yield | ||
#manage.drop_storage(storage, force=True) | ||
|
||
|
||
def test_file_exists(storage: object): | ||
assert isinstance(storage, storages.SftpStorage) | ||
|
||
# prepare | ||
write_commnand = shell.write_file_command(storage, TEST_TOUCH_FILE_NAME) | ||
(exitcode, _) = subprocess.getstatusoutput(f"echo '' | {write_commnand}") | ||
assert exitcode == 0 | ||
assert info.file_exists(storage, TEST_TOUCH_FILE_NAME) | ||
|
||
# test | ||
assert info.file_exists(storage, file_name=TEST_TOUCH_FILE_NAME) | ||
assert not info.file_exists(storage, file_name=TEST_FILE_NOT_EXISTS_FILE_NAME) | ||
|
||
# clean up test | ||
delete_command = shell.delete_file_command(storage, TEST_TOUCH_FILE_NAME) | ||
(exitcode, _) = subprocess.getstatusoutput(delete_command) | ||
assert exitcode == 0 | ||
|
||
|
||
def test_read_file_command(storage: object): | ||
assert isinstance(storage, storages.SftpStorage) | ||
|
||
# prepare | ||
compressions = [ | ||
Compression.NONE] | ||
write_commnand = shell.write_file_command(storage, TEST_READ_FILE_NAME) | ||
(exitcode, _) = subprocess.getstatusoutput(f'echo "{TEST_CONTENT}" | {write_commnand}') | ||
assert exitcode == 0 | ||
assert info.file_exists(storage, TEST_READ_FILE_NAME) | ||
|
||
for compression in compressions: | ||
if compression == Compression.NONE: | ||
continue | ||
raise NotImplementedError() | ||
|
||
# test | ||
for compression in compressions: | ||
print(f'Test compression: {compression}') | ||
file_extension = compression_file_extension(compression) | ||
file_extension = f'.{file_extension}' if file_extension else '' | ||
command = shell.read_file_command(storage, file_name=f'{TEST_READ_FILE_NAME}{file_extension}', compression=compression) | ||
assert command | ||
|
||
(exitcode, stdout) = subprocess.getstatusoutput(command) | ||
assert exitcode == 0 | ||
assert stdout == TEST_CONTENT | ||
|
||
|
||
def test_write_file_command(storage: object): | ||
assert isinstance(storage, storages.SftpStorage) | ||
|
||
command = shell.write_file_command(storage, file_name=TEST_WRITE_FILE_NAME) | ||
assert command | ||
|
||
(exitcode, _) = subprocess.getstatusoutput(f'echo "{TEST_CONTENT}" | {command}') | ||
assert exitcode == 0 | ||
|
||
assert info.file_exists(storage, file_name=TEST_WRITE_FILE_NAME) | ||
|
||
def test_delete_file_command(storage: object): | ||
assert isinstance(storage, storages.SftpStorage) | ||
|
||
# prepare | ||
write_commnand = shell.write_file_command(storage, TEST_TOUCH_FILE_NAME) | ||
(exitcode, _) = subprocess.getstatusoutput(f"echo '' | {write_commnand}") | ||
assert exitcode == 0 | ||
assert info.file_exists(storage, TEST_TOUCH_FILE_NAME) | ||
|
||
# test | ||
command = shell.delete_file_command(storage, file_name=TEST_TOUCH_FILE_NAME) | ||
assert command | ||
|
||
(exitcode, _) = subprocess.getstatusoutput(command) | ||
assert exitcode == 0 | ||
assert not info.file_exists(storage, TEST_TOUCH_FILE_NAME) | ||
|
||
# test if force option works as expected | ||
command = shell.delete_file_command(storage, file_name=TEST_TOUCH_FILE_NAME, force=True) | ||
assert command | ||
|
||
(exitcode, _) = subprocess.getstatusoutput(command) | ||
assert exitcode == 0 | ||
assert not info.file_exists(storage, TEST_TOUCH_FILE_NAME) |