use std::path::PathBuf;
use clap::{Args, Parser, Subcommand};
use greentic_deploy_spec::CapabilitySlot;
use crate::environment::LocalFsStore;
use super::{OpError, OpFlags, OpOutcome, render_error};
#[derive(Parser, Debug)]
#[command(
after_help = "Nouns: env, env-packs, extensions, bundles, revisions, traffic, config, credentials, secrets, messaging.\n\
Every verb honors:\n\
--schema dump the JSON schema of the payload it would accept, then exit\n\
--answers <PATH> read the payload from a JSON or YAML file\n\n\
Examples:\n\
greentic-operator op env create --answers env.json\n\
greentic-operator op revisions warm --answers warm.yaml\n\
greentic-operator op env show <env-id>\n\n\
Errors are written to stderr as a JSON envelope:\n\
{\"op\":\"<verb>\",\"noun\":\"<noun>\",\"error\":{\"kind\":\"…\",\"message\":\"…\"}}\n\
Success output goes to stdout as:\n\
{\"op\":\"<verb>\",\"noun\":\"<noun>\",\"result\":…}"
)]
pub struct OpCommand {
#[arg(long, global = true)]
pub store_root: Option<PathBuf>,
#[arg(long, global = true)]
pub store_url: Option<String>,
#[arg(long, global = true)]
pub store_token: Option<String>,
#[arg(long, global = true)]
pub schema: bool,
#[arg(long, global = true)]
pub answers: Option<PathBuf>,
#[command(subcommand)]
pub noun: OpNoun,
}
#[derive(Subcommand, Debug)]
pub enum OpNoun {
Env {
#[command(subcommand)]
verb: EnvVerb,
},
EnvPacks {
#[command(subcommand)]
verb: EnvPacksVerb,
},
Bundles {
#[command(subcommand)]
verb: BundlesVerb,
},
Revisions {
#[command(subcommand)]
verb: RevisionsVerb,
},
Traffic {
#[command(subcommand)]
verb: TrafficVerb,
},
Deploy(BundleDeployArgs),
Config {
#[command(subcommand)]
verb: ConfigVerb,
},
Credentials {
#[command(subcommand)]
verb: CredentialsVerb,
},
Secrets {
#[command(subcommand)]
verb: SecretsVerb,
},
#[command(name = "trust-root")]
TrustRoot {
#[command(subcommand)]
verb: TrustRootVerb,
},
Messaging {
#[command(subcommand)]
verb: MessagingNoun,
},
Extensions {
#[command(subcommand)]
verb: ExtensionsVerb,
},
}
#[derive(Subcommand, Debug)]
pub enum MessagingNoun {
Endpoint {
#[command(subcommand)]
verb: MessagingEndpointVerb,
},
}
#[derive(Subcommand, Debug)]
pub enum MessagingEndpointVerb {
Add(MessagingEndpointAddArgs),
List { env_id: String },
Show { env_id: String, endpoint_id: String },
#[command(name = "link-bundle")]
LinkBundle(MessagingEndpointLinkBundleArgs),
#[command(name = "unlink-bundle")]
UnlinkBundle(MessagingEndpointLinkBundleArgs),
#[command(name = "set-welcome-flow")]
SetWelcomeFlow(MessagingEndpointSetWelcomeFlowArgs),
Remove(MessagingEndpointRemoveArgs),
#[command(name = "rotate-webhook-secret")]
RotateWebhookSecret(MessagingEndpointRemoveArgs),
}
#[derive(Args, Debug)]
pub struct MessagingEndpointAddArgs {
#[arg(long)]
pub env: Option<String>,
#[arg(long = "provider-type")]
pub provider_type: Option<String>,
#[arg(long = "provider-id")]
pub provider_id: Option<String>,
#[arg(long = "display-name")]
pub display_name: Option<String>,
#[arg(long = "secret-ref", value_name = "URI")]
pub secret_ref: Vec<String>,
#[arg(long = "idempotency-key")]
pub idempotency_key: Option<String>,
#[arg(long = "updated-by")]
pub updated_by: Option<String>,
}
#[derive(Args, Debug)]
pub struct MessagingEndpointLinkBundleArgs {
#[arg(long)]
pub env: Option<String>,
#[arg(long = "endpoint-id")]
pub endpoint_id: Option<String>,
#[arg(long = "bundle-id")]
pub bundle_id: Option<String>,
#[arg(long = "idempotency-key")]
pub idempotency_key: Option<String>,
#[arg(long = "updated-by")]
pub updated_by: Option<String>,
}
#[derive(Args, Debug)]
pub struct MessagingEndpointSetWelcomeFlowArgs {
#[arg(long)]
pub env: Option<String>,
#[arg(long = "endpoint-id")]
pub endpoint_id: Option<String>,
#[arg(long = "bundle-id")]
pub bundle_id: Option<String>,
#[arg(long = "pack-id")]
pub pack_id: Option<String>,
#[arg(long = "flow-id")]
pub flow_id: Option<String>,
#[arg(long = "idempotency-key")]
pub idempotency_key: Option<String>,
#[arg(long = "updated-by")]
pub updated_by: Option<String>,
}
#[derive(Args, Debug)]
pub struct MessagingEndpointRemoveArgs {
#[arg(long)]
pub env: Option<String>,
#[arg(long = "endpoint-id")]
pub endpoint_id: Option<String>,
#[arg(long = "idempotency-key")]
pub idempotency_key: Option<String>,
#[arg(long = "updated-by")]
pub updated_by: Option<String>,
}
#[derive(Subcommand, Debug)]
pub enum EnvVerb {
Init(EnvInitArgs),
Apply(EnvApplyArgs),
Create(EnvCreateArgs),
Update(EnvUpdateArgs),
SetPublicUrl(EnvSetPublicUrlArgs),
List,
Show {
env_id: String,
},
Doctor {
env_id: String,
},
ToolCheck {
env_id: String,
},
Render(EnvRenderArgs),
Destroy {
env_id: String,
#[arg(long)]
confirm: bool,
},
MigrateDev {
target: String,
#[arg(long, conflicts_with = "apply")]
check: bool,
#[arg(long, conflicts_with = "check")]
apply: bool,
},
MigrateState {
target: String,
#[arg(long, conflicts_with = "apply")]
check: bool,
#[arg(long, conflicts_with = "check")]
apply: bool,
#[arg(long = "state-dir")]
state_dir: Option<PathBuf>,
},
}
#[derive(Subcommand, Debug)]
pub enum TrustRootVerb {
Bootstrap { env_id: Option<String> },
List { env_id: String },
Add(TrustRootAddArgs),
Remove(TrustRootRemoveArgs),
}
#[derive(Args, Debug)]
pub struct TrustRootAddArgs {
pub env_id: Option<String>,
#[arg(long = "key-id")]
pub key_id: Option<String>,
#[arg(long = "public-key-pem")]
pub public_key_pem: Option<String>,
#[arg(long = "public-key-file")]
pub public_key_file: Option<PathBuf>,
}
#[derive(Args, Debug)]
pub struct EnvInitArgs {
#[arg(long = "public-url")]
pub public_url: Option<String>,
}
#[derive(Args, Debug)]
pub struct EnvApplyArgs {
#[arg(long = "dry-run")]
pub dry_run: bool,
#[arg(long, conflicts_with = "dry_run")]
pub check: bool,
#[arg(long = "non-interactive")]
pub non_interactive: bool,
#[arg(
long = "emit-answers-template",
value_name = "PATH",
conflicts_with_all = ["dry_run", "check"]
)]
pub emit_answers_template: Option<PathBuf>,
#[arg(long = "updated-by")]
pub updated_by: Option<String>,
#[arg(long)]
pub yes: bool,
}
impl EnvApplyArgs {
fn into_options(self) -> super::env_apply::ApplyOptions {
use super::env_apply::ApplyMode;
let mode = if self.check {
ApplyMode::Check
} else if self.dry_run {
ApplyMode::DryRun
} else {
ApplyMode::Apply
};
super::env_apply::ApplyOptions {
mode,
updated_by: self.updated_by,
yes: self.yes,
non_interactive: self.non_interactive,
}
}
}
#[derive(Args, Debug)]
pub struct EnvCreateArgs {
pub environment_id: Option<String>,
#[arg(long = "name")]
pub name: Option<String>,
#[arg(long = "region")]
pub region: Option<String>,
#[arg(long = "tenant-org")]
pub tenant_org_id: Option<String>,
#[arg(long = "listen-addr")]
pub listen_addr: Option<String>,
#[arg(long = "public-url")]
pub public_url: Option<String>,
}
#[derive(Args, Debug)]
pub struct EnvUpdateArgs {
pub environment_id: Option<String>,
#[arg(long = "name")]
pub name: Option<String>,
#[arg(long = "region")]
pub region: Option<String>,
#[arg(long = "tenant-org")]
pub tenant_org_id: Option<String>,
}
#[derive(Args, Debug)]
pub struct EnvRenderArgs {
pub env_id: String,
#[arg(long)]
pub kind: Option<String>,
#[arg(long)]
pub output: Option<PathBuf>,
}
#[derive(Args, Debug)]
pub struct EnvSetPublicUrlArgs {
pub env_id: String,
pub url: String,
}
#[derive(Args, Debug)]
pub struct TrustRootRemoveArgs {
pub env_id: Option<String>,
#[arg(long = "key-id")]
pub key_id: Option<String>,
}
#[derive(Subcommand, Debug)]
pub enum EnvPacksVerb {
Add,
Update,
Remove,
Rollback,
List { env_id: String },
}
#[derive(Subcommand, Debug)]
pub enum ExtensionsVerb {
Add,
Update,
Remove,
Rollback,
List { env_id: String },
}
#[derive(Subcommand, Debug)]
pub enum BundlesVerb {
Add,
Update,
Remove,
List { env_id: String },
}
#[derive(Subcommand, Debug)]
pub enum RevisionsVerb {
Stage(RevisionStageArgs),
Warm,
Drain,
Archive,
List { env_id: String },
}
#[derive(Args, Debug)]
pub struct RevisionStageArgs {
pub env_id: Option<String>,
#[arg(long)]
pub deployment: Option<String>,
#[arg(long)]
pub bundle: Option<PathBuf>,
}
#[derive(Subcommand, Debug)]
pub enum TrafficVerb {
Set(TrafficSetArgs),
Show(TrafficTargetArgs),
Rollback(TrafficTargetArgs),
}
#[derive(Args, Debug)]
pub struct TrafficSetArgs {
pub env_id: Option<String>,
pub entries: Vec<String>,
#[arg(long)]
pub deployment: Option<String>,
#[arg(long)]
pub idempotency_key: Option<String>,
#[arg(long)]
pub updated_by: Option<String>,
#[arg(long)]
pub authorization_ref: Option<PathBuf>,
}
#[derive(Args, Debug)]
pub struct BundleDeployArgs {
#[arg(long)]
pub bundle: Option<PathBuf>,
#[arg(long)]
pub env: Option<String>,
#[arg(long = "bundle-id")]
pub bundle_id: Option<String>,
#[arg(long = "customer-id")]
pub customer_id: Option<String>,
#[arg(long = "idempotency-key")]
pub idempotency_key: Option<String>,
#[arg(long = "config-override", value_name = "PACK_ID:KEY=VALUE")]
pub config_override: Vec<String>,
#[arg(long = "config-override-json", value_name = "PACK_ID:KEY=JSON")]
pub config_override_json: Vec<String>,
#[arg(long = "config-overrides-from", value_name = "FILE")]
pub config_overrides_from: Option<PathBuf>,
#[arg(long = "path-prefix", value_name = "PREFIX")]
pub path_prefix: Vec<String>,
#[arg(long = "host", value_name = "HOST")]
pub host: Vec<String>,
#[arg(long = "tenant", value_name = "TENANT")]
pub tenant: Option<String>,
#[arg(long = "team", value_name = "TEAM")]
pub team: Option<String>,
}
#[derive(Args, Debug)]
pub struct TrafficTargetArgs {
pub env_id: Option<String>,
#[arg(long)]
pub deployment: Option<String>,
}
#[derive(Subcommand, Debug)]
pub enum ConfigVerb {
Show,
Set,
}
#[derive(Subcommand, Debug)]
pub enum CredentialsVerb {
Requirements,
Bootstrap,
Rotate,
}
#[derive(Subcommand, Debug)]
pub enum SecretsVerb {
List,
Put,
Get,
Rotate,
}
#[derive(Args, Debug)]
pub struct PayloadArg {
#[arg(long, conflicts_with = "answers")]
pub payload_json: Option<String>,
}
pub fn build_store(cmd: &OpCommand) -> Result<LocalFsStore, OpError> {
let root = match &cmd.store_root {
Some(p) => p.clone(),
None => LocalFsStore::default_root().ok_or_else(|| {
OpError::InvalidArgument("no --store-root and HOME / USERPROFILE not set".to_string())
})?,
};
Ok(LocalFsStore::new(root))
}
pub fn print_outcome(outcome: &OpOutcome) -> Result<(), OpError> {
let value = serde_json::to_value(outcome)
.map_err(|e| OpError::InvalidArgument(format!("serialize outcome: {e}")))?;
println!("{value}");
Ok(())
}
pub fn print_error(noun: &'static str, op: &'static str, err: &OpError) {
let value = render_error(noun, op, err);
eprintln!("{value}");
}
pub fn dispatch_op(cmd: OpCommand) -> Result<(), OpError> {
let registry = crate::env_packs::EnvPackRegistry::with_builtins();
dispatch_op_with_registry(cmd, ®istry)
}
pub fn dispatch_op_with_registry(
cmd: OpCommand,
registry: &crate::env_packs::EnvPackRegistry,
) -> Result<(), OpError> {
let flags = OpFlags {
schema_only: cmd.schema,
answers: cmd.answers.clone(),
};
let (noun, verb) = noun_verb_labels(&cmd.noun);
let (store_url, store_token) = crate::cli::dispatch_remote::resolve_remote_target(
cmd.store_url.clone(),
cmd.store_token.clone(),
std::env::var("GREENTIC_STORE_URL").ok(),
std::env::var("GREENTIC_STORE_TOKEN").ok(),
);
if let Some(raw_url) = store_url
&& !cmd.schema
{
return crate::cli::dispatch_remote::dispatch_op_remote(&raw_url, store_token, cmd, &flags)
.inspect_err(|err| print_error(noun, verb, err));
}
let store = build_store(&cmd).inspect_err(|err| print_error(noun, verb, err))?;
let result = match cmd.noun {
OpNoun::Env { verb } => dispatch_env(&store, registry, &flags, verb),
OpNoun::EnvPacks { verb } => dispatch_env_packs(&store, &flags, verb),
OpNoun::Bundles { verb } => dispatch_bundles(&store, &flags, verb),
OpNoun::Revisions { verb } => dispatch_revisions(&store, &flags, verb),
OpNoun::Traffic { verb } => dispatch_traffic(&store, &flags, verb),
OpNoun::Deploy(args) => dispatch_deploy(&store, &flags, args),
OpNoun::Config { verb } => dispatch_config(&store, &flags, verb),
OpNoun::Credentials { verb } => dispatch_credentials(&store, registry, &flags, verb),
OpNoun::Secrets { verb } => dispatch_secrets(&store, &flags, verb),
OpNoun::TrustRoot { verb } => dispatch_trust_root(&store, &flags, verb),
OpNoun::Messaging { verb } => dispatch_messaging(&store, &flags, verb),
OpNoun::Extensions { verb } => dispatch_extensions(&store, &flags, verb),
};
result.inspect_err(|err| print_error(noun, verb, err))
}
pub fn noun_verb_labels(noun: &OpNoun) -> (&'static str, &'static str) {
match noun {
OpNoun::Env { verb } => (
"env",
match verb {
EnvVerb::Init(_) => "init",
EnvVerb::Apply(_) => "apply",
EnvVerb::Create(_) => "create",
EnvVerb::Update(_) => "update",
EnvVerb::SetPublicUrl(_) => "set-public-url",
EnvVerb::List => "list",
EnvVerb::Show { .. } => "show",
EnvVerb::Doctor { .. } => "doctor",
EnvVerb::ToolCheck { .. } => "tool-check",
EnvVerb::Render(_) => "render",
EnvVerb::Destroy { .. } => "destroy",
EnvVerb::MigrateDev { .. } => "migrate-dev",
EnvVerb::MigrateState { .. } => "migrate-state",
},
),
OpNoun::EnvPacks { verb } => (
"env-packs",
match verb {
EnvPacksVerb::Add => "add",
EnvPacksVerb::Update => "update",
EnvPacksVerb::Remove => "remove",
EnvPacksVerb::Rollback => "rollback",
EnvPacksVerb::List { .. } => "list",
},
),
OpNoun::Bundles { verb } => (
"bundles",
match verb {
BundlesVerb::Add => "add",
BundlesVerb::Update => "update",
BundlesVerb::Remove => "remove",
BundlesVerb::List { .. } => "list",
},
),
OpNoun::Revisions { verb } => (
"revisions",
match verb {
RevisionsVerb::Stage(_) => "stage",
RevisionsVerb::Warm => "warm",
RevisionsVerb::Drain => "drain",
RevisionsVerb::Archive => "archive",
RevisionsVerb::List { .. } => "list",
},
),
OpNoun::Traffic { verb } => (
"traffic",
match verb {
TrafficVerb::Set(_) => "set",
TrafficVerb::Show(_) => "show",
TrafficVerb::Rollback(_) => "rollback",
},
),
OpNoun::Deploy(_) => ("deploy", "run"),
OpNoun::Config { verb } => (
"config",
match verb {
ConfigVerb::Show => "show",
ConfigVerb::Set => "set",
},
),
OpNoun::Credentials { verb } => (
"credentials",
match verb {
CredentialsVerb::Requirements => "requirements",
CredentialsVerb::Bootstrap => "bootstrap",
CredentialsVerb::Rotate => "rotate",
},
),
OpNoun::Secrets { verb } => (
"secrets",
match verb {
SecretsVerb::List => "list",
SecretsVerb::Put => "put",
SecretsVerb::Get => "get",
SecretsVerb::Rotate => "rotate",
},
),
OpNoun::TrustRoot { verb } => (
"trust-root",
match verb {
TrustRootVerb::Bootstrap { .. } => "bootstrap",
TrustRootVerb::List { .. } => "list",
TrustRootVerb::Add(_) => "add",
TrustRootVerb::Remove(_) => "remove",
},
),
OpNoun::Messaging { verb } => (
"messaging.endpoint",
match verb {
MessagingNoun::Endpoint { verb } => match verb {
MessagingEndpointVerb::Add(_) => "add",
MessagingEndpointVerb::List { .. } => "list",
MessagingEndpointVerb::Show { .. } => "show",
MessagingEndpointVerb::LinkBundle(_) => "link-bundle",
MessagingEndpointVerb::UnlinkBundle(_) => "unlink-bundle",
MessagingEndpointVerb::SetWelcomeFlow(_) => "set-welcome-flow",
MessagingEndpointVerb::Remove(_) => "remove",
MessagingEndpointVerb::RotateWebhookSecret(_) => "rotate-webhook-secret",
},
},
),
OpNoun::Extensions { verb } => (
"extensions",
match verb {
ExtensionsVerb::Add => "add",
ExtensionsVerb::Update => "update",
ExtensionsVerb::Remove => "remove",
ExtensionsVerb::Rollback => "rollback",
ExtensionsVerb::List { .. } => "list",
},
),
}
}
fn dispatch_env(
store: &LocalFsStore,
registry: &crate::env_packs::EnvPackRegistry,
flags: &OpFlags,
verb: EnvVerb,
) -> Result<(), OpError> {
let outcome = match verb {
EnvVerb::Init(args) => super::env::init(store, flags, args.into_payload(flags)?)?,
EnvVerb::Apply(mut args) => {
if let Some(path) = args.emit_answers_template.take() {
super::env_apply::emit_answers_template(&path)?
} else {
super::env_apply::apply(store, flags, args.into_options())?
}
}
EnvVerb::Create(args) => {
super::env::create(store, flags, args.into_payload("create", flags)?)?
}
EnvVerb::Update(args) => {
super::env::update(store, flags, args.into_payload("update", flags)?)?
}
EnvVerb::SetPublicUrl(args) => {
super::env::set_public_url(store, flags, &args.env_id, &args.url)?
}
EnvVerb::List => super::env::list(store, flags)?,
EnvVerb::Show { env_id } => super::env::show(store, flags, &env_id)?,
EnvVerb::Doctor { env_id } => super::env::doctor(store, flags, &env_id)?,
EnvVerb::ToolCheck { env_id } => super::env::tool_check(store, flags, &env_id)?,
EnvVerb::Render(args) => super::env::render(store, registry, flags, args)?,
EnvVerb::Destroy { env_id, confirm } => {
super::env::destroy(store, flags, &env_id, confirm)?
}
EnvVerb::MigrateDev {
target,
check,
apply,
} => {
if !(check ^ apply) {
return Err(OpError::InvalidArgument(
"migrate-dev requires exactly one of --check or --apply".to_string(),
));
}
if check {
super::migrate::check(store, flags, &target)?
} else {
super::migrate::apply(store, flags, &target)?
}
}
EnvVerb::MigrateState {
target,
check,
apply,
state_dir,
} => {
if !(check ^ apply) {
return Err(OpError::InvalidArgument(
"migrate-state requires exactly one of --check or --apply".to_string(),
));
}
if check {
super::migrate_state::check(store, flags, &target, state_dir.as_deref())?
} else {
super::migrate_state::apply(store, flags, &target, state_dir.as_deref())?
}
}
};
print_outcome(&outcome)
}
fn dispatch_env_packs(
store: &LocalFsStore,
flags: &OpFlags,
verb: EnvPacksVerb,
) -> Result<(), OpError> {
let outcome = match verb {
EnvPacksVerb::Add => super::env_packs::add(store, flags, None)?,
EnvPacksVerb::Update => super::env_packs::update(store, flags, None)?,
EnvPacksVerb::Remove => super::env_packs::remove(store, flags, None)?,
EnvPacksVerb::Rollback => super::env_packs::rollback(store, flags, None)?,
EnvPacksVerb::List { env_id } => super::env_packs::list(store, flags, &env_id)?,
};
print_outcome(&outcome)
}
fn dispatch_extensions(
store: &LocalFsStore,
flags: &OpFlags,
verb: ExtensionsVerb,
) -> Result<(), OpError> {
let outcome = match verb {
ExtensionsVerb::Add => super::extensions::add(store, flags, None)?,
ExtensionsVerb::Update => super::extensions::update(store, flags, None)?,
ExtensionsVerb::Remove => super::extensions::remove(store, flags, None)?,
ExtensionsVerb::Rollback => super::extensions::rollback(store, flags, None)?,
ExtensionsVerb::List { env_id } => super::extensions::list(store, flags, &env_id)?,
};
print_outcome(&outcome)
}
fn dispatch_bundles(
store: &LocalFsStore,
flags: &OpFlags,
verb: BundlesVerb,
) -> Result<(), OpError> {
let outcome = match verb {
BundlesVerb::Add => super::bundles::add(store, flags, None)?,
BundlesVerb::Update => super::bundles::update(store, flags, None)?,
BundlesVerb::Remove => super::bundles::remove(store, flags, None)?,
BundlesVerb::List { env_id } => super::bundles::list(store, flags, &env_id)?,
};
print_outcome(&outcome)
}
fn dispatch_revisions(
store: &LocalFsStore,
flags: &OpFlags,
verb: RevisionsVerb,
) -> Result<(), OpError> {
let outcome = match verb {
RevisionsVerb::Stage(args) => {
let payload = super::revisions::payload_from_stage_args(args)?;
super::revisions::stage(store, flags, payload)?
}
RevisionsVerb::Warm => super::revisions::warm(store, flags, None)?,
RevisionsVerb::Drain => super::revisions::drain(store, flags, None)?,
RevisionsVerb::Archive => super::revisions::archive(store, flags, None)?,
RevisionsVerb::List { env_id } => super::revisions::list(store, flags, &env_id)?,
};
print_outcome(&outcome)
}
fn dispatch_traffic(
store: &LocalFsStore,
flags: &OpFlags,
verb: TrafficVerb,
) -> Result<(), OpError> {
let outcome = match verb {
TrafficVerb::Set(args) => {
let payload = super::traffic::payload_from_set_args(args)?;
super::traffic::set(store, flags, payload)?
}
TrafficVerb::Show(args) => {
let payload = super::traffic::payload_from_target_args(args)?;
super::traffic::show(store, flags, payload)?
}
TrafficVerb::Rollback(args) => {
let payload = super::traffic::payload_from_target_args(args)?;
super::traffic::rollback(store, flags, payload)?
}
};
print_outcome(&outcome)
}
fn dispatch_deploy(
store: &LocalFsStore,
flags: &OpFlags,
args: BundleDeployArgs,
) -> Result<(), OpError> {
let payload = super::deploy::payload_from_deploy_args(args)?;
let outcome = super::deploy::deploy(store, flags, payload)?;
print_outcome(&outcome)
}
fn dispatch_config(store: &LocalFsStore, flags: &OpFlags, verb: ConfigVerb) -> Result<(), OpError> {
let outcome = match verb {
ConfigVerb::Show => super::config::show(store, flags, None)?,
ConfigVerb::Set => super::config::set(store, flags, None)?,
};
print_outcome(&outcome)
}
fn dispatch_credentials(
store: &LocalFsStore,
registry: &crate::env_packs::EnvPackRegistry,
flags: &OpFlags,
verb: CredentialsVerb,
) -> Result<(), OpError> {
let outcome = match verb {
CredentialsVerb::Requirements => {
super::credentials::requirements(store, registry, flags, None)?
}
CredentialsVerb::Bootstrap => super::credentials::bootstrap(store, registry, flags, None)?,
CredentialsVerb::Rotate => super::credentials::rotate(store, registry, flags, None)?,
};
print_outcome(&outcome)
}
fn dispatch_secrets(
store: &LocalFsStore,
flags: &OpFlags,
verb: SecretsVerb,
) -> Result<(), OpError> {
let outcome = match verb {
SecretsVerb::List => super::secrets::list(store, flags, None)?,
SecretsVerb::Put => super::secrets::put(store, flags, None)?,
SecretsVerb::Get => super::secrets::get(store, flags, None)?,
SecretsVerb::Rotate => super::secrets::rotate(store, flags, None)?,
};
print_outcome(&outcome)
}
fn dispatch_trust_root(
store: &LocalFsStore,
flags: &OpFlags,
verb: TrustRootVerb,
) -> Result<(), OpError> {
let outcome = match verb {
TrustRootVerb::Bootstrap { env_id } => {
let payload = env_id
.map(|id| super::trust_root::TrustRootBootstrapPayload { environment_id: id });
super::trust_root::bootstrap(store, flags, payload)?
}
TrustRootVerb::List { env_id } => super::trust_root::list(store, flags, &env_id)?,
TrustRootVerb::Add(args) => {
let payload = match (args.env_id, args.key_id) {
(Some(env_id), Some(key_id)) => Some(super::trust_root::TrustRootAddPayload {
environment_id: env_id,
key_id,
public_key_pem: args.public_key_pem,
public_key_file: args.public_key_file,
}),
_ => None, };
super::trust_root::add(store, flags, payload)?
}
TrustRootVerb::Remove(args) => {
let payload = match (args.env_id, args.key_id) {
(Some(env_id), Some(key_id)) => Some(super::trust_root::TrustRootRemovePayload {
environment_id: env_id,
key_id,
}),
_ => None,
};
super::trust_root::remove(store, flags, payload)?
}
};
print_outcome(&outcome)
}
fn dispatch_messaging(
store: &LocalFsStore,
flags: &OpFlags,
verb: MessagingNoun,
) -> Result<(), OpError> {
let outcome = match verb {
MessagingNoun::Endpoint { verb } => match verb {
MessagingEndpointVerb::Add(args) => {
super::messaging::add(store, flags, args.into_payload("add", flags)?)?
}
MessagingEndpointVerb::List { env_id } => {
super::messaging::list(store, flags, &env_id)?
}
MessagingEndpointVerb::Show {
env_id,
endpoint_id,
} => super::messaging::show(store, flags, &env_id, &endpoint_id)?,
MessagingEndpointVerb::LinkBundle(args) => super::messaging::link_bundle(
store,
flags,
args.into_payload("link-bundle", flags)?,
)?,
MessagingEndpointVerb::UnlinkBundle(args) => super::messaging::unlink_bundle(
store,
flags,
args.into_payload("unlink-bundle", flags)?,
)?,
MessagingEndpointVerb::SetWelcomeFlow(args) => super::messaging::set_welcome_flow(
store,
flags,
args.into_payload("set-welcome-flow", flags)?,
)?,
MessagingEndpointVerb::Remove(args) => {
super::messaging::remove(store, flags, args.into_remove_payload("remove", flags)?)?
}
MessagingEndpointVerb::RotateWebhookSecret(args) => {
super::messaging::rotate_webhook_secret(
store,
flags,
args.into_rotate_payload("rotate-webhook-secret", flags)?,
)?
}
},
};
print_outcome(&outcome)
}
#[allow(dead_code)]
fn _slot_anchor(_: CapabilitySlot) {}