Implement neofs-cli lib for container and object

Signed-off-by: Vladimir Avdeev <v.avdeev@yadro.com>
This commit is contained in:
Vladimir Avdeev 2022-08-19 05:22:20 +03:00 committed by Vladimir Domnich
parent d935c2cafa
commit 3294299612
14 changed files with 680 additions and 171 deletions

View file

@ -0,0 +1 @@
from .cli import NeofsCli

View file

@ -0,0 +1,25 @@
from typing import Optional
from .cli_command import NeofsCliCommandBase
class NeofsCliAccounting(NeofsCliCommandBase):
def balance(self, wallet: str, rpc_endpoint: str, address: Optional[str] = None,
owner: Optional[str] = None) -> str:
"""Get internal balance of NeoFS account
Args:
address: address of wallet account
owner: owner of balance account (omit to use owner from private key)
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
wallet: WIF (NEP-2) string or path to the wallet or binary key
Returns:
str: Command string
"""
return self._execute(
'accounting balance',
**{param: param_value for param, param_value in locals().items() if param not in ['self']}
)

View file

@ -0,0 +1,32 @@
from typing import Optional
from common import NEOFS_CLI_EXEC
from .accounting import NeofsCliAccounting
from .cli_command import NeofsCliCommandBase
from .container import NeofsCliContainer
from .object import NeofsCliObject
class NeofsCli:
neofs_cli_exec_path: Optional[str] = None
config: Optional[str] = None
accounting: Optional[NeofsCliAccounting] = None
container: Optional[NeofsCliContainer] = None
object: Optional[NeofsCliObject] = None
def __init__(self, neofs_cli_exec_path: Optional[str] = None, config: Optional[str] = None, timeout: int = 30):
self.config = config # config(str): config file (default is $HOME/.config/neofs-cli/config.yaml)
self.neofs_cli_exec_path = neofs_cli_exec_path or NEOFS_CLI_EXEC
self.accounting = NeofsCliAccounting(self.neofs_cli_exec_path, timeout=timeout, config=config)
self.container = NeofsCliContainer(self.neofs_cli_exec_path, timeout=timeout, config=config)
self.object = NeofsCliObject(self.neofs_cli_exec_path, timeout=timeout, config=config)
def version(self) -> str:
"""Application version and NeoFS API compatibility
Returns:
str: Command string
"""
return NeofsCliCommandBase(self.neofs_cli_exec_path, config=self.config)._execute(command=None, version=True)

View file

@ -0,0 +1,39 @@
from typing import Optional
from cli_helpers import _cmd_run
class NeofsCliCommandBase:
neofs_cli_exec: Optional[str] = None
timeout: Optional[int] = None
__base_params: Optional[str] = None
map_params = {'json_mode': 'json', 'await_mode': 'await', 'hash_type': 'hash'}
def __init__(self, neofs_cli_exec: str, timeout: int = 30, **base_params):
self.neofs_cli_exec = neofs_cli_exec
self.timeout = timeout
self.__base_params = ' '.join([f'--{param} {value}' for param, value in base_params.items() if value])
def _format_command(self, command: str, **params) -> str:
param_str = []
for param, value in params.items():
if param in self.map_params.keys():
param = self.map_params[param]
param = param.replace('_', '-')
if not value:
continue
if isinstance(value, bool):
param_str.append(f'--{param}')
elif isinstance(value, list):
param_str.append(f'--{param} \'{",".join(value)}\'')
elif isinstance(value, dict):
param_str.append(f'--{param} \'{",".join(f"{key}={val}" for key, val in value.items())}\'')
else:
value_str = str(value).replace("'", "\\'")
param_str.append(f"--{param} '{value_str}'")
param_str = ' '.join(param_str)
return f'{self.neofs_cli_exec} {self.__base_params} {command or ""} {param_str}'
def _execute(self, command: Optional[str], **params) -> str:
return _cmd_run(self._format_command(command, **params), timeout=self.timeout)

View file

@ -0,0 +1,184 @@
from typing import Optional
from .cli_command import NeofsCliCommandBase
class NeofsCliContainer(NeofsCliCommandBase):
def create(self, rpc_endpoint: str, wallet: str, address: Optional[str] = None, attributes: Optional[dict] = None,
basic_acl: Optional[str] = None, await_mode: bool = False, disable_timestamp: bool = False,
name: Optional[str] = None, nonce: Optional[str] = None, policy: Optional[str] = None,
session: Optional[str] = None, subnet: Optional[str] = None, ttl: Optional[int] = None,
xhdr: Optional[list] = None) -> str:
"""Create a new container and register it in the NeoFS.
It will be stored in the sidechain when the Inner Ring accepts it.
Args:
address: address of wallet account
attributes: comma separated pairs of container attributes in form of Key1=Value1,Key2=Value2
await_mode: block execution until container is persisted
basic_acl: hex encoded basic ACL value or keywords like 'public-read-write', 'private',
'eacl-public-read' (default "private")
disable_timestamp: disable timestamp container attribute
name: container name attribute
nonce: UUIDv4 nonce value for container
policy: QL-encoded or JSON-encoded placement policy or path to file with it
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
session: path to a JSON-encoded container session token
subnet: string representation of container subnetwork
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'container create',
**{param: param_value for param, param_value in locals().items() if param not in ['self']}
)
def delete(self, rpc_endpoint: str, wallet: str, cid: str, address: Optional[str] = None, await_mode: bool = False,
session: Optional[str] = None, ttl: Optional[int] = None, xhdr: Optional[list] = None) -> str:
"""Delete an existing container.
Only the owner of the container has permission to remove the container.
Args:
address: address of wallet account
await_mode: block execution until container is removed
cid: container ID
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
session: path to a JSON-encoded container session token
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'container delete',
**{param: param_value for param, param_value in locals().items() if param not in ['self']}
)
def get(self, rpc_endpoint: str, wallet: str, cid: str, address: Optional[str] = None, await_mode: bool = False,
to: Optional[str] = None, json_mode: bool = False, ttl: Optional[int] = None,
xhdr: Optional[dict] = None) -> str:
"""Get container field info
Args:
address: address of wallet account
await_mode: block execution until container is removed
cid: container ID
json_mode: print or dump container in JSON format
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
to: path to dump encoded container
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'container get',
**{param: param_value for param, param_value in locals().items() if param not in ['self']}
)
def get_eacl(self, rpc_endpoint: str, wallet: str, cid: str, address: Optional[str] = None,
await_mode: bool = False, to: Optional[str] = None, session: Optional[str] = None,
ttl: Optional[int] = None, xhdr: Optional[dict] = None) -> str:
"""Get extended ACL talbe of container
Args:
address: address of wallet account
await_mode: block execution until container is removed
cid: container ID
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
to: path to dump encoded container
session: path to a JSON-encoded container session token
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'container get-eacl',
**{param: param_value for param, param_value in locals().items() if param not in ['self']}
)
def list(self, rpc_endpoint: str, wallet: str, address: Optional[str] = None,
owner: Optional[str] = None, ttl: Optional[int] = None, xhdr: Optional[dict] = None, **params) -> str:
"""List all created containers
Args:
address: address of wallet account
owner: owner of containers (omit to use owner from private key)
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'container list',
**{param: param_value for param, param_value in locals().items() if param not in ['self']}
)
def list_objects(self, rpc_endpoint: str, wallet: str, cid: str, address: Optional[str] = None,
ttl: Optional[int] = None, xhdr: Optional[dict] = None) -> str:
"""List existing objects in container
Args:
address: address of wallet account
cid: container ID
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'container list-objects',
**{param: param_value for param, param_value in locals().items() if param not in ['self']}
)
def set_eacl(self, rpc_endpoint: str, wallet: str, cid: str, address: Optional[str] = None,
await_mode: bool = False, table: Optional[str] = None, session: Optional[str] = None,
ttl: Optional[int] = None, xhdr: Optional[dict] = None) -> str:
"""Set a new extended ACL table for the container.
Container ID in the EACL table will be substituted with the ID from the CLI.
Args:
address: address of wallet account
await_mode: block execution until container is removed
cid: container ID
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
session: path to a JSON-encoded container session token
table: path to file with JSON or binary encoded EACL table
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'container set-eacl',
**{param: param_value for param, param_value in locals().items() if param not in ['self']}
)

View file

@ -0,0 +1,240 @@
from typing import Optional
from .cli_command import NeofsCliCommandBase
class NeofsCliObject(NeofsCliCommandBase):
def delete(self, rpc_endpoint: str, wallet: str, cid: str, oid: str, address: Optional[str] = None,
bearer: Optional[str] = None, session: Optional[str] = None, ttl: Optional[int] = None,
xhdr: Optional[list] = None, **params) -> str:
"""Delete object from NeoFS
Args:
address: address of wallet account
bearer: File with signed JSON or binary encoded bearer token
cid: Container ID
oid: Object ID
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
session: path to a JSON-encoded container session token
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'object delete',
**{param: param_value for param, param_value in locals().items() if param not in ['self', 'params']}
)
def get(self, rpc_endpoint: str, wallet: str, cid: str, oid: str, address: Optional[str] = None,
bearer: Optional[str] = None, file: Optional[str] = None,
header: Optional[str] = None, no_progress: bool = False, raw: bool = False,
session: Optional[str] = None, ttl: Optional[int] = None, xhdr: Optional[list] = None, **params) -> str:
"""Get object from NeoFS
Args:
address: address of wallet account
bearer: File with signed JSON or binary encoded bearer token
cid: Container ID
file: File to write object payload to. Default: stdout.
header: File to write header to. Default: stdout.
no_progress: Do not show progress bar
oid: Object ID
raw: Set raw request option
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
session: path to a JSON-encoded container session token
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'object get',
**{param: param_value for param, param_value in locals().items() if param not in ['self', 'params']}
)
def hash(self, rpc_endpoint: str, wallet: str, cid: str, oid: str, address: Optional[str] = None,
bearer: Optional[str] = None, range: Optional[str] = None, salt: Optional[str] = None,
ttl: Optional[int] = None, hash_type: Optional[str] = None, xhdr: Optional[list] = None,
**params) -> str:
"""Get object hash
Args:
address: address of wallet account
bearer: File with signed JSON or binary encoded bearer token
cid: Container ID
oid: Object ID
range: Range to take hash from in the form offset1:length1,...
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
salt: Salt in hex format
ttl: TTL value in request meta header (default 2)
hash_type: Hash type. Either 'sha256' or 'tz' (default "sha256")
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'object hash',
**{param: param_value for param, param_value in locals().items() if param not in ['self', 'params']}
)
def head(self, rpc_endpoint: str, wallet: str, cid: str, oid: str, address: Optional[str] = None,
bearer: Optional[str] = None, file: Optional[str] = None,
json_mode: bool = False, main_only: bool = False, proto: bool = False, raw: bool = False,
session: Optional[str] = None, ttl: Optional[int] = None, xhdr: Optional[list] = None, **params) -> str:
"""Get object header
Args:
address: address of wallet account
bearer: File with signed JSON or binary encoded bearer token
cid: Container ID
file: File to write object payload to. Default: stdout.
json_mode: Marshal output in JSON
main_only: Return only main fields
oid: Object ID
proto: Marshal output in Protobuf
raw: Set raw request option
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
session: path to a JSON-encoded container session token
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'object head',
**{param: param_value for param, param_value in locals().items() if param not in ['self', 'params']}
)
def lock(self, rpc_endpoint: str, wallet: str, cid: str, oid: str, lifetime: int, address: Optional[str] = None,
bearer: Optional[str] = None, session: Optional[str] = None,
ttl: Optional[int] = None, xhdr: Optional[list] = None, **params) -> str:
"""Lock object in container
Args:
address: address of wallet account
bearer: File with signed JSON or binary encoded bearer token
cid: Container ID
oid: Object ID
lifetime: Object lifetime
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
session: path to a JSON-encoded container session token
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'object lock',
**{param: param_value for param, param_value in locals().items() if param not in ['self', 'params']}
)
def put(self, rpc_endpoint: str, wallet: str, cid: str, file: str, address: Optional[str] = None,
attributes: Optional[dict] = None, bearer: Optional[str] = None, disable_filename: bool = False,
disable_timestamp: bool = False, expire_at: Optional[int] = None, no_progress: bool = False,
notify: Optional[str] = None, session: Optional[str] = None, ttl: Optional[int] = None,
xhdr: Optional[list] = None, **params) -> str:
"""Put object to NeoFS
Args:
address: address of wallet account
attributes: User attributes in form of Key1=Value1,Key2=Value2
bearer: File with signed JSON or binary encoded bearer token
cid: Container ID
disable_filename: Do not set well-known filename attribute
disable_timestamp: Do not set well-known timestamp attribute
expire_at: Last epoch in the life of the object
file: File with object payload
no_progress: Do not show progress bar
notify: Object notification in the form of *epoch*:*topic*; '-' topic means using default
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
session: path to a JSON-encoded container session token
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'object put',
**{param: param_value for param, param_value in locals().items() if param not in ['self', 'params']}
)
def range(self, rpc_endpoint: str, wallet: str, cid: str, oid: str, range: str, address: Optional[str] = None,
bearer: Optional[str] = None, file: Optional[str] = None, json_mode: bool = False, raw: bool = False,
session: Optional[str] = None, ttl: Optional[int] = None, xhdr: Optional[list] = None, **params) -> str:
"""Get payload range data of an object
Args:
address: address of wallet account
bearer: File with signed JSON or binary encoded bearer token
cid: Container ID
file: File to write object payload to. Default: stdout.
json_mode: Marshal output in JSON
oid: Object ID
range: Range to take data from in the form offset:length
raw: Set raw request option
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
session: path to a JSON-encoded container session token
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'object range',
**{param: param_value for param, param_value in locals().items() if param not in ['self', 'params']}
)
def search(self, rpc_endpoint: str, wallet: str, cid: str, address: Optional[str] = None,
bearer: Optional[str] = None, filters: Optional[list] = None, oid: Optional[str] = None,
phy: bool = False, root: bool = False, session: Optional[str] = None, ttl: Optional[int] = None,
xhdr: Optional[list] = None, **params) -> str:
"""Search object
Args:
address: address of wallet account
bearer: File with signed JSON or binary encoded bearer token
cid: Container ID
filters: Repeated filter expressions or files with protobuf JSON
oid: Object ID
phy: Search physically stored objects
root: Search for user objects
rpc_endpoint: remote node address (as 'multiaddr' or '<host>:<port>')
session: path to a JSON-encoded container session token
ttl: TTL value in request meta header (default 2)
wallet: WIF (NEP-2) string or path to the wallet or binary key
xhdr: Request X-Headers in form of Key=Value
Returns:
str: Command string
"""
return self._execute(
'object search',
**{param: param_value for param, param_value in locals().items() if param not in ['self', 'params']}
)