Пример #1
0
def push_command(
    workspace: Workspace,
    only: Optional[List[str]] = None,
    skip: Optional[List[str]] = None,
    only_workspace: bool = False,
) -> int:
    """Run the push command on the pushable resources and the workspace.
    """
    if only_workspace:
        if isinstance(workspace, CentralWorkspaceMixin):
            raise ConfigurationError(
                "--only-workspace not valid for central workspace %s" % workspace.name
            )
        resource_list = []  # type: List[LocalStateResourceMixin]
    else:
        resource_list = [
            cast(LocalStateResourceMixin, workspace.get_resource(rn))
            for rn in build_resource_list(workspace, only, skip)
        ]

    if isinstance(workspace, CentralWorkspaceMixin):
        if len(resource_list) == 0:
            click.echo("No resources to push.")
            return 0
        else:
            print(
                "Pushing resources: %s" % ", ".join([cast(Resource, r).name for r in resource_list])
            )
            workspace.push_resources(resource_list)
    elif isinstance(workspace, SyncedWorkspaceMixin):
        if len(resource_list) > 0:
            click.echo(
                "Pushing workspace and resources: %s"
                % ", ".join([cast(Resource, r).name for r in resource_list])
            )
        elif not only_workspace:
            click.echo("No resources to push, will still push workspace")
        else:
            click.echo("Pushing workspace.")
        workspace.push(resource_list)

    workspace.save("push command")
    return len(resource_list)
Пример #2
0
def config_command(
    workspace: Workspace,
    param_name: Optional[str],
    param_value: Optional[str],
    resource: Optional[str],
):
    if param_name is None and param_value is None:
        names = []
        scopes = []
        values = []
        isdefaults = []
        helps = []
        if resource is None:
            handlers = [
                GlobalWorkspaceHandler(workspace),
                LocalWorkspaceHandler(workspace),
            ]  # type: List[ParamConfigHandler]
        else:
            if resource not in workspace.get_resource_names():
                raise ConfigurationError(
                    "No resource in this workspace with name '%s'" % resource)
            resource_obj = workspace.get_resource(resource)
            handlers = [GlobalResourceHandler(resource_obj, workspace)]
            if isinstance(resource_obj, LocalStateResourceMixin):
                handlers.append(LocalResourceHandler(resource_obj, workspace))
        for handler in handlers:
            for name in handler.defs.keys():
                names.append(name)
                scopes.append(handler.get_scope())
                helps.append(handler.defs[name].help)
                values.append(handler.get_value(name))
                isdefaults.append("Y" if handler.is_default(name) else "N")
        print_columns(
            {
                "Name": names,
                "Scope": scopes,
                "Value": values,
                "Default?": isdefaults,
                "Description": helps,
            },
            spec={"Description": ColSpec(width=40)},
            paginate=False,
        )
        click.echo()
    else:
        assert param_name is not None
        if resource is None:
            if param_name in PARAM_DEFS:
                handler = GlobalWorkspaceHandler(workspace)
            elif param_name in LOCAL_PARAM_DEFS:
                handler = LocalWorkspaceHandler(workspace)
            else:
                raise ParamNotFoundError("No workspace parameter named '%s'" %
                                         param_name)
        else:  # resource-specific
            if resource not in workspace.get_resource_names():
                raise ConfigurationError(
                    "No resource in this workspace with name '%s'" % resource)
            resource_obj = workspace.get_resource(resource)
            if isinstance(resource_obj, LocalStateResourceMixin) and (
                    param_name in resource_obj.get_local_params()):
                handler = LocalResourceHandler(resource_obj, workspace)
            elif param_name in resource_obj.get_params().keys():
                handler = GlobalResourceHandler(resource_obj, workspace)
            else:
                raise ParamNotFoundError(
                    "Resource %s has no parameter named '%s'" %
                    (resource, param_name))

        if param_value is None:
            # just print for the specific param
            title = "%s parameter '%s'" % (handler.get_what_for().capitalize(),
                                           param_name)
            click.echo(title)
            click.echo("=" * len(title))
            click.echo()
            print_columns(
                {
                    "Value": [handler.get_value(param_name)],
                    "Scope": [handler.get_scope()],
                    "Default?":
                    ["Y" if handler.is_default(param_name) else "N"],
                    "Description": [handler.defs[param_name].help],
                },
                spec={"Description": ColSpec(width=60)},
                paginate=False,
            )
            click.echo()
        else:  # setting the parameter
            parsed_value = handler.defs[param_name].parse(param_value)
            handler.set_value(param_name,
                              handler.defs[param_name].to_json(parsed_value))
            param_for = handler.get_what_for()
            workspace.save("Update of %s parameter %s" %
                           (param_for, param_name))
            click.echo("Successfully set %s %s parameter '%s' to %s." %
                       (param_for, handler.get_scope(), param_name,
                        repr(parsed_value)))
Пример #3
0
def restore_command(
    workspace: Workspace,
    tag_or_hash: str,
    only: Optional[List[str]] = None,
    leave: Optional[List[str]] = None,
    strict: bool = False,
) -> int:
    """Run the restore and return the number of resources affected.
    """
    if not isinstance(workspace, SnapshotWorkspaceMixin):
        raise ConfigurationError("Workspace %s does not support snapshots" %
                                 workspace.name)
    mixin = cast(SnapshotWorkspaceMixin, workspace)
    # First, find the history entry
    md = mixin.get_snapshot_by_tag_or_hash(tag_or_hash)

    # process the lists of resources
    current_names = set(workspace.get_resource_names())
    # get the non-null resources in snapshot
    snapshot_names = set([
        rn for rn in md.restore_hashes.keys()
        if md.restore_hashes[rn] is not None
    ])
    all_names = current_names.union(snapshot_names)
    if (only is not None) and (leave is not None):
        raise ApiParamError(
            "Cannot specify both only and leave for restore command.")
    elif only is not None:
        # For only, we will be a little stricter, as the user is explicitly
        # specifying the resources.
        restore_set = set(only)
        strict = True
    elif leave is not None:
        restore_set = all_names.difference(leave)
    else:
        restore_set = all_names

    # We need to remove result resources from the restore set, as we
    # do not restore them to their prior state.
    result_resources = {
        rname
        for rname in restore_set
        if workspace.get_resource_role(rname) == ResourceRoles.RESULTS
    }
    result_resources_in_restore_set = result_resources.intersection(
        restore_set)
    if len(result_resources_in_restore_set) > 0:
        if strict:
            raise ConfigurationError(
                "Restore set contains result resources, which cannot be restored. The following are result resources: %s"
                % ", ".join(result_resources_in_restore_set))
        else:
            click.echo(
                "Skipping the restore of the following result resources, which are left in their latest state: %s"
                % ", ".join(result_resources_in_restore_set))
            restore_set = restore_set.difference(result_resources)

    # error checking
    invalid = restore_set.difference(all_names)
    if len(invalid) > 0:
        raise ConfigurationError("Resource name(s) not found: %s" %
                                 ", ".join(sorted(invalid)))
    removed_names = restore_set.difference(current_names)
    if len(removed_names) > 0:
        if strict:
            raise ConfigurationError(
                "Resources have been removed from workspace or have no restore hash and strict mode is enabled."
                + " Removed resources: %s" % ", ".join(sorted(removed_names)))
        else:
            click.echo(
                "Skipping restore of resources that have been removed from workspace or have no restore hash: %s"
                % ", ".join(sorted(removed_names)),
                err=True,
            )
            restore_set = restore_set.difference(removed_names)
    added_names = restore_set.difference(snapshot_names)
    if len(added_names) > 0:
        if strict:
            raise ConfigurationError(
                "Resources have been added to workspace since restore, and strict mode enabled."
                + " Added resources: %s" % ", ".join(sorted(added_names)))
        else:
            click.echo(
                "Resources have been added to workspace since restore, will leave them as-is: %s"
                % ", ".join(sorted(added_names)),
                err=True,
            )
            restore_set = restore_set.difference(added_names)

    # get ordered list of names and resources as well as restore hashes
    restore_name_list = [
        rn for rn in workspace.get_resource_names() if rn in restore_set
    ]
    if len(restore_name_list) == 0:
        click.echo("No resources to restore.")
        return 0
    restore_resource_list = [
        workspace.get_resource(rn) for rn in restore_name_list
    ]
    for r in restore_resource_list:
        if not isinstance(r, SnapshotResourceMixin):
            raise InternalError(
                "Resource %s was in snapshot, but is not a SnapshotResourceMixin"
                % r.name)
    restore_hashes = {rn: md.restore_hashes[rn] for rn in restore_set}

    tagstr = " (%s)" % ",".join(md.tags) if len(md.tags) > 0 else ""
    click.echo("Restoring snapshot %s%s" % (md.hashval, tagstr))

    def fmt_rlist(rnames):
        if len(rnames) > 0:
            return ", ".join(rnames)
        else:
            return "None"

    click.echo("  Resources to restore: %s" % fmt_rlist(restore_name_list))
    names_to_leave = sorted(current_names.difference(restore_set))
    click.echo("  Resources to leave: %s" % fmt_rlist(names_to_leave))
    if not workspace.batch:
        # Unless in batch mode, we always want to ask for confirmation
        resp = input("Should I perform this restore? [Y/n]")
        if resp.lower() != "y" and resp != "":
            raise UserAbort()

    # do the work!
    mixin.restore(md.hashval, restore_hashes,
                  cast(List[SnapshotResourceMixin], restore_resource_list))
    workspace.save("Restore to %s" % md.hashval)

    return len(restore_name_list)