Skip to content
Snippets Groups Projects
Commit bd1375e5 authored by František Řezníček's avatar František Řezníček
Browse files

feat: initial kick of the migration script and documentation

parent 01b58ae6
No related branches found
No related tags found
No related merge requests found
......@@ -2,3 +2,29 @@
e-INFRA CZ G1 to G2 OpenStack cloud workload migration.
This is automation CI pipeline is core of the G1 to G2 migration process.
More details of the progress can be found [here](https://docs.e-infra.cz/compute/openstack/migration-to-g2-openstack-cloud/).
## Migration checklist
* [ ] Define date of the workload migration
* [ ] Is the project personal or group?
* [ ] Are there any data in object store?
* [ ] Are there any DNS records on FIPs?
## How to launch G1 to G2 migration
Input argumenta are:
* `PROJECT_NAME`
* name of the project in G1 and in G2 OpenStack cloud
* `KEYPAIR_ID`
* id of any existing keypair in G1 or G2 cloud
* `SERVER_NAME`
* migrate just single VM instance with defined name
#!/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()))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment