技术分享
openstack虚拟机迁移到ovirt环境脚本实现
2021-06-06
1、需求背景:
旧平台openstack虚拟机需要迁移到ovirt-engine环境,直接用ovirt自带的对接openstack环境一直cinder鉴权报错,调查是版本不支持,只能手动备份导入的ovirt平台。
思路:获取openstack环境虚拟机信息,读取迁移虚拟机表格,导出虚拟机为qcow2,上传到ovirt平台创建虚拟机挂盘。
2、获取openstack计算节点虚拟机信息
通过virsh list获取instance实例列表,再通过dumpxml获取虚拟机信息利用xml模块解析所需要的信息
def get_vms_list(self):
# print("virsh list --all --name ...")
list_cmd = "virsh list --all --name".split(" ")
stdout, stderr = self.cmd_process(list_cmd)
instance_names = list(filter(None, stdout.split("\n")))
return instance_names
def get_dumpxml_info(self, instance_name):
# print("virsh dumpxml...")
info_cmd = "virsh dumpxml %s" % instance_name
stdout, _ = self.cmd_process(info_cmd.split(" "))
return stdout
def get_vms_info(self):
instance_names = self.get_vms_list()
vms_info = []
for instance_name in instance_names:
xml_str = self.get_dumpxml_info(instance_name)
DOMTree = xml.dom.minidom.parseString(xml_str)
collection = DOMTree.documentElement
vm_info = {}
data_volume = []
vm_info["instance_name"] = collection.getElementsByTagName("name")[0].childNodes[0].data
vm_info["vm_name"] = collection.getElementsByTagName("metadata")[0].getElementsByTagName("nova:instance")[
0].getElementsByTagName("nova:name")[0].childNodes[0].data
vm_info["vm_flavor"] = collection.getElementsByTagName("metadata")[0].getElementsByTagName("nova:instance")[
0].getElementsByTagName("nova:flavor")[0].getAttribute("name")
vm_info["instance_uuid"] = collection.getElementsByTagName("uuid")[0].childNodes[0].data
vm_info["instance_vcpu"] = collection.getElementsByTagName("vcpu")[0].childNodes[0].data
vm_info["instance_memory"] = collection.getElementsByTagName("memory")[0].childNodes[0].data
for disk_info in collection.getElementsByTagName("devices")[0].getElementsByTagName("disk"):
dev = disk_info.getElementsByTagName("target")[0].getAttribute("dev")
if dev == "vda" or dev == "hda":
vm_info["system_volume"] = disk_info.getElementsByTagName("source")[0].getAttribute("name")
else:
data_volume.append(disk_info.getElementsByTagName("source")[0].getAttribute("name"))
vm_info["data_volume"] = data_volume
vms_info.append(vm_info)
return vms_info计算节点都要执行,最后汇总到执行脚本的节点,并且汇总读取信息(注意系统卷和数据卷的判断根据具体环境修改适配)
run_first_time = False
if run_first_time:
for host in HOST_LIST:
print("** get the vm info from %s" % host)
os.system("scp get_vm_info.py root@%s:/home" % host)
sshclient_execmd(host, "python /home/get_vm_info.py > /home/%s_vm_info.txt" % host)
time.sleep(1)
sshclient_execmd(host, "scp /home/%s_vm_info.txt root@cmp014:/home/test/info" % host)
time.sleep(1)
print("** update vm info successful")
print("** read the info file")
info_path = "/home/test/info"
files = os.listdir(info_path)
for file_name in files:
print("** read the file : %s" % file_name)
with open(info_path + "/" + file_name) as f:
content = f.read()
all_vms_info.extend(ast.literal_eval(content))
3、获取卷信息后转换格式
def rbd_export(self, volume_path, volume_name):
rbd_cmd_str = "rbd export %s %s.qcow2" % (volume_path, volume_name)
self.cmd_process(rbd_cmd_str.split(" "))
print ("**%s exported %s successfully." % (volume_path, volume_name))
def img_covert(self, qcow2_path, qcow2_name):
img_covert_str = "qemu-img convert -O qcow2 %s %s" % (qcow2_path + ".qcow2", qcow2_name + ".qcow2")
self.cmd_process(img_covert_str.split(" "))
print ("**%s coverted successfully." % qcow2_name)
os.remove(qcow2_path + ".qcow2")
print ("**remove tmp file:%s" % (qcow2_path + ".qcow2"))
def clean_disks(self, qcow2_name):
if os.path.exists(qcow2_name + ".qcow2"):
os.remove(qcow2_name + ".qcow2")
print ("** remove disk %s" % qcow2_name)4、虚拟机disk转换之后利用ovirt sdk的方法上传系统盘和数据盘,创建虚拟机将盘挂载在虚拟机上,添加网卡,等等
def upload_disk(self):
print ("--Step01:upload disk....")
for volume_path in self.volumes_list:
# Get image info using qemu-img
image_info = self.get_image_info(volume_path)
new_disk_format = self.get_disk_format(image_info)
print("**Uploaded image format: %s" % image_info["format"])
print("**Disk content type: %s" % image_info["content_type"])
print("**Disk format: %s" % new_disk_format)
print("**Transfer format: %s" % image_info["transfer_format"])
# This example will connect to the server and create a new `floating`
# disk, one that isn't attached to any virtual machine.
# Then using transfer service it will transfer disk data from local
# qcow2 disk to the newly created disk in server.
print("**Creating disk...")
image_size = os.path.getsize(volume_path)
disks_service = self.system_service.disks_service()
disk = disks_service.add(
disk=types.Disk(
name=os.path.basename(volume_path[:-6]),
content_type=image_info["content_type"],
description='Uploaded disk',
format=new_disk_format,
initial_size=image_size,
provisioned_size=image_info["virtual-size"],
sparse=new_disk_format == types.DiskFormat.COW,
storage_domains=[
types.StorageDomain(
name=self.args.sd_name
)
]
)
)
# Wait till the disk is up, as the transfer can't start if the
# disk is locked:
disk_service = disks_service.disk_service(disk.id)
while True:
time.sleep(5)
disk = disk_service.get()
if disk.status == types.DiskStatus.OK:
break
print("**Creating transfer session...")
# Get a reference to the service that manages the image
# transfer that was added in the previous step:
transfers_service = self.system_service .image_transfers_service()
# Add a new image transfer:
transfer = transfers_service.add(
types.ImageTransfer(
image=types.Image(
id=disk.id
),
# 'format' can be used only for ovirt-engine 4.3 or above
format=image_info["transfer_format"],
)
)
# Get reference to the created transfer service:
transfer_service = transfers_service.image_transfer_service(transfer.id)
# After adding a new transfer for the disk, the transfer's status will be INITIALIZING.
# Wait until the init phase is over. The actual transfer can start when its status is "Transferring".
while transfer.phase == types.ImageTransferPhase.INITIALIZING:
time.sleep(1)
transfer = transfer_service.get()
print("**Uploading image...")
# At this stage, the SDK granted the permission to start transferring the disk, and the
# user should choose its preferred tool for doing it - regardless of the SDK.
# In this example, we will use Python's httplib.HTTPSConnection for transferring the data.
if args.direct:
if transfer.transfer_url is not None:
destination_url = transfer.transfer_url
else:
print("**Direct upload to host not supported (requires ovirt-engine 4.2 or above).")
sys.exit(1)
else:
destination_url = transfer.proxy_url
with ui.ProgressBar(image_size) as pb:
client.upload(
volume_path,
destination_url,
self.args.cafile,
secure=self.args.secure,
progress=pb.update)
print("**Finalizing transfer session...")
# Successful cleanup
transfer_service.finalize()
print("**Upload %s completed successfully" % volume_path)
def attach_disk(self, disk_attachments_service, disk_name, vm_name, bootable=True):
disks_service = self.system_service.disks_service()
while True:
time.sleep(5)
my_disk = disks_service.list(search='name=%s' % disk_name)[0]
if my_disk.status == types.DiskStatus.OK:
print ("**DiskStatus is ok")
break
disk_attachment = disk_attachments_service.add(
types.DiskAttachment(
disk=my_disk,
interface=types.DiskInterface.VIRTIO,
bootable=bootable,
active=True,
),
)
# Wait until the disk status is OK:
disk_service = disks_service.disk_service(disk_attachment.disk.id)
while True:
time.sleep(5)
disk = disk_service.get()
if disk.status == types.DiskStatus.OK:
print("**Disk '%s' added to '%s'." % (disk.name, vm_name))
break
def attach_nics(self, vm_name):
vms_service = self.system_service.vms_service()
vm = vms_service.list(search='name=%s' % vm_name)[0]
cluster = self.system_service.clusters_service().cluster_service(vm.cluster.id).get()
dcs_service = self.system_service.data_centers_service()
dc = dcs_service.list(search='Clusters.name=%s' % cluster.name)[0]
networks_service = dcs_service.service(dc.id).networks_service()
network = next(
(n for n in networks_service.list()
if n.name == 'Ext-Net'),
None
)
profiles_service = self.system_service.vnic_profiles_service()
profile_id = None
nic_name = random.choice(NIC_LIST)
for profile in profiles_service.list():
if profile.name == nic_name:
print ("**add nic : %s" % profile.name)
profile_id = profile.id
break
# Locate the service that manages the network interface cards of the
# virtual machine:
nics_service = vms_service.vm_service(vm.id).nics_service()
# Use the "add" method of the network interface cards service to add the
# new network interface card:
nics_service.add(
types.Nic(
name='mynic',
description='My network interface card',
vnic_profile=types.VnicProfile(
id=profile_id,
),
),
)
print("**Nic added successfully")
def assign_permission(self, permissions_service, user, group):
if user:
print("**assign user permission.")
permissions_service.add(
types.Permission(
user=types.User(
id=user.id,
),
role=types.Role(
name=USER_ROLENAME,
),
),
)
else:
print ("**user is none, pass the user assign permission")
if group:
print ("**assign group permission.")
permissions_service.add(
types.Permission(
group=types.Group(
id=group.id,
),
role=types.Role(
name=GROUP_ROLENAME,
),
),
)
else:
print ("**group is none, pass the user assign permission")
def create_vm(self):
print ("--Step02:begin create vm")
vms_service = self.system_service.vms_service()
users_service = connection.system_service().users_service()
groups_service = connection.system_service().groups_service()
try:
user = users_service.list(search='usrname=%s' % op.user_name)[0]
except:
user = None
try:
group = groups_service.list(search='name=%s' % op.group_name)[0]
except:
group = None
vm = vms_service.add(
types.Vm(
name=op.vm_name,
description='migrate from openstack',
comment=group.name if group else None,
cluster=types.Cluster(
name='Default',
),
cpu=types.Cpu(
topology=types.CpuTopology(
cores=1,
sockets=int(self.vm_info.get("instance_vcpu")),
threads=1
)
),
template=types.Template(
name='Blank',
),
high_availability=types.HighAvailability(
enabled=True,
priority=1
),
memory=int(self.vm_info.get("instance_memory"))*1024,
),
)
# Find the service that manages the virtual machine:
vm_service = vms_service.vm_service(vm.id)
# Wait till the virtual machine is down, which means that it is
# completely created:
while True:
time.sleep(5)
vm = vm_service.get()
if vm.status == types.VmStatus.DOWN:
print("**The vm %s is created successfully." % self.vm_info.get("vm_name"))
break
print ("--Step03:begin to attach disk.")
disk_attachments_service = vm_service.disk_attachments_service()
for volume_path in self.volumes_list:
print ("**begin to attach disk: %s" % volume_path)
self.attach_disk(disk_attachments_service, str(volume_path[:-6]), vm.name, bootable=("system" in volume_path))
print ("--Step04:begin to attach nic.")
self.attach_nics(vm.name)
print ("--Step05:assign permission to vms.")
permissions_service = vm_service.permissions_service()
self.assign_permission(permissions_service, user, group)5、执行结果

- 标签:
-
其他