'''
This class provides methods to create batch file that contains different operations on Handle.
The batch file is executed by the hdl-genericbatch (hdl-genericbatch <batchfile>).
Author Sofiane Bendoukha (DKRZ), 2017.
'''
from __future__ import absolute_import
import logging
import os
from os.path import expanduser
from pyhandle.batchhsexceptions import BatchFileExistsException
from pyhandle.pyhandleclient import HandleClient
from pyhandle.clientcredentials import PIDClientCredentials
from .. import util
LOGGER = logging.getLogger(__name__)
LOGGER.addHandler(util.NullHandler())
class BatchHandleClient(HandleClient):
'''The BatchHandleClient class'''
HANDLE_CLIENT = 'batch'
HOME_DIRECTORY = expanduser("~")
_default_batch_file_path = HOME_DIRECTORY + '/handle_batch'
[docs] def __init__(self, **args):
'''
Initialize the batch client and set the path for the batch file.
:param credentials: Optional. As json file in form {"user":"user", "password":"password"}
:param args: Optional. This includes different parameters concerning the batch file, such as the PATH.
'''
LOGGER.debug('\n' + 60 * '*' + '\nInstantiation of BatchHandleClient\n' + 60 * '*')
super(BatchHandleClient, self).__init__()
self.__all_args = args
self.__batch_file_path = args['batch_file_path']
if self.__batch_file_path is None:
self.__batch_file_path = self._default_batch_file_path
[docs] def create_batch_file(self, overwrite=False):
'''
Creates a batch file in a directory specified by the user or in the default directory
(./pyhandle/batch/handle_batch).
:param overwrite: Optional. If set to True, the existing batch file
will be overwritten. Defaults to False.
:raises: :exc:`~pyhandle.batchhsexceptions.BatchFileExistsException` Only if overwrite is not set or
set to False.
'''
LOGGER.debug('BatchHandleClient')
batch_file_path = self.get_batch_file_path()
if overwrite:
batch_file = os.fdopen(os.open(batch_file_path, os.O_CREAT | os.O_WRONLY), "w")
batch_file.seek(0)
batch_file.truncate()
else:
try:
batch_file = os.fdopen(os.open(batch_file_path, os.O_CREAT | os.O_WRONLY | os.O_EXCL), "w")
batch_file.close()
except Exception as exc:
if exc.args[0] == 17:
msg = 'Could not create batch file, already exists'
LOGGER.error(msg + ', as it already exists.')
raise BatchFileExistsException(file=self.get_batch_file_path(), msg=msg)
[docs] def register_handle_batch(self, handle, location, hdl_admin_index, admin_handle, perm):
'''
This method creates a simple Handle record including a Handle value to define the administrator of the Handle
and the value for the location (URL)..
Operation name is 'CREATE'. The first line is composed of the following:
CREATE + space + handle_name.
:param handle: The full name of the handle to be registered (prefix
and suffix)
:param location: The URL of the data entity to be referenced
:param hdl_admin_index: Unique index number
:param admin_handle: Administrator of the Handle
:param perm: permissions
:raises: :exc:`~pyhandle.batchhsexceptions.BatchFileExistsException`.
'''
LOGGER.debug("Creating a handle (batch)")
if self.check_if_file_exists(self.get_batch_file_path()):
with open(self.get_batch_file_path(), 'a') as bfile:
bfile.write('\nCREATE ' + handle + '\n100 HS_ADMIN 86400 1110 ADMIN ' + str(hdl_admin_index)
+ ':' + perm + ':' + admin_handle)
with open(self.get_batch_file_path(), 'a') as bfile:
bfile.write('\n\nADD ' + handle + '\n1 URL 86400 1110 UTF8 ' + location)
else:
msg = 'does not exists'
raise BatchFileExistsException(file=self.get_batch_file_path(), msg=msg)
[docs] def delete_handle(self, handle):
'''
This method deletes an existing Handle and its records.
Operation name 'DELETE'.
:param handle: Handle name to be deleted
:raises: :exc:`~pyhandle.batchhsexceptions.BatchFileExistsException`.
'''
LOGGER.debug("Deleting a handle (batch)")
if self.check_if_file_exists(self.get_batch_file_path()):
with open(self.get_batch_file_path(), 'a') as bfile:
bfile.write('\nDELETE ' + handle)
else:
msg = 'does not exists'
raise BatchFileExistsException(file=self.get_batch_file_path(), msg=msg)
[docs] def modify_handle_value(self, handle, **kvpairs):
'''
This method changes Handle values for an existing Handle.
Operation name 'MODIFY'
:param handle: Handle whose record is to be modified
:param kvpairs: Contains the unique index number, Handle value type and the value data
:raises: :exc:`~pyhandle.batchhsexceptions.BatchFileExistsException`.
'''
LOGGER.debug("Modifying a value of handle (batch)")
if kvpairs:
self.type = kvpairs['type']
self.index = kvpairs['index']
self.data = kvpairs['data']
if self.check_if_file_exists(self.get_batch_file_path()):
with open(self.get_batch_file_path(), 'a') as bfile:
bfile.write('\nMODIFY ' + handle + '\n' + str(self.index) + ' ' + self.type + ' 86400 1110 UTF8 ' +
self.data)
else:
msg = 'does not exists'
raise BatchFileExistsException(file=self.get_batch_file_path(), msg=msg)
[docs] def add_handle_value(self, handle, **kvpairs):
'''
The method adds new handle values to an existing handle.
Operation name 'ADD'.
:param handle: The handle where the new value will be added
:param kvpairs: Contains the unique index number, Handle value type and the value data
:raises: :exc:`~pyhandle.batchhsexceptions.BatchFileExistsException`.
'''
LOGGER.debug("Add handle value")
if kvpairs:
self.type = kvpairs['type']
self.index = kvpairs['index']
self.data = kvpairs['data']
if self.check_if_file_exists(self.get_batch_file_path()):
with open(self.get_batch_file_path(), 'a') as bfile:
bfile.write('\nADD ' + handle + '\n' + str(self.index) + ' ' + self.type + ' 86400 1110 UTF8 ' +
self.data)
else:
msg = 'does not exists'
raise BatchFileExistsException(file=self.get_batch_file_path(), msg=msg)
[docs] def delete_handle_value(self, handle, value_index):
'''
This method removes one or more handle values from an existing handle.
Operation name 'REMOVE'.
:param handle: Handle from whose record the entry should be deleted.
:param value_index: The index of the value
:raises: :exc:`~pyhandle.batchhsexceptions.BatchFileExistsException`.
'''
LOGGER.debug("Delete handle value")
if self.check_if_file_exists(self.get_batch_file_path()):
if len(value_index) == 1:
with open(self.get_batch_file_path(), 'a') as bfile:
bfile.write('\nREMOVE ' + str(value_index[0]) + ':' + handle)
else:
with open(self.get_batch_file_path(), 'a') as bfile:
for key in range(len(value_index)):
bfile.write('\nREMOVE ' + str(value_index[key]) + ':' + handle)
else:
msg = 'does not exists'
raise BatchFileExistsException(file=self.get_batch_file_path(), msg=msg)
[docs] def authenticate_seckey(self, user, password):
'''
Secret key authentication. Operation name 'AUTHENTICATE'.
:param user: This must be a handle value reference in the format
"index:prefix/suffix".
:param password: This is the password stored as secret key in the
actual Handle value the username points to.
:param credentials: Optional. When credentials are
:raises: :exc:`~pyhandle.batchhsexceptions.BatchFileExistsException`.
'''
LOGGER.debug("Authenticate with SECKEY")
if self.check_if_file_exists(self.get_batch_file_path()):
with open(self.get_batch_file_path(), 'a') as bfile:
bfile.write('\nAUTHENTICATE SECKEY:' + user + '\n' + password)
else:
msg = 'does not exists'
raise BatchFileExistsException(file=self.get_batch_file_path(), msg=msg)
[docs] def authenticate_pubkey(self, user, priv_key_path, passphrase=None):
'''
Private key authentication. Operation name 'AUTHENTICATE'.
:param user: admin_index:admin_handle
:param pubkey_path: private_key_file_path
:param passphrase: If your private key was created and encrypted by passphrase
:raises: :exc:`~pyhandle.batchhsexceptions.BatchFileExistsException`.
'''
LOGGER.debug("Authenticate with PUBKEY")
if self.check_if_file_exists(self.get_batch_file_path()):
if passphrase:
with open(self.get_batch_file_path(), 'w+') as bfile:
bfile.write('AUTHENTICATE PUBKEY:' + user + '\n' + priv_key_path + '|' + passphrase)
else:
with open(self.get_batch_file_path(), 'w+') as bfile:
bfile.write('AUTHENTICATE PUBKEY:' + user + '\n' + priv_key_path)
else:
msg = 'does not exists'
raise BatchFileExistsException(file=self.get_batch_file_path(), msg=msg)
[docs] def authenticate_with_credentials(self, credentials, auth_type):
'''
Set the credentials for seckey and pubkey authentication.
:param credentials: A credentials object, see separate class
PIDClientCredentials.
:param auth_type: Set authentication type to 'seckey' (username:password)
or to pubkey (privatekey | passphrase).
'''
if isinstance(credentials, PIDClientCredentials):
self.credentials = credentials.get_all_args()
else:
self.credentials = credentials
self.username = credentials.get_username()
self.password = credentials.get_password()
self.private_key = credentials.get_path_to_private_key()
self.passphrase = credentials.get_key_passphrase()
if auth_type == "seckey":
self.authenticate_seckey(self.username, self.password)
if auth_type == "pubkey":
self.authenticate_pubkey(self.username, self.private_key, passphrase=self.passphrase)
[docs] def get_all_args(self):
return self.__all_args
[docs] def get_batch_file_path(self):
return self.__batch_file_path
[docs] def check_if_file_exists(self, file_path):
if os.path.isfile(file_path):
return True
return False