1use std::net::{Ipv4Addr, SocketAddr};
2
3use url::Url;
4use vector_lib::configurable::configurable_component;
5
6#[configurable_component]
8#[configurable(metadata(
9 docs::warnings = "The API currently does not support authentication. Only enable it in isolated environments or for debugging. It must not be exposed to untrusted clients."
10))]
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12#[serde(default, deny_unknown_fields)]
13pub struct Options {
14 #[serde(default = "default_enabled")]
16 #[configurable(metadata(docs::common = true, docs::required = false))]
17 pub enabled: bool,
18
19 #[serde(default = "default_address")]
23 #[configurable(metadata(docs::examples = "0.0.0.0:8686"))]
24 #[configurable(metadata(docs::examples = "127.0.0.1:1234"))]
25 #[configurable(metadata(docs::common = true, docs::required = false))]
26 pub address: Option<SocketAddr>,
27}
28
29impl_generate_config_from_default!(Options);
30
31impl Default for Options {
32 fn default() -> Self {
33 Self {
34 enabled: default_enabled(),
35 address: default_address(),
36 }
37 }
38}
39
40const fn default_enabled() -> bool {
41 false
42}
43
44pub fn default_address() -> Option<SocketAddr> {
48 Some(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 8686))
49}
50
51pub fn default_grpc_url() -> Url {
53 let addr = default_address().unwrap();
54 Url::parse(&format!("http://{addr}"))
55 .expect("Couldn't parse default API URL. Please report this.")
56}
57
58impl Options {
59 pub fn merge(&mut self, other: Self) -> Result<(), String> {
60 let address = match (self.address, other.address) {
64 (None, b) => b,
65 (Some(a), None) => Some(a),
66 (Some(a), Some(b)) if a == b => Some(a),
67 (Some(a), Some(b)) => {
69 match (Some(a) == default_address(), Some(b) == default_address()) {
70 (false, false) => return Err(format!("Conflicting `api` address: {a}, {b} .")),
71 (false, true) => Some(a),
72 (true, _) => Some(b),
73 }
74 }
75 };
76
77 let options = Options {
78 address,
79 enabled: self.enabled | other.enabled,
80 };
81
82 *self = options;
83 Ok(())
84 }
85}
86
87#[test]
88fn bool_merge() {
89 let mut a = Options {
90 enabled: true,
91 address: None,
92 };
93
94 a.merge(Options::default()).unwrap();
95
96 assert_eq!(
97 a,
98 Options {
99 enabled: true,
100 address: default_address(),
101 }
102 );
103}
104
105#[test]
106fn bind_merge() {
107 let address = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 9000);
108 let mut a = Options {
109 enabled: true,
110 address: Some(address),
111 };
112
113 a.merge(Options::default()).unwrap();
114
115 assert_eq!(
116 a,
117 Options {
118 enabled: true,
119 address: Some(address),
120 }
121 );
122}
123
124#[test]
125fn bind_conflict() {
126 let mut a = Options {
127 address: Some(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 9000)),
128 ..Options::default()
129 };
130
131 let b = Options {
132 address: Some(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 9001)),
133 ..Options::default()
134 };
135
136 assert!(a.merge(b).is_err());
137}