def create_compute_instance_for_endpoint()

in mds_plugin/util.py [0:0]


def create_compute_instance_for_endpoint(**kwargs):
    """Returns a public compute instance

    If the instance does not yet exists in the compartment, create it

    Args:
        **kwargs: Optional parameters

    Keyword Args:
        instance_name (str): The name of the compute instance
        db_system_name (str): The new name of the DB System.
        db_system_id (str): The OCID of the db_system
        private_key_file_path (str): The file path to an SSH private key
        subnet_id (str): The OCID of the subnet to use
        public_ip (bool): If set to false, no public IP will be assigned
        shape (str): The name of the shape to use
        cpu_count (int): The number of OCPUs
        memory_size (int): The amount of memory
        dns_a_record_notification (bool): Whether to print a message to setup the DNS A record for this instance
        domain_name (str): The domain name of the compute instance
        compartment_id (str): The OCID of the compartment
        config (object): An OCI config object or None.
        config_profile (str): The name of an OCI config profile
        interactive (bool): Indicates whether to execute in interactive mode
        raise_exceptions (bool): If set to true exceptions are raised
        return_formatted (bool): If set to true, a list object is returned
        return_python_object (bool): Used for internal plugin calls

    Returns:
       None
    """
    instance_name = kwargs.get("instance_name", "MDSJumpHost")
    db_system_name = kwargs.get("db_system_name")
    db_system_id = kwargs.get("db_system_id")
    private_key_file_path = kwargs.get(
        "private_key_file_path", "~/.ssh/id_rsa")
    public_ip = kwargs.get("public_ip", True)
    subnet_id = kwargs.get("subnet_id")
    shape = kwargs.get("shape", "VM.Standard.E4.Flex")
    cpu_count = kwargs.get("cpu_count", 1)
    memory_size = kwargs.get("memory_size", 16)
    dns_a_record_notification = kwargs.get("dns_a_record_notification", False)
    domain_name = kwargs.get("domain_name")

    compartment_id = kwargs.get("compartment_id")
    config = kwargs.get("config")
    config_profile = kwargs.get("config_profile")

    interactive = kwargs.get("interactive", core.get_interactive_default())
    raise_exceptions = kwargs.get("raise_exceptions", not interactive)
    return_formatted = kwargs.get("return_formatted", interactive)
    return_python_object = kwargs.get("return_python_object", False)

    # Get the active config and compartment
    try:
        config = configuration.get_current_config(
            config=config, config_profile=config_profile,
            interactive=interactive)
        compartment_id = configuration.get_current_compartment_id(
            compartment_id=compartment_id, config=config)

        import oci.mysql
        from pathlib import Path
        import os.path
        from mds_plugin import compartment, compute, network
        import time

        db_system = mysql_database_service.get_db_system(
            db_system_name=db_system_name, db_system_id=db_system_id,
            compartment_id=compartment_id, config=config,
            interactive=interactive, raise_exceptions=True,
            return_python_object=True)
        if db_system is None:
            raise ValueError("DB System not specified or found.")

        # Get compartment and public subnet_id from MDS
        if not compartment_id:
            compartment_id = db_system.compartment_id
        if not subnet_id:
            mds_subnet = network.get_subnet(
                subnet_id=db_system.subnet_id,
                config=config, interactive=False)
            subnet = network.get_subnet(
                network_id=mds_subnet.vcn_id,
                public_subnet=public_ip,
                config=config,
                interactive=False)
            if subnet:
                subnet_id = subnet.id

        if not subnet_id:
            if public_ip:
                raise ValueError(
                    'The network used by the MDS instance does not have public subnet.'
                    'Please add a public subnet first')
            else:
                raise ValueError('No subnet specified.')

        # Try to get the Compute Instance with the given name
        mds_jump_host = compute.get_instance(
            instance_name=instance_name,
            compartment_id=compartment_id,
            config=config, interactive=False,
            raise_exceptions=True,
            return_python_object=True)

        # If it already exists, return it
        if mds_jump_host:
            return mds_jump_host

        # if interactive:
        #     # If there is no MySQL DBSystemProxy instance yet, ask the user
        #     print(f"In order to perform the requested operation for the MySQL "
        #           f"DB System\na compute instance named 'MDSJumpHost' "
        #           f"needs to be created.\n")
        #     prompt = core.prompt(
        #         "Do you want to create a new compute instance to be used as "
        #         "bastion host? [YES/no]: ",
        #         {'defaultValue': 'yes'}).strip().lower()
        #     if prompt != "yes":
        #         print("Operation cancelled.\n")
        #         return

        if interactive:
            print(f"Creating Compute Instance '{instance_name}'...")

        new_jump_host = compute.create_instance(
            instance_name=instance_name,
            shape=shape,
            cpu_count=cpu_count, memory_size=memory_size,
            operating_system="Oracle Linux",
            operating_system_version="9",
            use_latest_image=True,
            subnet_id=subnet_id,
            public_subnet=public_ip,
            init_script_file_path=os.path.join(
                os.path.join(Path(__file__).parent.absolute(), "internal"), "init_router_script.sh"),
            interactive=False,
            return_python_object=True)
        if new_jump_host is None:
            print("Compute instance could not be created.")
            return

        # Initialize the identity client
        compute_client = core.get_oci_compute_client(config=config)

        print(f"Waiting for Compute Instance '{instance_name}' to become "
              "available.\nThis can take up to 5 minutes or more.", end="")

        # Wait until the lifecycle_state == RUNNING, 5 minutes max
        try:
            cycles = 0
            while cycles < 60:
                mds_jump_host = compute_client.get_instance(
                    new_jump_host.id).data
                if mds_jump_host.lifecycle_state == "RUNNING":
                    break
                else:
                    time.sleep(5)
                    print(".", end="")
                cycles += 1
            print("")
        except oci.exceptions.ServiceError as e:
            print(f'Could not fetch the compute instances state.\n'
                  f'ERROR: {e.message}. (Code: {e.code}; Status: {e.status})')
            return
        if mds_jump_host.lifecycle_state != "RUNNING":
            print(f"Compute Instance '{instance_name}' did not become available "
                  f"within 5 minutes. Please check the state manually.")
            return None if interactive else mds_jump_host

        if interactive:
            print(f"Compute Instance '{instance_name}' became available.")

        # Get the public IP of the instance
        public_ip = compute.get_instance_public_ip(
            instance_id=mds_jump_host.id, compartment_id=compartment_id,
            config=config, private_ip_fallback=True)
        if public_ip is None or public_ip == "":
            raise Exception(
                f"The public IP of the {instance_name} instance could not be "
                "fetched.")

        if dns_a_record_notification and interactive:
            print("\nATTENTION: Please create a DNS A record using the following values.\n"
                  f"Domain: {domain_name}\n"
                  f"Destination TCP/IP address: {public_ip}")

            answered = False
            while not answered:
                try:
                    result = core.prompt(
                        f"Please click OK once the DNS A record has been created. [OK/Cancel]: ",
                        {"defaultValue": "OK"})
                    answered = True
                except:
                    print(
                        "Please select OK or Cancel on the confirmation notification.")
                    pass

            if result != "OK":
                raise Exception(
                    "Endpoint creation cancelled. Please delete the compute instance that has been created.")

        if interactive:
            print("\nPerforming base configuration.\n"
                  f"Connecting to {instance_name} instance at {public_ip}...",
                  end="")

        setup_complete = False
        connected = False
        cycles = 0
        while not setup_complete and cycles < 10:
            cycles += 1
            try:
                with compute.SshConnection(
                        username="opc", host=public_ip,
                        private_key_file_path=private_key_file_path) as conn:

                    connected = True
                    if interactive:
                        print(f"\nConnected to {instance_name} instance at "
                              f"{public_ip}.")

                    # Get MySQL Router configuration from remote instance
                    output = ""
                    output = conn.execute('mysqlsh --js -e "mds.info()"').strip()
                    if "MySQL Shell MDS Plugin" not in output:
                        # If the config is not available yet, give the instance
                        # time to complete setup
                        if interactive:
                            print(f"Waiting for {instance_name} setup to be "
                                  f"completed.\nThis can take up to 2 minutes.",
                                  end="")
                        try:
                            i = 0
                            while ("MySQL Shell MDS Plugin" not in output
                                   and i < 25):
                                output = conn.execute(
                                    'mysqlsh --js -e "mds.info()"').strip()
                                if "MySQL Shell MDS Plugin" not in output:
                                    time.sleep(5)
                                    if interactive:
                                        print(".", end="")
                                i += 1
                        except:
                            pass

                        if interactive:
                            print("")

                    if "MySQL Shell MDS Plugin" not in output:
                        raise Exception(
                            f"\nCould not finish the '{instance_name}' setup "
                            f"at {public_ip}.\n")
                    else:
                        setup_complete = True

            except Exception as e:
                if cycles < 10 and not connected:
                    time.sleep(5)
                    if interactive:
                        print(".", end="")
                else:
                    raise Exception(
                        f"Could not connect to compute instance "
                        f"'{instance_name}' at {public_ip}.\n"
                        f"ERROR: {str(e)}")

        if interactive:
            print(f"Compute Instance '{instance_name}' successfully created.")

        return core.return_oci_object(
            oci_object=new_jump_host,
            return_formatted=return_formatted,
            return_python_object=return_python_object,
            format_function=compute.format_instance_listing)
    except Exception as e:
        if raise_exceptions:
            raise
        print(f"ERROR: {str(e)}")