trappo/steps/
rollback.rs

1//! Contains the default steps performed during a rollback.
2use steps::{Step, Context, error::StepError};
3use cmd::*;
4
5const NO_PREV_ERR_MSG: &str = "Can't rollback because there is no release to rollback to.";
6
7/// Checks whether or not there is a release to rollback to.
8pub struct CanRollBack;
9
10/// Checks whether or not there is a release to rollback to. If the `Context.prev_release_path`
11/// contains a `None`, then the rollback is not possible.
12impl Step for CanRollBack {
13
14    fn execute (&self, context: &Context) -> Result<(), StepError> {
15        context.prev_release_path.as_ref().ok_or(StepError::Critical(NO_PREV_ERR_MSG.into())).map(|_| ())
16    }
17
18    fn get_name(&self) -> &str {
19        "rollback:check"
20    }
21}
22
23/// Removes all the files from the relase we are rolling back from.
24/// Note this doesn't include the shared files and directories which are shared
25/// accross releases.
26pub struct RemoveCurrentRelease;
27
28/// Removes all the files from the relase we are rolling back from.
29impl Step for RemoveCurrentRelease {
30
31    fn execute (&self, context: &Context) -> Result<(), StepError> {
32
33        let release_path = &context.release_path;
34        let cmd = format!("rm -rf {}", release_path);
35        let output = exec_remote_cmd(&context.config.host, &cmd)?;
36
37        match output.status.success() {
38            true => Ok(()),
39            false => {
40                let err_msg = format!("Failed to remove current release at {}", release_path);
41                Err(StepError::Critical(err_msg))
42            }
43        }
44    }
45
46    fn get_name(&self) -> &str {
47        "rollback:rm:latest"
48    }
49}
50
51/// Points the current symlink to the previous relases, completing the rollback.
52pub struct SymlinkPreviousRelease;
53
54impl Step for SymlinkPreviousRelease {
55
56    fn execute (&self, context: &Context) -> Result<(), StepError> {
57
58        let current_symlink_path = format!("{}/current", context.config.deploy_path);
59        let current_symlink_exist = exec_remote_file_exists(&context.config.host, &current_symlink_path, FSResourceType::Symlink)?;
60
61        //remove current symlink if it exists.
62        if current_symlink_exist {
63            let remove_current_command = format!("rm {}", current_symlink_path);
64
65            let status = exec_remote_cmd(&context.config.host, &remove_current_command)?.status;
66
67            if !status.success() {
68                return Err(StepError::from_failed_command(&remove_current_command, status.code()));
69            }
70        }
71
72        let prev_release_path = context.prev_release_path.as_ref().unwrap();
73        let create_current_symlink_cmd = format!("ln -s {} {}", prev_release_path.trim(), current_symlink_path);
74        let status = exec_remote_cmd(&context.config.host, &create_current_symlink_cmd)?.status;
75
76        if !status.success() {
77            return Err(StepError::from_failed_command(&create_current_symlink_cmd, status.code()));
78        }
79
80        Ok(())
81    }
82
83    fn get_name(&self) -> &str {
84        "rollback:symlink:previous"
85    }
86}