Esempio n. 1
0
def _maybe_glob_deps(deployment_id):
    matching_deployments = None
    if _is_a_glob(deployment_id):
        deps = Deployment.list(True)
        dep_ids = [d.dep_id for d in deps]
        matching_dep_ids = fnmatch.filter(dep_ids, deployment_id)
        matching_deployments = [
            d for d in deps if d.dep_id in matching_dep_ids
        ]
    else:
        matching_deployments = [Deployment.load(deployment_id)]
    return matching_deployments
Esempio n. 2
0
def tunnel(deployment_id,
           service=None,
           node=None,
           remote_port=None,
           local_port=None,
           local_address=None):
    """
    Creates an SSH port forwarding for the services that are running in the
    deployment DEPLOYMENT_ID.

    If SERVICE is not specified, you can use the --remote-port and --node to forward
    a generic service.
    """
    dep = Deployment.load(deployment_id)
    if service:
        if service == 'dashboard':
            click.echo(
                "Opening tunnel to service 'dashboard' in deployment '{}'...".
                format(dep.dep_id))
        else:
            click.echo("Opening tunnel to service '{}' on node '{}' of "
                       "deployment '{}'...".format(service, node, dep.dep_id))
    elif remote_port:
        click.echo(
            "Opening tunnel between remote {} port and local {} port on "
            "node '{}' of deployment '{}'...".format(
                remote_port, local_port if local_port else remote_port, node,
                dep.dep_id))
    dep.start_port_forwarding(service, node, remote_port, local_port,
                              local_address)
Esempio n. 3
0
def scp(recursive, deployment_id, source, destination):
    """
    Prepares and executes a 'scp' command to copy a file or entire directory
    from a cluster node to the host, or from the host to a cluster node.

    Takes three arguments: in addition to deployment_id, it needs both a source
    and destination, one of which will be in a special form:

        <node>:<path>

    Note: You can check the existing node names with the command
    "sesdev show <deployment_id>"

    For example, to copy the file /etc/os-release from the node 'master'
    on cluster (deployment_id) 'foo' to the current directory on the host:

        sesdev scp foo master:/etc/os-release .

    To recursively copy the entire directory "/bar" from the host to "/root/bar"
    on node1 in deployment foo:

        sesdev scp --recursive foo /bar node1:

    (From the cluster node's perspective, the scp operation will be done as
    root.)

    The --recursive option can also be abbreviated to -r and can appear anywhere
    in the command line, e.g.:

        sesdev scp foo -r /bar node1:
    """
    dep = Deployment.load(deployment_id)
    dep.scp(source, destination, recurse=recursive)
Esempio n. 4
0
def _create_command(deployment_id, deploy, settings_dict):
    interactive = not settings_dict.get('non_interactive', False)
    settings = Settings(**settings_dict)
    dep = Deployment.create(deployment_id, settings)
    if not dep.settings.devel_repo:
        if dep.settings.version not in Constant.CORE_VERSIONS:
            raise OptionNotSupportedInVersion('--product',
                                              dep.settings.version)
    really_want_to = None
    click.echo(
        "=== Creating deployment \"{}\" with the following configuration ===".
        format(deployment_id))
    click.echo(dep.status())
    if deploy:
        really_want_to = True
        if interactive:
            really_want_to = click.confirm(
                'Do you want to continue with the deployment?',
                default=True,
            )
        try:
            if really_want_to:
                dep.vet_configuration()
                if dep.settings.dry_run:
                    click.echo(
                        "Dry run. Stopping now, before creating any VMs.")
                    raise click.Abort()
                dep.start(_print_log)
                click.echo("=== Deployment Finished ===")
                click.echo()
                click.echo("You can login into the cluster with:")
                click.echo()
                click.echo("  $ sesdev ssh {}".format(deployment_id))
                click.echo()
                if dep.settings.version == 'ses5':
                    click.echo("Or, access openATTIC with:")
                    click.echo()
                    click.echo(
                        "  $ sesdev tunnel {} openattic".format(deployment_id))
                elif dep.settings.version == 'octopus' and dep.has_suma():
                    click.echo("Or, access the SUMA WebUI with:")
                    click.echo()
                    click.echo(
                        "  $ sesdev tunnel {} suma".format(deployment_id))
                    click.echo()
                else:
                    click.echo("Or, access the Ceph Dashboard with:")
                    click.echo()
                    click.echo(
                        "  $ sesdev tunnel {} dashboard".format(deployment_id))
                    click.echo()
            else:
                raise click.Abort()
        except click.Abort:
            click.echo()
            click.echo("Exiting...")
            dep.destroy(_silent_log)
Esempio n. 5
0
def add_repo(update, deployment_id, custom_repo):
    """
    Add a custom repo to all nodes of an already-deployed cluster. The repo
    should be specified in the form of an URL, but it is optional: if it is
    omitted, the "devel" repo (which has a specific meaning depending on the
    deployment version) will be added.
    """
    dep = Deployment.load(deployment_id)
    dep.add_repo_subcommand(custom_repo, update, _print_log)
Esempio n. 6
0
def replace_mgr_modules(deployment_id, **kwargs):
    """
    Fetches a different version of Ceph MGR modules from a local repository or github,
    replacing the installed ones.

    --local, --pr and --branch conflict with each other,
    when the first is found the remaining are ignored.
    """
    dep = Deployment.load(deployment_id)
    dep.replace_mgr_modules(**kwargs)
Esempio n. 7
0
def redeploy(deployment_id, **kwargs):
    """
    Destroys the VMs of the deployment DEPLOYMENT_ID and deploys again the cluster
    from scratch with the same configuration.
    """
    interactive = not (kwargs.get('non_interactive', False)
                       or kwargs.get('force', False))
    if interactive:
        really_want_to = True
        if interactive:
            really_want_to = click.confirm(
                'Do you want to continue with the deployment?',
                default=True,
            )
        if not really_want_to:
            raise click.Abort()
    dep = Deployment.load(deployment_id)
    dep.destroy(_print_log)
    dep = Deployment.create(deployment_id, dep.settings)
    dep.start(_print_log)
Esempio n. 8
0
def supportconfig(deployment_id, node):
    """
    Runs supportconfig on a node within an already-deployed cluster. Dumps the
    resulting tarball in the current working directory.

    If the node is not specified, it defaults to "master".

    NOTE: supportconfig is only available in deployments running on SUSE Linux
    Enterprise.
    """
    dep = Deployment.load(deployment_id)
    _node = 'master' if node is None else node
    dep.supportconfig(_print_log, _node)
Esempio n. 9
0
def remove_box(box_name, **kwargs):
    """
    Remove a Vagrant Box installed in the system by sesdev.

    This involves first removing the corresponding image from the libvirt
    storage pool, and then running 'vagrant box remove' on it.
    """
    settings_dict = _gen_box_settings_dict(**kwargs)
    settings = Settings(**settings_dict)
    #
    # existing deployments might be using this box
    deps = Deployment.list(True)
    existing_deployments = []
    for dep in deps:
        if box_name == dep.settings.os:
            existing_deployments.append(dep.dep_id)
    if existing_deployments:
        if len(existing_deployments) == 1:
            click.echo(
                "The following deployment is already using box ->{}<-:".format(
                    box_name))
        else:
            click.echo(
                "The following deployments are already using box ->{}<-:".
                format(box_name))
        for dep_id in existing_deployments:
            click.echo("        {}".format(dep_id))
        click.echo()
        if len(existing_deployments) == 1:
            click.echo("It must be destroyed first!")
        else:
            click.echo("These must be destroyed first!")
        sys.exit(-1)

    box_obj = Box(settings)

    if box_obj.exists(box_name):
        click.echo("Proceeding to remove Vagrant Box ->{}<-".format(box_name))
    else:
        click.echo("There is no Vagrant Box called ->{}<-".format(box_name))
        sys.exit(-1)

    image_to_remove = box_obj.get_image_by_box(box_name)
    if image_to_remove:
        click.echo("Found related image ->{}<- in libvirt storage pool".format(
            image_to_remove))
        box_obj.remove_image(image_to_remove)
        click.echo("Libvirt image removed.")

    box_obj.remove_box(box_name)
    click.echo("Vagrant Box removed.")
Esempio n. 10
0
def ssh(deployment_id, node=None, command=None):
    """
    Opens an SSH shell to, or runs optional COMMAND on, node NODE in deployment
    DEPLOYMENT_ID.

    If the node is not specified, it defaults to "master".

    Note: You can check the existing node names with the command
    "sesdev show <deployment_id>"
    """
    dep = Deployment.load(deployment_id)
    node_name = 'master' if node is None else node
    if command:
        log_msg = "Running SSH command on {}: {}".format(node_name, command)
        logger.info(log_msg)
    dep.ssh(node_name, command)
Esempio n. 11
0
def box_remove_handler(box_name, **kwargs):
    settings_dict = _gen_box_settings_dict(**kwargs)
    interactive = not settings_dict.get('non_interactive', False)
    settings = Settings(**settings_dict)
    box_obj = Box(settings)
    boxes_to_remove = box_obj.maybe_glob_boxes(box_name, simple=True)
    box_word = None
    if boxes_to_remove:
        box_word = _singular_or_plural(boxes_to_remove)
    else:
        return None
    if interactive:
        if boxes_to_remove:
            click.echo(
                "You have asked to remove the following {}".format(box_word))
            click.echo("---------------------------------------" +
                       len(box_word) * '-')
            for box_to_remove in boxes_to_remove:
                click.echo(box_to_remove)
            click.echo()
        really_want_to = click.confirm(
            'Do you really want to remove {} {}'.format(
                len(boxes_to_remove), box_word),
            default=True,
        )
        if not really_want_to:
            raise click.Abort()
    #
    # remove the boxes
    deps = Deployment.list(True)
    problems_encountered = False
    boxes_removed_count = 0
    for box_being_removed in boxes_to_remove:
        Log.info("Attempting to remove Vagrant Box ->{}<- ...".format(
            box_being_removed))
        #
        # existing deployments might be using this box
        existing_deployments = []
        for dep in deps:
            if box_being_removed == dep.settings.os:
                existing_deployments.append(dep.dep_id)
        if existing_deployments:
            if len(existing_deployments) == 1:
                Log.warning(
                    "The following deployment is already using Vagrant Box ->{}<-:"
                    .format(box_being_removed))
            else:
                Log.warning(
                    "The following deployments are already using Vagrant Box ->{}<-:"
                    .format(box_being_removed))
            for dep_id in existing_deployments:
                Log.warning("        {}".format(dep_id))
            click.echo()
            if len(existing_deployments) == 1:
                Log.warning("It must be destroyed first!")
            else:
                Log.warning("These must be destroyed first!")
            problems_encountered = True
            continue
        image_to_remove = box_obj.get_image_by_box(box_being_removed)
        if image_to_remove:
            Log.info(
                "Found related image ->{}<- in libvirt storage pool".format(
                    image_to_remove))
            box_obj.remove_image(image_to_remove)
            Log.info("Libvirt image removed.")
        box_obj.remove_box(box_being_removed)
        Log.info("Vagrant Box ->{}<- removed.".format(box_being_removed))
        boxes_removed_count += 1
    if boxes_removed_count != 1:
        click.echo("{} Vagrant Boxes were removed".format(boxes_removed_count))
    if problems_encountered:
        Log.warning("sesdev tried to remove {} Vagrant Box(es), but "
                    "problems were encountered.".format(len(boxes_to_remove)))
        click.echo("Use \"sesdev box list\" to check current state")
    return None
Esempio n. 12
0
def list_deps(format_opt):
    """
    Lists all the available deployments.
    """
    p_table = None
    deployments_list = []
    deps = Deployment.list(True)
    if deps:
        log_msg = "Found deployments: {}".format(", ".join(d.dep_id
                                                           for d in deps))
        logger.info(log_msg)
    else:
        msg = "No deployments found"
        logger.info(msg)
        if format_opt in ['json']:
            click.echo(json.dumps([], sort_keys=True, indent=4))
        else:
            click.echo(msg)
        return None

    def _status(nodes):
        status = None
        for node in nodes.values():
            if status is None:
                status = node.status
            elif node.status == 'running' and status == 'not deployed':
                status = 'partially deployed'
            elif node.status == 'stopped' and status == 'running':
                status = 'partially running'
            elif node.status == 'suspended' and status == 'running':
                status = 'partially running'
            elif node.status == 'running' and status == 'stopped':
                status = 'partially running'
            elif node.status == 'running' and status == 'suspended':
                status = 'partially running'
        return status

    if format_opt not in ['json']:
        p_table = PrettyTable(["ID", "Version", "Status", "Nodes"])
        p_table.align = "l"

    for dep in deps:
        logger.debug("Looping over deployments: %s", dep.dep_id)
        status = str(_status(dep.nodes))
        logger.debug("-> status: %s", status)
        version = getattr(dep.settings, 'version', None)
        logger.debug("-> version: %s", version)
        nodes = getattr(dep, 'nodes', None)
        node_names = '(unknown)' if nodes is None else ', '.join(nodes)
        logger.debug("-> node_names: %s", node_names)
        if format_opt in ['json']:
            deployments_list.append({
                "id": dep.dep_id,
                "version": version,
                "status": status,
                "nodes": list(nodes),
            })
        else:
            p_table.add_row([dep.dep_id, version, status, node_names])
    if format_opt in ['json']:
        click.echo(json.dumps(deployments_list, sort_keys=True, indent=4))
    else:
        deployment_word = "deployments" if len(deps) > 1 else "deployment"
        click.echo("Found {} {}:".format(len(deps), deployment_word))
        click.echo()
        click.echo(p_table)
        click.echo()
Esempio n. 13
0
def replace_ceph_salt(deployment_id, local=None):
    """
    Install ceph-salt from source
    """
    dep = Deployment.load(deployment_id)
    dep.replace_ceph_salt(local)
Esempio n. 14
0
def show(deployment_id):
    """
    Shows the information of deployment DEPLOYMENT_ID
    """
    dep = Deployment.load(deployment_id)
    click.echo(dep.status())
Esempio n. 15
0
def qa_test(deployment_id):
    """
    Runs QA test on an already-deployed cluster.
    """
    dep = Deployment.load(deployment_id)
    dep.qa_test(_print_log)