solana-install design proposal

This commit is contained in:
Michael Vines 2019-03-13 15:31:05 -07:00
parent 3f2fc21bb3
commit a17843c8f6
8 changed files with 368 additions and 0 deletions

15
Cargo.lock generated
View File

@ -2171,6 +2171,21 @@ dependencies = [
"solana-vote-api 0.13.0",
]
[[package]]
name = "solana-install"
version = "0.13.0"
dependencies = [
"bincode 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-client 0.13.0",
"solana-logger 0.13.0",
"solana-sdk 0.13.0",
]
[[package]]
name = "solana-keygen"
version = "0.13.0"

View File

@ -65,6 +65,7 @@ members = [
"drone",
"fullnode",
"genesis",
"install",
"keygen",
"ledger-tool",
"logger",

View File

@ -33,3 +33,4 @@
- [JSON RPC API](jsonrpc-api.md)
- [JavaScript API](javascript-api.md)
- [solana-wallet CLI](wallet.md)

21
install/Cargo.toml Normal file
View File

@ -0,0 +1,21 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-install"
description = "The solana cluster software installer"
version = "0.13.0"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
bincode = "1.1.2"
bs58 = "0.2.0"
clap = { version = "2.32.0"}
chrono = { version = "0.4.0", features = ["serde"] }
log = "0.4.2"
serde_json = "1.0.39"
solana-client = { path = "../client", version = "0.13.0" }
solana-logger = { path = "../logger", version = "0.13.0" }
solana-sdk = { path = "../sdk", version = "0.13.0" }

15
install/build.rs Normal file
View File

@ -0,0 +1,15 @@
use std::time::SystemTime;
fn main() {
println!(
"cargo:rustc-env=TARGET={}",
std::env::var("TARGET").unwrap()
);
println!(
"cargo:rustc-env=BUILD_SECONDS_SINCE_UNIX_EPOCH={}",
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs(),
);
}

101
install/src/main.rs Normal file
View File

@ -0,0 +1,101 @@
use clap::{crate_description, crate_name, crate_version, App, AppSettings, Arg, SubCommand};
//use clap::{crate_description, crate_version, load_yaml, App, AppSettings};
use std::error;
use std::time::Duration;
const TARGET: &str = env!("TARGET");
const BUILD_SECONDS_SINCE_UNIX_EPOCH: &str = env!("BUILD_SECONDS_SINCE_UNIX_EPOCH");
fn main() -> Result<(), Box<dyn error::Error>> {
solana_logger::setup();
let matches = App::new(crate_name!())
.about(crate_description!())
.version(crate_version!())
.setting(AppSettings::ArgRequiredElseHelp)
.subcommand(
SubCommand::with_name("init")
.about("initializes a new installation")
.setting(AppSettings::DisableVersion)
.arg(
Arg::with_name("json_rpc_url")
.short("u")
.long("url")
.value_name("URL")
.takes_value(true)
.default_value("https://api.testnet.solana.com/")
.help("JSON RPC URL for the solana cluster"),
)
.arg(
Arg::with_name("update_pubkey")
.short("p")
.long("pubkey")
.value_name("PUBKEY")
.takes_value(true)
.default_value("Solana-managed update manifest")
.help("Public key of the update manifest"),
),
)
.subcommand(
SubCommand::with_name("info")
.about("displays information about the current installation")
.setting(AppSettings::DisableVersion)
.arg(
Arg::with_name("local_info_only")
.short("l")
.long("local")
.help(
"only display local information, don't check the cluster for new updates",
),
),
)
.subcommand(
SubCommand::with_name("deploy")
.about("deploys a new update")
.setting(AppSettings::DisableVersion)
.arg(
Arg::with_name("download_url")
.index(1)
.required(true)
.help("URL to the solana release archive"),
)
.arg(
Arg::with_name("update_manifest_keypair")
.index(2)
.required(true)
.help("Keypair file for the update manifest (/path/to/keypair.json)"),
),
)
.subcommand(
SubCommand::with_name("update")
.about("checks for an update, and if available downloads and applies it")
.setting(AppSettings::DisableVersion),
)
.subcommand(
SubCommand::with_name("run")
.about("Runs a program while periodically checking and applying software updates")
.after_help("The program will be restarted upon a successful software update")
.setting(AppSettings::DisableVersion)
.arg(
Arg::with_name("program_name")
.index(1)
.required(true)
.help("program to run"),
)
.arg(
Arg::with_name("program_arguments")
.index(2)
.multiple(true)
.help("arguments to supply to the program"),
),
)
.get_matches();
println!("TARGET={}", TARGET);
println!(
"BUILD_SECONDS_SINCE_UNIX_EPOCH={:?}",
Duration::from_secs(u64::from_str_radix(BUILD_SECONDS_SINCE_UNIX_EPOCH, 10).unwrap())
);
println!("{:?}", matches);
Ok(())
}

View File

@ -23,6 +23,7 @@
- [References](ed_references.md)
- [Cluster Test Framework](cluster-test-framework.md)
- [Testing Programs](testing-programs.md)
- [Cluster Software Installation and Updates](installer.md)
- [Implemented Design Proposals](implemented-proposals.md)
- [Leader-to-Leader Transition](leader-leader-transition.md)

213
proposals/src/installer.md Normal file
View File

@ -0,0 +1,213 @@
## Cluster Software Installation and Updates
Currently users are required to build the solana cluster software themselves
from the git repository and manually update it, which is error prone and
inconvenient.
This document proposes an easy to use software install and updater that can be
used to deploy pre-built binaries for supported platforms. Users may elect to
use binaries supplied by Solana or any other party they trust. Deployment of
updates is managed using an on-chain update manifest program.
### Motivating Examples
#### Fetch and run a pre-built installer
With a well-known release URL, a pre-built binary can be obtained for supported
platforms:
```bash
$ curl -o solana-install https://github.com/solana-labs/solana/releases/download/v1.2.3/solana-install-x86_64-apple-darwin
$ chmod +x ./solana-install
$ ./solana-install --help
```
Note: future enhancements should include building wrapper in the style of
https://rustup.rs/ to make bootstrapping an install even easier.
#### Build and run the installer from source
If a pre-built binary is not available for a given platform, building the
installer from source is always an option:
```bash
$ git clone https://github.com/solana-labs/solana.git
$ cd solana/install
$ cargo run -- --help
```
#### Deploy a new update to a cluster
Given a solana release tarball (as created by `ci/publish-tarball.sh`) that has already been uploaded to a publicly accessible URL,
the following commands will deploy the update:
```bash
$ solana-keygen -o update-manifest.json # <-- only generated once, the public key is shared with users
$ solana-install deploy http://example.com/path/to/solana-release.tar.bz2 update-manifest.json
```
Note: Supporting IPFS download URLs in the future would be attractive.
#### Run a validator node that auto updates itself
```bash
$ solana-install init --pubkey 92DMonmBYXwEMHJ99c9ceRSpAmk9v6i3RdvDdXaVcrfj # <-- pubkey is obtained from whoever is deploying the updates
$ export PATH=~/.local/share/solana-install/bin:$PATH
$ solana-keygen ... # <-- runs the latest solana-keygen
$ solana-install run solana-fullnode ... # <-- runs a fullnode, restarting it as necesary when an update is applied
```
### Update Manifest on-chain program
The Update Manifest program is used to advertise the deployment of new release tarballs
on a solana cluster. Each instance of this program describes a logical update
channel for a given target triple (eg, `x86_64-apple-darwin`). The public key
of each program instance is well-known between the entity deploying new updates
and users consuming those updates.
The update tarball itself is hosted elsewhere, off-chain and can be fetched from
the specified `download_url`.
```rust,ignore
use solana_sdk::signature::Signature;
/// Information required to download and apply a given update
pub struct UpdateManifest {
pub target: String, // Target triple (TARGET)
pub commit: String, // git sha1 of this update, must match the commit sha1 in the release tar.bz2
pub timestamp_secs: u64, // When the release was deployed (seconds since UNIX EPOC)
pub download_url: String, // Download URL to the release tar.bz2
pub download_signature: Signature, // Signature of the release tar.bz2 file, verify with the Account public key
}
/// Userdata of an Update Manifest program Account.
pub struct SignedUpdateManifest {
pub manifest: UpdateManifest,
pub manifest_signature: Signature, // Signature of UpdateInfo, verify with the Account public key
}
```
Note that the `manifest` field itself contains a corresponding signature
(`manifest_signature`) to guard against man-in-the-middle attacks between the
`solana-install` tool and the solana cluster RPC API.
To guard against rollback attacks, `solana-install` will refuse to install an
update with an older `timestamp_secs` than what is currently installed.
### solana-install Tool
The `solana-install` tool is used by the user to install and update their cluster software.
It manages the following files and directories in the user's home directory:
* `~/.config/solana/updater.json` - user configuration and information about currently installed software version
* `~/.local/share/solana-install/bin` - a symlink to the current release. eg, `~/.local/share/solana-update/<update-pubkey>-<manifest_signature>/bin`
* `~/.local/share/solana-install/<update-pubkey>-<manifest_signature>/` - contents of the release
* `~/.local/share/solana-install/<update-pubkey>-<manifest_signature>.tmp/` - temporary directory used while downloading a new release
#### Command-line Interface
```bash
$ solana-install --help
solana-install 0.13.0
The solana cluster software installer
USAGE:
solana-install [SUBCOMMAND]
FLAGS:
-h, --help Prints help information
SUBCOMMANDS:
deploy deploys a new update
help Prints this message or the help of the given subcommand(s)
info displays information about the current installation
init initializes a new installation
run Runs a program while periodically checking and applying software updates. The program will be
restarted upon a successful software update
update checks for an update, and if available downloads and applies it
```
##### init
```bash
$ solana-install init --help
solana-install-init
initializes a new installation
USAGE:
solana-install init [OPTIONS]
FLAGS:
-h, --help Prints help information
OPTIONS:
-u, --url <URL> JSON RPC URL for the solana cluster [default: https://api.testnet.solana.com/]
-p, --pubkey <PUBKEY> Public key of the update manifest [default: Solana-managed update manifest]
```
##### info
```bash
$ solana-install info --help
solana-install-info
displays information about the current installation
USAGE:
solana-install info [FLAGS]
FLAGS:
-h, --help Prints help information
-l only display local information, don't check the cluster for new updates
```
##### deploy
```bash
$ solana-install deploy --help
solana-install-deploy
deploys a new update
USAGE:
solana-install deploy <URL> <PATH>
FLAGS:
-h, --help Prints help information
ARGS:
<URL> URL to the solana release archive
<PATH> Keypair file for the update manifest (/path/to/keypair.json)
```
##### update
```bash
$ solana-install update --help
solana-install-update
checks for an update, and if available downloads and applies it
USAGE:
solana-install update
FLAGS:
-h, --help Prints help information
```
##### run
```bash
$ solana-install run --help
solana-install-run
Runs a program while periodically checking and applying software updates. The program will be restarted upon a
successful software update
USAGE:
solana-install run <program_name> [program_arguments]...
FLAGS:
-h, --help Prints help information
ARGS:
<program_name> program to run
<program_arguments>... arguments to supply to the program
```
### Release Archive Contents
A release archive is expected to be a tar file compressed with
bzip2 with the following internal structure:
* `/version.yml` - a simple YAML file containing the fields (1) `"commit"` - the git
sha1 for this release, and (2) `"target"` - the target tuple. Any additional
fields are ignored.
* `/bin/` -- directory containing available programs in the release.
`solana-install` will symlink this directory to
`~/.local/share/solana-install/bin` for use by the `PATH` environment
variable.
* `...` -- any additional files and directories are permitted