-
František Řezníček authoredbd1375e5
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
project-migrator.py 6.01 KiB
#!/usr/bin/env python3
"""
OpenStack project multicloud migrator
"""
import argparse
import re
import sys
import paramiko
import keystoneauth1.session
from keystoneauth1.identity import v3
from openstack import connection
from keystoneauth1 import session
def get_openrc(file_handle):
""" parse and return OpenRC file """
openrc_vars = {}
for line in file_handle:
match = re.match(r'^export (\w+)=(.+)$', line.strip())
if match:
openrc_vars[match.group(1)] = match.group(2).strip('"')
return openrc_vars
def get_ostack_session_connection(openrc_vars):
""" """
auth_args = {
'auth_url': openrc_vars.get('OS_AUTH_URL'),
'username': openrc_vars.get('OS_USERNAME'),
'password': openrc_vars.get('OS_PASSWORD'),
'project_name': openrc_vars.get('OS_PROJECT_NAME'),
'project_domain_name': openrc_vars.get('OS_PROJECT_DOMAIN_NAME'),
'user_domain_name': openrc_vars.get('OS_USER_DOMAIN_NAME'),
'project_domain_id': openrc_vars.get('OS_PROJECT_DOMAIN_ID'),
'user_domain_id': openrc_vars.get('OS_USER_DOMAIN_ID'),
}
auth = v3.Password(**auth_args)
ostack_sess = session.Session(auth=auth)
ostack_conn = connection.Connection(session=ostack_sess)
return ostack_sess, ostack_conn
def get_ostack_project(ostack_connection, project_name):
project = None
for i_project in ostack_connection.list_projects():
if i_project.name == project_name:
project = i_project
return project
def get_ostack_project_keypairs(ostack_connection, project_name):
return ostack_connection.compute.keypairs()
def get_ostack_project_security_groups(ostack_connection, project_name):
return ostack_connection.network.security_groups()
def get_ostack_project_servers(ostack_connection, project_name):
return ostack_connection.compute.servers()
def get_ostack_project_volumes(ostack_connection, project_name):
return ostack_connection.block_store.volumes()
def remote_cmd_exec(hostname, username, key_filename, command):
# Create SSH client
ssh_client = paramiko.SSHClient()
# Automatically add untrusted hosts
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
# Connect to the remote host
pkey = paramiko.RSAKey.from_private_key_file(key_filename)
ssh_client.connect(hostname, username=username, pkey=pkey, look_for_keys=False)
# Execute the command
stdin, stdout, stderr = ssh_client.exec_command(command)
# Read the output
output = stdout.read().decode().strip()
# Close the SSH connection
ssh_client.close()
return output
except Exception as e:
print("Error:", e)
return None
def main(args):
""" """
# connect to source cloud
source_openrc = get_openrc(args.source_openrc)
source_sess, source_conn = get_ostack_session_connection(source_openrc)
# connect to destination cloud
destination_openrc = get_openrc(args.destination_openrc)
destination_sess, destination_conn = get_ostack_session_connection(destination_openrc)
# check project exists in source and destination
source_project = get_ostack_project(source_conn, args.project_name)
destination_project = get_ostack_project(destination_conn, args.project_name)
# connect to migrator node
reply = remote_cmd_exec(args.ceph_migrator_host, args.ceph_migrator_user,
args.ceph_migrator_sshkeyfile.name, 'uname -a')
# get source/destination keypairs
source_keypairs = get_ostack_project_keypairs(source_conn, args.project_name)
destination_keypairs = get_ostack_project_keypairs(destination_conn, args.project_name)
# get source/destination security groups
source_security_groups = get_ostack_project_security_groups(source_conn, args.project_name)
destination_security_groups = get_ostack_project_security_groups(destination_conn, args.project_name)
# get source/destination servers in the project
source_project_servers = get_ostack_project_servers(source_conn, args.project_name)
destination_project_servers = get_ostack_project_servers(destination_conn, args.project_name)
# get source/destination volumes in the project
source_project_volumes = get_ostack_project_volumes(source_conn, args.project_name)
destination_project_volumes = get_ostack_project_volumes(destination_conn, args.project_name)
#print(dir(source_conn))
print(locals())
# connect to source cloud
# connect to ceph migrator node
pass
# main() call (argument parsing)
# ---------------------------------------------------------------------------
if __name__ == "__main__":
AP = argparse.ArgumentParser(epilog=globals().get('__doc__'),
formatter_class=argparse.RawDescriptionHelpFormatter)
AP.add_argument('--source-openrc', default=None, type=argparse.FileType('r'),
required=True, help='Source cloud authentication (OpenRC file)')
AP.add_argument('--destination-openrc', default=None, type=argparse.FileType('r'),
required=True, help='Destination cloud authentication (OpenRC file)')
AP.add_argument('--ceph-migrator-host', default='controller-ostack.stage.cloud.muni.cz',
help='OpenStack migrator ceph node host')
AP.add_argument('--ceph-migrator-user', default='root',
help='OpenStack migrator ceph node username')
AP.add_argument('--ceph-migrator-sshkeyfile', default=None, type=argparse.FileType('r'),
help='OpenStack migrator SSH keyfile')
AP.add_argument('--project-name', default=None, required=True,
help='OpenStack project name (identical in both clouds)')
AP.add_argument('--keypair-id', default=None, required=True,
help='Any keypair ID within selected OpenStack project')
#AP.add_argument('--hide-skipped-actions', default=False, action='store_true',
# help="Hide skipped ansible actions")
sys.exit(main(AP.parse_args()))