1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! Types and methods for handling wash contexts, the configuration files for interacting with
//! lattices

use std::path::PathBuf;

use anyhow::Result;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, NoneAsEmptyString};

use crate::{
    config::{
        DEFAULT_COMPONENT_OPERATION_TIMEOUT_MS, DEFAULT_LATTICE, DEFAULT_NATS_HOST,
        DEFAULT_NATS_PORT, DEFAULT_NATS_TIMEOUT_MS,
    },
    id::ClusterSeed,
};

pub mod fs;

pub const HOST_CONFIG_NAME: &str = "host_config";

/// A trait that can be implemented by any type that wants to load, save, and otherwise manage wash
/// contexts (e.g. from a database or a config store
// NOTE(thomastaylor312): We may want to make this an async trait in the future since any other
// implementation than the fs one will likely involve networking
pub trait ContextManager {
    /// Returns the name of the currently set default context.
    fn default_context_name(&self) -> Result<String>;

    /// Sets the current default context to the given name. Should error if it doesn't exist
    fn set_default_context(&self, name: &str) -> Result<()>;

    /// Saves the given context
    fn save_context(&self, ctx: &WashContext) -> Result<()>;

    /// Deletes named context. If this context is the current default context, the default context
    /// should be unset
    fn delete_context(&self, name: &str) -> Result<()>;

    /// Loads the currently set default context
    fn load_default_context(&self) -> Result<WashContext>;

    /// Loads the named context
    fn load_context(&self, name: &str) -> Result<WashContext>;

    /// Returns a list of all context names
    fn list_contexts(&self) -> Result<Vec<String>>;
}

#[serde_as]
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct WashContext {
    #[serde(default)]
    pub name: String,
    #[serde_as(as = "NoneAsEmptyString")]
    pub cluster_seed: Option<ClusterSeed>,

    #[serde(default = "default_nats_host")]
    pub ctl_host: String,
    #[serde(default = "default_nats_port")]
    pub ctl_port: u16,
    #[serde_as(as = "NoneAsEmptyString")]
    pub ctl_jwt: Option<String>,
    #[serde_as(as = "NoneAsEmptyString")]
    pub ctl_seed: Option<String>,
    pub ctl_credsfile: Option<PathBuf>,
    /// timeout in milliseconds
    #[serde(default = "default_timeout_ms")]
    pub ctl_timeout: u64,
    /// TLS CA file to use for CTL
    pub ctl_tls_ca_file: Option<PathBuf>,

    // NOTE: lattice_prefix was renamed to lattice in most places, but this alias will need to remain for backwards compatibility with existing context files
    #[serde(alias = "lattice_prefix", default = "default_lattice")]
    pub lattice: String,

    pub js_domain: Option<String>,

    #[serde(default = "default_nats_host")]
    pub rpc_host: String,
    #[serde(default = "default_nats_port")]
    pub rpc_port: u16,
    #[serde_as(as = "NoneAsEmptyString")]
    pub rpc_jwt: Option<String>,
    #[serde_as(as = "NoneAsEmptyString")]
    pub rpc_seed: Option<String>,
    pub rpc_credsfile: Option<PathBuf>,
    /// rpc timeout in milliseconds
    #[serde(default = "default_timeout_ms")]
    pub rpc_timeout: u64,
    /// TLS CA file to use for RPC calls
    pub rpc_tls_ca_file: Option<PathBuf>,
}

impl WashContext {
    /// Create a new default context with the given name
    #[must_use]
    pub fn named(name: String) -> Self {
        WashContext {
            name,
            ..Self::default()
        }
    }
}

impl Default for WashContext {
    fn default() -> Self {
        WashContext {
            name: "default".to_string(),
            cluster_seed: None,
            ctl_host: DEFAULT_NATS_HOST.to_string(),
            ctl_port: DEFAULT_NATS_PORT.parse().unwrap(),
            ctl_jwt: None,
            ctl_seed: None,
            ctl_credsfile: None,
            ctl_timeout: DEFAULT_NATS_TIMEOUT_MS,
            ctl_tls_ca_file: None,
            lattice: DEFAULT_LATTICE.to_string(),
            js_domain: None,
            rpc_host: DEFAULT_NATS_HOST.to_string(),
            rpc_port: DEFAULT_NATS_PORT.parse().unwrap(),
            rpc_jwt: None,
            rpc_seed: None,
            rpc_credsfile: None,
            rpc_timeout: DEFAULT_NATS_TIMEOUT_MS,
            rpc_tls_ca_file: None,
        }
    }
}

// Below are required functions for serde default derive with WashContext

fn default_nats_host() -> String {
    DEFAULT_NATS_HOST.to_string()
}

fn default_nats_port() -> u16 {
    DEFAULT_NATS_PORT.parse().unwrap()
}

fn default_lattice() -> String {
    DEFAULT_LATTICE.to_string()
}

#[must_use]
pub fn default_timeout_ms() -> u64 {
    DEFAULT_NATS_TIMEOUT_MS
}

/// Default timeout that should be used with operations that manipulate components (ex. scale)
#[must_use]
pub fn default_component_operation_timeout_ms() -> u64 {
    DEFAULT_COMPONENT_OPERATION_TIMEOUT_MS
}