Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rust): Implement upgrade and uninstall commands #5171

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from

Conversation

BradLewis
Copy link
Contributor

@BradLewis BradLewis commented Jun 26, 2023

I've created this as a draft PR for now to get your feedback on this approach. It probably needs more work with things like the error handling and the messages, but I figured it'd be worthwhile getting feedback on the more "happy" paths before working on making that better. Let me know what you think!

Current behavior

Currently there is no way for the user to upgrade or uninstall ockam directly through the binary.

Proposed changes

Resolves #4916

This PR adds both an upgrade and uninstall command.

Upgrade

For the upgrade command it works as follows:

  1. Checks to see if a new update is available by checking the github releases.
  2. Stops all the running nodes.
  3. Checks to see if it was installed via homebrew. If it was it runs brew upgrade ockam. It will then restart all the nodes it stopped in step 2.
  4. If it was installed via the install.sh script it will check to see if it can find location of the script by looking at $OCKAM_HOME or $HOME/.ockam. If it can't find it then it stops the upgrade.
  5. If all is okay to upgrade, it will delete the existing ockam binary.
  6. It will then upgrade ockam using the install.sh script, specifying the specific version and the install path.
  7. Once the upgrade is completed, it'll restart all the nodes that were stopped in step 2.

In order to do this I made some slight changes, namely writing the install.sh script to the $OCKAM_HOME folder, and add the $OCKAM_HOME variable to the environment variable files.

I also implemented some logic to fetch the latest versions from the releases on github rather than the upgrade.json file as I found that the upgrade.json file seems to be out of date? (0.87.0 and 0.88.0 are empty, and 0.86.0 points to 0.87.0 etc). Not sure if this is intentional however.

Uninstall

For the uninstall command,

  1. it will first check if it was uninstalled through the install.sh script or with homebrew.
  2. If it was installed with homebrew, it'll run brew uninstall ockam, otherwise it'll delete the ockam binary.
  3. It will then clear all references to $OCKAM_HOME and then delete the $OCKAM_HOME directory.

I'm not sure about this final step however as it'll delete all the metadata on nodes and whatnot the user has, which could be troublesome if they just wanted to do a simple uninstall/reinstall to fix an issue or something. Let me know what you think of that.

Checks

@mrinalwadhwa
Copy link
Member

@BradLewis this is awesome, thank you for spending time on this. I'll try the commands and leave some thoughts soon

@BradLewis BradLewis force-pushed the bradlewis/implement-upgrade-command branch 4 times, most recently from 3418080 to c153f5c Compare June 27, 2023 21:43
@BradLewis
Copy link
Contributor Author

BradLewis commented Jun 27, 2023

Okay I've refactored the implementation quite a bit and improved the error handling as well. This split the upgrade and uninstall process for homebrew and binary installations into 2 separate logical flows. For homebrew it's pretty simple, just run the respective commands. For the binary installation it's a little more involved.

For upgrade:

  1. Backup binary and environment files
  2. Remove ockam lines in the environment files
  3. Download installation script
  4. Run the installation script to install the latest version and rewrite all the environment files.
    If any point in the process fails, everything gets restored from backup

For installation it follows a similar pattern, with everything being backed up and restored if anything goes wrong.

Let me know what you think, and if you like this approach I'll open this as a non-draft PR 🙂

@BradLewis BradLewis marked this pull request as ready for review June 28, 2023 22:45
@BradLewis BradLewis requested a review from a team as a code owner June 28, 2023 22:45
@BradLewis BradLewis force-pushed the bradlewis/implement-upgrade-command branch 4 times, most recently from 2b9ee3e to 78760ec Compare June 30, 2023 20:23
Copy link
Member

@etorreborre etorreborre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @BradLewis I left a bunch of comments and suggestions for you to consider. Next I would like to test your PR a bit on my machine to double-check that it is also working for me. How have you tested it so far?

if let Ok(r) = resp {
if let Ok(upgrade) = r.json::<UpgradeFile>().await {
if let Some(message) = upgrade.upgrade_message {
eprintln!("\n{}", message.yellow());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to use the opts.terminal instead of eprintln here.

Copy link
Contributor Author

@BradLewis BradLewis Jul 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was also part of the original code that checked for the latest version from the version.json file on GitHub, I just moved it to this file. I can refactor this as part of this PR as well if you would like.

I could also rework this to not use the version.json file and instead just pull the latest version from the GitHub releases?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can refactor this as part of this PR as well if you would like.

I see. Yes that would be nice. We are trying to move away from bare printlns in order to completely control the rendering in the terminal.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could also rework this to not use the version.json file and instead just pull the latest version from the GitHub releases?

I don't understand that part. Are you talking about the upgrade.json file? I actually tried to download it from https://github.com/build-trust/ockam/releases/download/ockam_v0.90.0/upgrade.json and it comes back empty. Is that the same for you too? Because then this means that we also need to fix that part somewhere in our release process (FYI @metaclips)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah exactly. I mentioned it in the description for this PR, but I found that the upgrade.json were never really up-to-date. You can play around with it by changing the version in the Cargo.toml file. Currently I only no suggestions for 0.89.0, 0.88.0 and 0.87.0. If I set it to 0.86.0 then it informs me that there is an update available, but that the latest version is 0.87.0.
image
Currently it pulls this information from the release of the version that the user is using, meaning these files would need to be updated every release to be effective.
That's why I ended up just pulling the latest version from the release instead of just using the version.json file.

@BradLewis BradLewis force-pushed the bradlewis/implement-upgrade-command branch from 78760ec to 8feee2a Compare July 4, 2023 23:21
@BradLewis BradLewis changed the title feature(rust): Implement upgrade and uninstall commands feat(rust): Implement upgrade and uninstall commands Jul 5, 2023
@BradLewis BradLewis force-pushed the bradlewis/implement-upgrade-command branch 2 times, most recently from 9f82eeb to f8f4e2a Compare July 5, 2023 11:42
@BradLewis
Copy link
Contributor Author

BradLewis commented Jul 5, 2023

Hi @BradLewis I left a bunch of comments and suggestions for you to consider. Next I would like to test your PR a bit on my machine to double-check that it is also working for me. How have you tested it so far?

So for testing I've been setting the version to something lower, eg 0.88.0, building the project and then moving the binary to the location I would like it to be. For testing with brew, I replace the binary that brew installs, for the script installation, I replace the binary there and for the standalone installation I just run it from the cargo build directory.

From there I just make sure all the nodes have restarted and if it was installed via the script, that all the environment files were updated correctly.

I will say this is definitely one that needs to be tested thoroughly given all the changes it can make on the end users machine. I split the logic into 3 flows (installation via brew, installation via the install script, and someone just downloading the binary from the GitHub releases), and then tried to infer which of the 3 were used, but there might be missed edge cases there.

One thing I haven't been able to test is the upgrade via brew as I'm not sure how to install an old version. But the uninstall command works as expected.

fn upgrade_check_is_disabled() -> bool {
get_env_with_default("OCKAM_DISABLE_UPGRADE_CHECK", false).unwrap_or(false)
fn upgrade_ockam(opts: &CommandGlobalOpts) -> miette::Result<()> {
let stopped_nodes_names = stop_all_running_nodes(opts)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be safer to move this at least after let installer = get_installer(opts)?;? Or, even better, right before restarting the nodes. I'm not sure what will happen to running processes after doing the upgrade (are they killed after removing the current binary version?).

Copy link
Contributor Author

@BradLewis BradLewis Jul 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, if you run the upgrade without stopping the nodes, everything will still be running, so we could only do the restart cycle after the upgrade has run successfully just to ensure the nodes get upgraded to the latest version.

As an aside to this, with all the changes made with the nodes logic since the 0.90.0 release, the nodes will no longer be restarted correctly on this branch. I'm pretty sure this is just due to the nodes trying to be restarted with the 0.90.0 version after you run the upgrade? I created a new branch https://github.com/BradLewis/ockam/tree/bradlewis/upgrade-test that is just sitting on the latest release just to test this and everything is restarted as expected.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's interesting... can you share more details on how to reproduce the restart problem?

Copy link
Contributor Author

@BradLewis BradLewis Jul 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

  1. Create a node using ockam node create n using any version of ockam.
  2. Change the version in the Cargo.toml file for ockam_command to something below 0.90.0.
  3. Run cargo run upgrade --yes to "upgrade" the ockam binary to the latest version. This should just replace the one in target/debug/ockam with the latest one from github.
  4. Everything appears to run smoothly, however if you run cargo run node list, you'll see that the node is stopped.

I'm pretty sure this is because it's trying to restart the nodes using the 0.90.0 release binary, but the "new" nodes are not compatible with that version.

If you run ockam node list you'll see that it thinks there are no nodes on the system

❯ ockam node list
       ┌───────────────────┐
       │       Nodes       │
       └───────────────────┘

     ! No nodes found on this system.

❯ cargo run node list
    Finished dev [unoptimized + debuginfo] target(s) in 0.20s
     Running `/Users/bradlewis/repos/ockam/target/debug/ockam node list`
       ┌───────────────────┐
       │       Nodes       │
       └───────────────────┘

     │ Node n (default) UP
     │ Process id 21821

     │ Node m  UP
     │ Process id 22503

You can also easily reproduce this behaviour by first creating a node with release 0.90.0, then a new one with cargo run and then listing the nodes

❯ ockam node create n
       Creating Node n...

     ✔︎ Node n created successfully

       To see more details on this node, run:
       ockam node show

❯ ockam node list
       ┌───────────────────┐
       │       Nodes       │
       └───────────────────┘

     │ Node n (default) UP
     │ Process id 26852


❯ cargo run node create m
    Finished dev [unoptimized + debuginfo] target(s) in 0.20s
     Running `/Users/bradlewis/repos/ockam/target/debug/ockam node create m`
       Creating Node m...

     ✔︎ Node m created successfully

       To see more details on this node, run:
       ockam node show

❯ cargo run node list
    Finished dev [unoptimized + debuginfo] target(s) in 0.20s
     Running `/Users/bradlewis/repos/ockam/target/debug/ockam node list`
       ┌───────────────────┐
       │       Nodes       │
       └───────────────────┘

     │ Node n (default) UP
     │ Process id 26852

     │ Node m  UP
     │ Process id 27086

❯ ockam node list
       ┌───────────────────┐
       │       Nodes       │
       └───────────────────┘

     ! No nodes found on this system.

Given all this I imagine what's happening is that when the nodes are trying to be restarted, they are trying to be restarted with the 0.90.0 binary, but the 0.90.0 binary doesn't see the nodes so nothing happens. Not sure why there isn't any error though.

If I run this all instead on my other branch I created, everything works as you would expect.

@BradLewis BradLewis force-pushed the bradlewis/implement-upgrade-command branch 2 times, most recently from f9dd663 to ded8afc Compare July 16, 2023 12:25
@BradLewis BradLewis force-pushed the bradlewis/implement-upgrade-command branch from ded8afc to 991c88d Compare July 29, 2023 23:27
@adrianbenavides adrianbenavides self-requested a review August 18, 2023 07:35
@BradLewis BradLewis force-pushed the bradlewis/implement-upgrade-command branch from 991c88d to ee3a09e Compare September 10, 2023 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement ockam uninstall and ockam upgrade commands
5 participants