#!/usr/bin/env python import json import os import paramiko import scp import sys import uuid from tape_task import TapeTask class TapeClient(object): EEADM = "/opt/ibm/ltfsee/bin/eeadm" # Constructor def __init__(self, host, port, user, keyFile): self.host = host self.port = port self.user = user self.client = paramiko.SSHClient() self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.key = paramiko.RSAKey.from_private_key_file(keyFile) self.client.load_system_host_keys() self.scp = None self.taskList = [] def connect(self): """Connects to the tape library frontend.""" self.client.connect(hostname = self.host, port = self.port, username = self.user, pkey = self.key) def getTaskList(self): """Returns the whole task list.""" stdin, stdout, stderr = self.client.exec_command(f"{self.EEADM} task list --json") exitCode = stdout.channel.recv_exit_status() if not exitCode: result = json.loads(stdout.readlines()[0].rstrip('\n')) #print(result) #print(len(result["payload"])) #print(result["payload"][0]) for t in result["payload"]: task = TapeTask() task.inUseTapes = t["inuse_tapes"] task.inUsePools = t["inuse_pools"] task.inUseNodeGroups = t["inuse_node_groups"] task.inUseDrives = t["inuse_drives"] task.cmdParam = t["cmd_param"] task.result = t["result"] task.status = t["status"] task.completedTime = t["completed_time"] task.startedTime = t["started_time"] task.createdTime = t["created_time"] task.setInUseLibs = t["inuse_libs"] task.type = t["type"] task.taskId = t["task_id"] task.id = t["id"] self.taskList.append(task) return self.taskList else: sys.exit("cmd_exit_code = FAILURE") def copy(self, srcPath, destPath): """Copies files/dirs recursively by passing their absolute paths.""" self.scp = scp.SCPClient(self.client.get_transport()) print(f"Copying {srcPath} in {destPath}") if os.path.isdir(srcPath): self.scp.put(srcPath, recursive = True, remote_path = destPath) elif os.path.isfile(srcPath): self.scp.put(srcPath, destPath) else: sys.exit("FATAL: invalid file/dir.") self.scp.close() def migrate(self, fileList): """ Migrates to tape all files whose absolute path is contained in 'fileList'. """ tmp = str(uuid.uuid1().hex) + "-vos_migrate.tmp" fp = open(tmp, "a") for f in fileList: fp.write(f"{f}\n") fp.close() self.copy(f"./{tmp}", f"/tmp/{tmp}") os.remove(f"./{tmp}") cmd = f"{self.EEADM} migrate /tmp/{tmp} -p pl_generic_rw_01" stdin, stdout, stderr = self.client.exec_command(cmd) def recall(self, fileList): """ Recalls from tape all files whose absolute path is contained in 'fileList'. """ tmp = str(uuid.uuid1().hex) + "-vos_recall.tmp" fp = open(tmp, "a") for f in fileList: fp.write(f"{f}\n") fp.close() self.copy(f"./{tmp}", f"/tmp/{tmp}") os.remove(f"./{tmp}") cmd = f"{self.EEADM} recall /tmp/{tmp}" stdin, stdout, stderr = self.client.exec_command(cmd) def recallChecksumFiles(self, dirName): """ Recursively recalls from tape all the checksum files related to the 'dirName' directory. """ cmd = f"find $(dirname {dirName}) -type f \( -iname \"*-md5sum.txt\" \) | {self.EEADM}" stdin, stdout, stderr = self.client.exec_command(cmd) exitCode = stdout.channel.recv_exit_status() out = open("tape_client_log.txt", "a") out.write(f"exitCode: {exitCode}\n") out.close() if exitCode: return False else: return True def disconnect(self): """Closes the connection.""" self.client.close() def getSize(self, fsMountPoint): cmd = f"df {fsMountPoint} | tail -n +2" #out = subprocess.run(cmd, shell = True, capture_output = True) stdin, stdout, stderr = self.client.exec_command(cmd) #res = stdout.stdout.decode('UTF-8').rstrip('\n') res = stdout.readlines()[0] res = ' '.join(res.split()).split(' ') #print(res) total = res[1] used = res[2] available = res[3] return ( total, used, available) # Test #tc = TapeClient("192.168.56.101", 22, "root", "ibm") #tc.connect() #tc.copy("/home/curban/store/mydir", "/home/mydir") #tc.copy("/home/curban/store/foo2.txt", "/home/mydir/foo2.txt") #tl = tc.getTaskList() #fsSize = tc.getSize("/ia2_tape_stb_01") #print(fsSize) #tc.disconnect() #for i in tl: # print(i.id) # print('\n')