Skip to content

Commit 05c5ab4

Browse files
committed
tweak LB
1 parent 0a89cf9 commit 05c5ab4

File tree

4 files changed

+137
-104
lines changed

4 files changed

+137
-104
lines changed

.github/workflows/load_balancer_ci_cd.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,5 +153,5 @@ jobs:
153153
- name: Deploy to Jonline-BE via DigitalOcean Kubernetes
154154
run: kubectl apply -f deploys/k8s/load_balancer.yaml -n jonline
155155

156-
- name: Verify Server deployment
156+
- name: Verify LB deployment
157157
run: kubectl rollout status deployment/jonline-lb -n jonline --timeout 2m

backend/src/bin/load_balancer.rs

+130-100
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ struct Options {
3131
// key: PathBuf,
3232
}
3333

34+
const NGINX_CONF: &str = "nginx.conf.jbl";
35+
3436
#[tokio::main]
3537
async fn main() -> Result<(), Box<dyn std::error::Error>> {
3638
init_crypto();
@@ -69,13 +71,15 @@ A Rust load balancer for Jonline servers deployed on Kubernetes
6971
return Ok(());
7072
} else {
7173
log::info!("Starting NGINX...");
72-
let _nginx = match std::process::Command::new("nginx")
73-
.args(&["-c", "nginx.conf.jbl", "-p", &pwd])
74+
let mut nginx = match std::process::Command::new("nginx")
75+
.args(&["-c", NGINX_CONF, "-p", &pwd, "-g", "daemon off;"])
7476
.spawn()
7577
{
7678
Ok(process) => process,
7779
Err(err) => panic!("Nginx crashed: {}", err),
7880
};
81+
82+
nginx.wait().expect("Nginx crashed");
7983
}
8084

8185
Ok(())
@@ -121,10 +125,12 @@ async fn setup_nginx_config(_options: &Options) -> io::Result<JonlineServerConfi
121125

122126
let env_servers = env::var("SERVERS")
123127
.expect("SERVERS must be set, JSON of the format [{\"host\": \"\", \"namespace\": \"\"}]");
128+
let env_no_certs = env::var("NO_CERTS").unwrap_or("false".to_string());
124129
// TODO:
125130
log::info!("SERVERS={:?}", env_servers);
126131
let servers: Vec<Server> = serde_json::from_str(&env_servers)
127132
.expect(format!("Invalid SERVERS JSON: {}", env_servers).as_str());
133+
let no_certs = env_no_certs == "true";
128134
log::info!("Parsed servers: {:?}", &servers);
129135

130136
// Source: https://stackoverflow.com/questions/73418121/how-allow-pod-from-default-namespace-read-secret-from-other-namespace/73419051#73419051
@@ -160,122 +166,146 @@ async fn setup_nginx_config(_options: &Options) -> io::Result<JonlineServerConfi
160166
)
161167
})?;
162168

163-
let nginx_conf = "nginx.conf.jbl";
164-
fs::write(nginx_conf, "events {}")?;
169+
fs::write(NGINX_CONF, "events {}")?;
170+
append_to_conf("http {")?;
165171
for server in &servers {
166172
let host = &server.host;
167173
let namespace = &server.namespace;
168174

169-
log::info!("Fetching certs for server {host} in namespace {namespace}...");
170-
let secrets_url = format!(
171-
"https://{}:{}/api/v1/namespaces/{}/secrets",
172-
k8s_server_host, k8s_server_port, &server.namespace
173-
);
174-
175-
// THE LOG BELOW SHOULD DEFINITELY NOT RUN IN REAL PRODUCTION ENVIRIONMENTS (but is needed to test security internally)
176-
// log::info!("Secrets URL: {:?}", secrets_url);
177-
// log::info!("K8s Secrets Token: {:?}", k8s_token);
178-
179-
let secrets = client
180-
.get(secrets_url)
181-
.send()
182-
.await
183-
.map_err(|e| {
184-
log::error!("Failed to fetch secrets: {:?}", e);
185-
io::Error::new(
186-
io::ErrorKind::InvalidInput,
187-
format!("Failed to fetch secrets: {:?}", e),
188-
)
189-
})?
190-
.text()
191-
.await
192-
.map_err(|e| {
193-
log::error!("Failed to read secrets: {:?}", e);
175+
if no_certs {
176+
log::info!("Skipping fetching certs for server {host} in namespace {namespace}...");
177+
178+
append_to_conf(&format!(
179+
"
180+
server {{
181+
listen 80;
182+
server_name {host};
183+
location / {{
184+
proxy_pass https://{host}:80/;
185+
proxy_http_version 1.1;
186+
proxy_set_header Upgrade $http_upgrade;
187+
proxy_set_header Connection 'upgrade';
188+
proxy_set_header Host $host;
189+
proxy_cache_bypass $http_upgrade;
190+
}}
191+
}}
192+
"
193+
))?;
194+
} else {
195+
log::info!("Fetching certs for server {host} in namespace {namespace}...");
196+
let secrets_url = format!(
197+
"https://{}:{}/api/v1/namespaces/{}/secrets",
198+
k8s_server_host, k8s_server_port, &server.namespace
199+
);
200+
201+
// THE LOG BELOW SHOULD DEFINITELY NOT RUN IN REAL PRODUCTION ENVIRIONMENTS (but is needed to test security internally)
202+
// log::info!("Secrets URL: {:?}", secrets_url);
203+
// log::info!("K8s Secrets Token: {:?}", k8s_token);
204+
205+
let secrets = client
206+
.get(secrets_url)
207+
.send()
208+
.await
209+
.map_err(|e| {
210+
log::error!("Failed to fetch secrets: {:?}", e);
211+
io::Error::new(
212+
io::ErrorKind::InvalidInput,
213+
format!("Failed to fetch secrets: {:?}", e),
214+
)
215+
})?
216+
.text()
217+
.await
218+
.map_err(|e| {
219+
log::error!("Failed to read secrets: {:?}", e);
220+
io::Error::new(
221+
io::ErrorKind::InvalidInput,
222+
format!("Failed to read secrets: {:?}", e),
223+
)
224+
})?;
225+
// log::debug!("Secrets response for server {:?}: {:?}", server, secrets);
226+
227+
let parsed_secrets =
228+
serde_json::from_str::<KubernetesSecrets>(&secrets).map_err(|e| {
229+
log::error!("Failed to parse secrets: {:?}", e);
230+
io::Error::new(
231+
io::ErrorKind::InvalidInput,
232+
format!("Failed to parse secrets: {:?}", e),
233+
)
234+
})?;
235+
236+
let tls_secrets = parsed_secrets
237+
.items
238+
.iter()
239+
.filter(|item| item.metadata.name == "jonline-generated-tls")
240+
.next()
241+
.ok_or_else(|| {
242+
log::error!("Failed to find tls secret for server: {:?}", server);
243+
io::Error::new(
244+
io::ErrorKind::InvalidInput,
245+
format!("Failed to find tls secret for server: {:?}", server),
246+
)
247+
})?;
248+
249+
log::info!(
250+
"Parsed TLS secrets for server {:?}: {:?}",
251+
server,
252+
tls_secrets
253+
);
254+
255+
let cert = tls_secrets.data.get("tls.crt").ok_or_else(|| {
256+
log::error!("Failed to find tls.crt for server: {:?}", server);
194257
io::Error::new(
195258
io::ErrorKind::InvalidInput,
196-
format!("Failed to read secrets: {:?}", e),
259+
format!("Failed to find tls.crt for server: {:?}", server),
197260
)
198261
})?;
199-
// log::debug!("Secrets response for server {:?}: {:?}", server, secrets);
200262

201-
let parsed_secrets = serde_json::from_str::<KubernetesSecrets>(&secrets).map_err(|e| {
202-
log::error!("Failed to parse secrets: {:?}", e);
203-
io::Error::new(
204-
io::ErrorKind::InvalidInput,
205-
format!("Failed to parse secrets: {:?}", e),
206-
)
207-
})?;
208-
209-
let tls_secrets = parsed_secrets
210-
.items
211-
.iter()
212-
.filter(|item| item.metadata.name == "jonline-generated-tls")
213-
.next()
214-
.ok_or_else(|| {
215-
log::error!("Failed to find tls secret for server: {:?}", server);
263+
let key = tls_secrets.data.get("tls.key").ok_or_else(|| {
264+
log::error!("Failed to find tls.key for server: {:?}", server);
216265
io::Error::new(
217266
io::ErrorKind::InvalidInput,
218-
format!("Failed to find tls secret for server: {:?}", server),
267+
format!("Failed to find tls.key for server: {:?}", server),
219268
)
220269
})?;
221270

222-
log::info!(
223-
"Parsed TLS secrets for server {:?}: {:?}",
224-
server,
225-
tls_secrets
226-
);
227-
228-
let cert = tls_secrets.data.get("tls.crt").ok_or_else(|| {
229-
log::error!("Failed to find tls.crt for server: {:?}", server);
230-
io::Error::new(
231-
io::ErrorKind::InvalidInput,
232-
format!("Failed to find tls.crt for server: {:?}", server),
233-
)
234-
})?;
235-
236-
let key = tls_secrets.data.get("tls.key").ok_or_else(|| {
237-
log::error!("Failed to find tls.key for server: {:?}", server);
238-
io::Error::new(
239-
io::ErrorKind::InvalidInput,
240-
format!("Failed to find tls.key for server: {:?}", server),
241-
)
242-
})?;
243-
244-
let cert_file = &format!("{host}.crt.jbl");
245-
fs::write(cert_file, cert)?;
246-
let key_file = &format!("{host}.key.jbl");
247-
fs::write(key_file, key)?;
248-
249-
let mut file = fs::OpenOptions::new()
250-
.write(true)
251-
.append(true)
252-
.open(nginx_conf)
253-
.unwrap();
254-
255-
if let Err(e) = writeln!(
256-
file,
257-
"
258-
server {{
259-
listen 443 ssl;
260-
server_name {host};
261-
ssl on;
262-
ssl_certificate {cert_file};
263-
ssl_certificate_key {key_file};
264-
include /etc/letsencrypt/options-ssl-nginx.conf;
265-
location / {{
266-
proxy_pass https://{host}:80/;
267-
proxy_http_version 1.1;
268-
proxy_set_header Upgrade $http_upgrade;
269-
proxy_set_header Connection 'upgrade';
270-
proxy_set_header Host $host;
271-
proxy_cache_bypass $http_upgrade;
271+
let cert_file = &format!("{host}.crt.jbl");
272+
fs::write(cert_file, cert)?;
273+
let key_file = &format!("{host}.key.jbl");
274+
fs::write(key_file, key)?;
275+
276+
append_to_conf(&format!(
277+
"
278+
server {{
279+
listen 443 ssl;
280+
server_name {host};
281+
ssl on;
282+
ssl_certificate {cert_file};
283+
ssl_certificate_key {key_file};
284+
include /etc/letsencrypt/options-ssl-nginx.conf;
285+
location / {{
286+
proxy_pass https://{host}:80/;
287+
proxy_http_version 1.1;
288+
proxy_set_header Upgrade $http_upgrade;
289+
proxy_set_header Connection 'upgrade';
290+
proxy_set_header Host $host;
291+
proxy_cache_bypass $http_upgrade;
292+
}}
272293
}}
273-
}}
274294
"
275-
) {
276-
eprintln!("Couldn't write to NGINX config file: {}", e);
295+
))?;
277296
}
278297
}
279298

299+
append_to_conf("}")?;
300+
280301
Ok(JonlineServerConfig { servers })
281302
}
303+
304+
fn append_to_conf(content: &str) -> io::Result<()> {
305+
let mut file = fs::OpenOptions::new()
306+
.write(true)
307+
.append(true)
308+
.open(NGINX_CONF)
309+
.unwrap();
310+
writeln!(file, "\n{}", content)
311+
}

frontends/tamagui/packages/app/features/accounts/accounts_sheet.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ export function AccountsSheet({ size = '$5', selectedGroup, primaryEntity }: Acc
159159
const renderContent = open || openDebounced;
160160

161161
const pinnedServers = usePinnedAccountsAndServers().map(aos =>
162-
`${aos.server ? serverID(aos.server) : null}-(${aos.account ? accountID(aos.account) : null})`);
162+
`${aos.server ? serverID(aos.server) : null}-(${aos.account ? accountID(aos.account) : null})`)
163+
.sort().join(',');
163164

164165
useEffect(() => {
165166
if (open) {

frontends/tamagui/packages/app/features/accounts/auth_sheet.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,10 @@ export function AuthSheet({ }: AuthSheetProps) {
166166
const alreadyHasAccounts = accountsOnServer.length > 0;
167167

168168

169-
const pinnedServers = usePinnedAccountsAndServers().map(aos =>
170-
`${aos.server ? serverID(aos.server) : null}-(${aos.account ? accountID(aos.account) : null})`);
169+
const pinnedServers = usePinnedAccountsAndServers()
170+
.map(aos =>
171+
`${aos.server ? serverID(aos.server) : null}-(${aos.account ? accountID(aos.account) : null})`)
172+
.sort().join(',');
171173

172174
useEffect(() => {
173175
if (open) {

0 commit comments

Comments
 (0)