[automation-api/python] - Support recovery workflow (#6037)

This commit is contained in:
Komal 2021-01-12 19:27:21 -08:00 committed by GitHub
parent 059402483b
commit 89b1d0d2c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 87 additions and 9 deletions

View file

@ -32,6 +32,12 @@ CHANGELOG
- [sdk/dotnet] Fix looking up empty version in `ResourcePackages.TryGetResourceType`.
[#6084](https://github.com/pulumi/pulumi/pull/6084)
- Python Automation API.
[#5979](https://github.com/pulumi/pulumi/pull/5979)
- Support recovery workflow (import/export/cancel) in Python Automation API.
[#6037](https://github.com/pulumi/pulumi/pull/6037)
## 2.17.0 (2021-01-06)
- Respect the `version` resource option for provider resources.
@ -48,9 +54,6 @@ CHANGELOG
- [CLI] Add a confirmation prompt when using `pulumi policy rm`
[#6034](https://github.com/pulumi/pulumi/pull/6034)
- Python Automation API.
[#5979](https://github.com/pulumi/pulumi/pull/5979)
- [CLI] Ensure errors with the Pulumi credentials file
give the user some information on how to resolve the problem

View file

@ -449,7 +449,7 @@ func (l *LocalWorkspace) ImportStack(ctx context.Context, stackName string, stat
f, err := ioutil.TempFile(os.TempDir(), "")
if err != nil {
return errors.Wrap(err, "could not import stack. failed to get allocate temp file.")
return errors.Wrap(err, "could not import stack. failed to allocate temp file.")
}
defer func() { contract.IgnoreError(os.Remove(f.Name())) }()

View file

@ -22,7 +22,7 @@ from typing import Optional, List, Mapping, Callable
from .config import ConfigMap, ConfigValue
from .project_settings import ProjectSettings
from .stack_settings import StackSettings
from .workspace import Workspace, PluginInfo, StackSummary, WhoAmIResult, PulumiFn
from .workspace import Workspace, PluginInfo, StackSummary, WhoAmIResult, PulumiFn, Deployment
from .stack import _DATETIME_FORMAT, Stack
from .cmd import _run_pulumi_cmd, CommandResult, OnOutput
@ -256,6 +256,20 @@ class LocalWorkspace(Workspace):
plugin_list.append(plugin)
return plugin_list
def export_stack(self, stack_name: str) -> Deployment:
self.select_stack(stack_name)
result = self._run_pulumi_cmd_sync(["stack", "export", "--show-secrets"])
state_json = json.loads(result.stdout)
return Deployment(**state_json)
def import_stack(self, stack_name: str, state: Deployment) -> None:
self.select_stack(stack_name)
file = tempfile.NamedTemporaryFile(mode="w", delete=False)
json.dump(state.__dict__, file, indent=4)
file.close()
self._run_pulumi_cmd_sync(["stack", "import", "--file", file.name])
os.remove(file.name)
def _run_pulumi_cmd_sync(self, args: List[str], on_output: Optional[OnOutput] = None) -> CommandResult:
envs = {"PULUMI_HOME": self.pulumi_home} if self.pulumi_home else {}
envs = {**envs, **self.env_vars}

View file

@ -23,9 +23,9 @@ from typing import List, Any, Mapping, MutableMapping, Optional
from .cmd import CommandResult, _run_pulumi_cmd, OnOutput
from .config import ConfigValue, ConfigMap, _SECRET_SENTINEL
from .errors import StackAlreadyExistsError, CommandError
from .errors import StackAlreadyExistsError
from .server import LanguageServer
from .workspace import Workspace, PulumiFn
from .workspace import Workspace, PulumiFn, Deployment
from ...runtime.settings import _GRPC_CHANNEL_OPTIONS
from ...runtime.proto import language_pb2_grpc
@ -329,10 +329,9 @@ class Stack:
summary = self.info()
assert (summary is not None)
return PreviewResult(stdout=preview_result.stdout, stderr=preview_result.stderr, summary=summary)
except CommandError as exn:
finally:
if on_exit is not None:
on_exit()
raise
def refresh(self,
parallel: Optional[int] = None,
@ -497,6 +496,34 @@ class Stack:
return None
return history[0]
def cancel(self) -> None:
"""
Cancel stops a stack's currently running update. It returns an error if no update is currently running.
Note that this operation is _very dangerous_, and may leave the stack in an inconsistent state
if a resource operation was pending when the update was canceled.
This command is not supported for local backends.
"""
self.workspace.select_stack(self.name)
self._run_pulumi_cmd_sync(["cancel", "--yes"])
def export_stack(self) -> Deployment:
"""
export_stack exports the deployment state of the stack.
This can be combined with Stack.import_state to edit a stack's state (such as recovery from failed deployments).
:returns: Deployment
"""
return self.workspace.export_stack(self.name)
def import_stack(self, state: Deployment) -> None:
"""
import_stack imports the specified deployment state into a pre-existing stack.
This can be combined with Stack.export_state to edit a stack's state (such as recovery from failed deployments).
:param state: The deployment state to import.
"""
return self.workspace.import_stack(self.name, state)
def _run_pulumi_cmd_sync(self,
args: List[str],
on_output: Optional[OnOutput] = None) -> CommandResult:

View file

@ -85,6 +85,18 @@ class PluginInfo:
self.version = version
class Deployment:
version: Optional[int]
deployment: Optional[Mapping[str, Any]]
def __init__(self, version: Optional[int] = None, deployment: Optional[Mapping[str, Any]] = None) -> None:
self.version = version
self.deployment = deployment
def __repr__(self):
return f"Deployment(version={self.version!r}, deployment={self.deployment!r})"
class Workspace(ABC):
"""
Workspace is the execution context containing a single Pulumi project, a program, and multiple stacks.
@ -346,3 +358,25 @@ class Workspace(ABC):
:returns: List[PluginInfo]
"""
pass
@abstractmethod
def export_stack(self, stack_name: str) -> Deployment:
"""
ExportStack exports the deployment state of the stack matching the given name.
This can be combined with ImportStack to edit a stack's state (such as recovery from failed deployments).
:param stack_name: The name of the stack to export.
:returns: Deployment
"""
pass
@abstractmethod
def import_stack(self, stack_name: str, state: Deployment) -> None:
"""
ImportStack imports the specified deployment state into a pre-existing stack.
This can be combined with ExportStack to edit a stack's state (such as recovery from failed deployments).
:param stack_name: The name of the stack to import.
:param state: The deployment state to import.
"""
pass