Salah satu tugas paling menarik dalam pekerjaan administrator aplikasi, menurut saya, adalah implementasi migrasi data saat pindah ke sistem baru. Hari ini saya ingin berbagi pengalaman saya sendiri dalam mentransfer data dari helpdesk yang tidak terlalu terkenal dari sistem VisionFlow ke sistem ServiceNow yang lebih terkenal.
Apa yang diinginkan pelanggan
Transfer semua data dari VisionFlow ke ServiceNow dengan menyimpan tanggal pendaftaran / penutupan tiket
Pindahkan seluruh riwayat korespondensi untuk setiap tiket (itu cukup untuk menggabungkan semua komentar menjadi satu utas, tetapi kami melangkah lebih jauh)
Pindahkan semua file yang dilampirkan ke tiket
Apa yang kita punya
Versi server dari sistem VisionFlow Helpdesk yang digunakan pada mesin Linux virtual dengan database MySQL untuk penyimpanan data.
ServiceNow misalnya, dengan meja yang disiapkan sebelumnya untuk pelanggan.
Pada tahap ini dibahas semua nuansa, seperti:
Model status
Bidang yang harus diisi
Logika penugasan tiket otomatis ke pelaksana
Data yang akan ditransfer
Transfer data
ServiceNow memungkinkan Anda menggunakan file excel sebagai sumber daya untuk mengimpor data. Saya tidak akan menjelaskan secara detail proses mengimpor data ke dalam sistem (prosesnya dijelaskan dengan baik dalam dokumentasi produk), tetapi secara umum terlihat seperti ini:
Impor data
Peta transformasi memungkinkan kita untuk menetapkan bidang kunci yang dengannya sistem akan memahami bahwa catatan dengan parameter ini sudah ada di tabel dan hanya bidang yang perlu diperbarui
xlsx , . VisionFlow . :
VisionFlow
SELECT
projectissue.projectIssueId,
projectissue.ticketId as 'Number',
reporter.email as 'Reporter',
projectissue.name as 'Short Description',
projectissue.Description as 'Description',
projectissue.companycustomfield15 as 'Product',
projectissue.companycustomfield13 as 'Document',
issuestatus.name as 'Status',
assignee.name as 'Assignee',
ADDTIME(projectissue.CreateDate, '-01:00') as 'Created',
ADDTIME(projectissue.completionDate, '-01:00') as 'Closed',
issuehistory.EventText as 'Comment',
author.name as 'commentAuthor'
FROM
projectissue
INNER JOIN issuestatus
ON projectissue.IssueStatusId = issuestatus.IssueStatusId
INNER JOIN systemuser assignee
ON projectissue.ResponsibleSystemUserId = assignee.SystemUserId
INNER JOIN systemuser reporter
ON projectissue.CreatedBySystemUserId = reporter.SystemUserId
INNER JOIN issuehistory ON
issuehistory.ProjectIssueId = projectissue.ProjectIssueId
INNER JOIN systemuser author
ON issuehistory.SystemUserId = author.SystemUserId
WHERE
projectissue.ProjectId = 54 AND (issuehistory.IssueEventTypeId = 5 OR issuehistory.IssueEventTypeId = 10 OR issuehistory.IssueEventTypeId = 2)
#projectissue.ProjectId = 54
ORDER BY projectissue.TicketId ASC, issuehistory.EventDate ASC
, , . JSON Excel . ServiceNow Data Source / .
: ServiceNow VisionFlow, , ( ) . .. , ( , ).
( ) , . , VisionFlow, , .
:
VisionFlow
SELECT
document.documentId,
document.name,
document.FullPath,
SUBSTRING_INDEX(SUBSTRING_INDEX(document.FullPath, '/', -2), '/', 1) as 'projectIssueId',
projectissue.ticketId as 'Number'
FROM
visionflow.document
INNER JOIN projectissue
ON projectissue.ProjectIssueId = SUBSTRING_INDEX(SUBSTRING_INDEX(document.FullPath, '/', -2), '/', 1)
WHERE
document.FullPath like '%/54/issuedocuments/%'
ORDER BY projectissueid
, VisionFlow . , , VF , , . issueId, . , , TicketId ( ServiceNow).
, ServiceNow . .. Python, , .
ServiceNow API attachments. SN endpoint .
ServiceNow code samples API. , :
file_name (Required) -
table_name (Required) - ,
table_sys_id (Required) - ID ,
Content-Type (Header) - mime type
, sys_id , ( VisionFlow). , , VisionFlow sys_id , . sys_id + ticketId ServiceNow + issueId + ticketId VisionFlow. VLOOKUP Excel :
old_folder_name
ticket_id
new_folder_name
Python , ( ):
import pandas as pd, os
from tqdm import tqdm
def renameFolders():
df = pd.read_csv('/Downloads/folder_rename.csv')
pbar = tqdm(total=len(df))
for _ , row in df.iterrows():
old_name = row['old_folder_name']
new_name = row['new_folder_name']
try:
os.rename(f'/Downloads/home/tomcat/vflowdocs/54/issuedocuments/{old_name}', f'/Downloads/home/tomcat/vflowdocs/54/issuedocuments/{new_name}')
pbar.update(1)
except:
pbar.update(1)
def removeEmptyFolders():
folder_list = os.listdir('/Downloads/home/tomcat/vflowdocs/54/issuedocuments/')
for folder in folder_list:
path = f'/Downloads/home/tomcat/vflowdocs/54/issuedocuments/{folder}'
try:
os.rmdir(path)
except:
if len(os.path.basename(path)) < 6 and os.path.basename(path) != 'nan':
print(f'ServiceNow SysId not found for item: {os.path.basename(path)}')
renameFolders()
removeEmptyFolders()
, :
, , , 3000 kb ( , ) def getSize()
. VisionFlow def removeDuplicates()
mime None. - mimetypes *msg, *txt, *eml
( , , ) -
import os, glob, filetype, requests, mimetypes
from tqdm import tqdm
import pandas as pd
def number_of_files():
files_number = 0
folder_list = os.listdir('/Downloads/home/tomcat/vflowdocs/54/issuedocuments/')
for folder in folder_list:
files_number += len(os.listdir(f'/Downloads/home/tomcat/vflowdocs/54/issuedocuments/{folder}/'))
return files_number
#Progress Bar
pbar = tqdm(total=1297)
log_messages_status = []
log_messages_filepath = []
log_messages_filename = []
log_messages_target = []
def uploadAllFiles(folder_name):
#Variables
entire_list = glob.glob(f'/Downloads/home/tomcat/vflowdocs/54/issuedocuments/{folder_name}/*')
my_list_updated = []
#Get Files Size
def getSize(fileobject):
fileobject.seek(0,2)
size = fileobject.tell()
return size
#Upload Files
def uploadFunc(filename, sys_id, path_to_file, content_type):
url = f'https://instance.service-now.com/api/now/attachment/file?file_name={filename}&table_name=table_name&table_sys_id={sys_id}'
payload=open(path_to_file, 'rb').read()
headers = {
'Accept': 'application/json',
'Authorization': 'Bearer ',
'Content-Type': content_type,
}
response = requests.request("POST", url, headers=headers, data=payload)
if response.status_code == 201:
#print(f'Success: {filename} was uploaded to the incident with sys_id {sys_id}')
pbar.update(1)
log_messages_status.append('Success')
log_messages_filename.append(filename)
log_messages_filepath.append(path_to_file)
log_messages_target.append(sys_id)
else:
pbar.update(1)
#print(f'Error: {filename} was not uploaded to the incident with sys_id {sys_id}')
log_messages_status.append('Error')
log_messages_filename.append(filename)
log_messages_filepath.append(path_to_file)
log_messages_target.append(sys_id)
#Remove Duplicates
def removeDuplicatesByName(list_of_elements):
list_of_elements.sort()
if len(list_of_elements) > 1:
for item in list_of_elements:
item_to_compare = item.split('.')[0]
for element in list_of_elements:
if item_to_compare in element:
entire_list.remove(element)
else:
pass
return list_of_elements
else:
return list_of_elements
my_list = removeDuplicatesByName(entire_list)
for item in my_list:
file_size = open(item, 'rb')
if getSize(file_size) > 3000:
my_list_updated.append(item)
else:
pass
for attach in my_list_updated:
kind = filetype.guess_mime(attach)
if kind != None:
uploadFunc(os.path.basename(attach), os.path.dirname(attach).split('/')[-1], attach, kind)
elif kind == None and attach.split('.')[-1] == 'txt':
uploadFunc(os.path.basename(attach), os.path.dirname(attach).split('/')[-1], attach, 'text/plain')
else:
uploadFunc(os.path.basename(attach), os.path.dirname(attach).split('/')[-1], attach, 'application/octet-stream')
def getFolders():
folder_list = os.listdir('/Downloads/home/tomcat/vflowdocs/54/issuedocuments/')
for folder in folder_list:
if folder != '.DS_Store':
uploadAllFiles(folder)
getFolders()
data_to_write = pd.DataFrame({
'status': log_messages_status,
'file_name' : log_messages_filename,
'file_path' : log_messages_filepath,
'target' : log_messages_target
})
data_to_write.to_csv('/Downloads/results_log.csv')
Kami memiliki 2 sachet .... ©. Kami memiliki 6.000.000 catatan untuk ditransfer (tidak terlalu banyak, sistem lama tidak berfungsi lama), 2.000 lampiran, dan sedikit waktu. Proses persiapan memakan waktu sekitar 14 jam (belajar, mencoba, dll.) Dari pekerjaan santai, dan total proses transfer memakan waktu sekitar 30 menit.
Tentu saja, mungkin ada banyak hal yang perlu ditingkatkan, proses yang sepenuhnya otomatis (dari membongkar data hingga mengunggahnya), tetapi, sayangnya, tugas ini hanya sekali. Sangat menarik untuk mencoba Python untuk implementasi proyek, dan saya dapat mengatakan bahwa dia membantu mengatasi tugas seperti itu dengan keras.
Pada akhirnya, tugas utama pemindahan ini adalah melakukannya sebisa mungkin tanpa diketahui oleh pelanggan, yang dilakukan oleh saya.