1use crate::ec2::{
4 aws::*, deployer_directory, services::*, utils::*, Config, Error, Host, Hosts, InstanceConfig,
5 CREATED_FILE_NAME, LOGS_PORT, MONITORING_NAME, MONITORING_REGION, PROFILES_PORT, TRACES_PORT,
6};
7use futures::future::try_join_all;
8use std::{
9 collections::{BTreeSet, HashMap, HashSet},
10 fs::File,
11 net::IpAddr,
12 path::PathBuf,
13 slice,
14};
15use tokio::process::Command;
16use tracing::info;
17
18#[derive(Clone)]
20pub struct Deployment {
21 pub instance: InstanceConfig,
22 pub id: String,
23 pub ip: String,
24}
25
26pub struct RegionResources {
28 pub vpc_id: String,
29 pub vpc_cidr: String,
30 pub route_table_id: String,
31 pub subnet_id: String,
32 pub binary_sg_id: Option<String>,
33 pub monitoring_sg_id: Option<String>,
34}
35
36pub async fn create(config: &PathBuf) -> Result<(), Error> {
38 let config: Config = {
40 let config_file = File::open(config)?;
41 serde_yaml::from_reader(config_file)?
42 };
43 let tag = &config.tag;
44 info!(tag = tag.as_str(), "loaded configuration");
45
46 let tag_directory = deployer_directory(tag);
48 if tag_directory.exists() {
49 return Err(Error::CreationAttempted);
50 }
51 std::fs::create_dir_all(&tag_directory)?;
52 info!(path = ?tag_directory, "created tag directory");
53
54 let mut instance_names = HashSet::new();
56 for instance in &config.instances {
57 if instance_names.contains(&instance.name) || instance.name == MONITORING_NAME {
58 return Err(Error::InvalidInstanceName(instance.name.clone()));
59 }
60 instance_names.insert(instance.name.clone());
61 }
62
63 let deployer_ip = get_public_ip().await?;
65 info!(ip = deployer_ip.as_str(), "recovered public IP");
66
67 let key_name = format!("deployer-{tag}");
69 let private_key_path = tag_directory.join(format!("id_rsa_{tag}"));
70 let public_key_path = tag_directory.join(format!("id_rsa_{tag}.pub"));
71 let output = Command::new("ssh-keygen")
72 .arg("-t")
73 .arg("rsa")
74 .arg("-b")
75 .arg("4096")
76 .arg("-f")
77 .arg(private_key_path.to_str().unwrap())
78 .arg("-N")
79 .arg("")
80 .output()
81 .await?;
82 if !output.status.success() {
83 return Err(Error::KeygenFailed);
84 }
85 let public_key = std::fs::read_to_string(&public_key_path)?;
86 let private_key = private_key_path.to_str().unwrap();
87
88 let mut regions: BTreeSet<String> = config.instances.iter().map(|i| i.region.clone()).collect();
90 regions.insert(MONITORING_REGION.to_string());
91
92 let mut instance_types_by_region: HashMap<String, HashSet<String>> = HashMap::new();
94 for instance in &config.instances {
95 instance_types_by_region
96 .entry(instance.region.clone())
97 .or_default()
98 .insert(instance.instance_type.clone());
99 }
100 instance_types_by_region
101 .entry(MONITORING_REGION.to_string())
102 .or_default()
103 .insert(config.monitoring.instance_type.clone());
104
105 info!(?regions, "initializing resources");
107 let mut vpc_cidrs = HashMap::new();
108 let mut subnet_cidrs = HashMap::new();
109 let mut ec2_clients = HashMap::new();
110 let mut region_resources = HashMap::new();
111 for (idx, region) in regions.iter().enumerate() {
112 let ec2_client = create_ec2_client(Region::new(region.clone())).await;
114 ec2_clients.insert(region.clone(), ec2_client);
115 info!(region = region.as_str(), "created EC2 client");
116
117 let instance_types: Vec<String> =
119 instance_types_by_region[region].iter().cloned().collect();
120 assert_arm64_support(&ec2_clients[region], &instance_types).await?;
121
122 let az = find_availability_zone(&ec2_clients[region], &instance_types).await?;
124 info!(
125 az = az.as_str(),
126 region = region.as_str(),
127 "selected availability zone"
128 );
129
130 let vpc_cidr = format!("10.{idx}.0.0/16");
132 vpc_cidrs.insert(region.clone(), vpc_cidr.clone());
133 let vpc_id = create_vpc(&ec2_clients[region], &vpc_cidr, tag).await?;
134 info!(
135 vpc = vpc_id.as_str(),
136 region = region.as_str(),
137 "created VPC"
138 );
139 let igw_id = create_and_attach_igw(&ec2_clients[region], &vpc_id, tag).await?;
140 info!(
141 igw = igw_id.as_str(),
142 vpc = vpc_id.as_str(),
143 region = region.as_str(),
144 "created and attached IGW"
145 );
146 let route_table_id =
147 create_route_table(&ec2_clients[region], &vpc_id, &igw_id, tag).await?;
148 info!(
149 route_table = route_table_id.as_str(),
150 vpc = vpc_id.as_str(),
151 region = region.as_str(),
152 "created route table"
153 );
154 let subnet_cidr = format!("10.{idx}.1.0/24");
155 subnet_cidrs.insert(region.clone(), subnet_cidr.clone());
156 let subnet_id = create_subnet(
157 &ec2_clients[region],
158 &vpc_id,
159 &route_table_id,
160 &subnet_cidr,
161 &az,
162 tag,
163 )
164 .await?;
165 info!(
166 subnet = subnet_id.as_str(),
167 vpc = vpc_id.as_str(),
168 region = region.as_str(),
169 "created subnet"
170 );
171
172 let monitoring_sg_id = if *region == MONITORING_REGION {
174 let sg_id =
175 create_security_group_monitoring(&ec2_clients[region], &vpc_id, &deployer_ip, tag)
176 .await?;
177 info!(
178 sg = sg_id.as_str(),
179 vpc = vpc_id.as_str(),
180 region = region.as_str(),
181 "created monitoring security group"
182 );
183 Some(sg_id)
184 } else {
185 None
186 };
187
188 import_key_pair(&ec2_clients[region], &key_name, &public_key).await?;
190 info!(
191 key = key_name.as_str(),
192 region = region.as_str(),
193 "imported key pair"
194 );
195
196 info!(
198 vpc = vpc_id.as_str(),
199 subnet = subnet_id.as_str(),
200 subnet_cidr = subnet_cidr.as_str(),
201 region = region.as_str(),
202 "initialized resources"
203 );
204 region_resources.insert(
205 region.clone(),
206 RegionResources {
207 vpc_id,
208 vpc_cidr: vpc_cidr.clone(),
209 route_table_id,
210 subnet_id,
211 binary_sg_id: None,
212 monitoring_sg_id,
213 },
214 );
215 }
216 info!(?regions, "initialized resources");
217
218 info!("initializing VPC peering connections");
220 let monitoring_region = MONITORING_REGION.to_string();
221 let monitoring_resources = region_resources.get(&monitoring_region).unwrap();
222 let monitoring_vpc_id = &monitoring_resources.vpc_id;
223 let monitoring_cidr = &monitoring_resources.vpc_cidr;
224 let binary_regions: HashSet<String> =
225 config.instances.iter().map(|i| i.region.clone()).collect();
226 for region in ®ions {
227 if region != &monitoring_region && binary_regions.contains(region) {
228 let binary_resources = region_resources.get(region).unwrap();
229 let binary_vpc_id = &binary_resources.vpc_id;
230 let binary_cidr = &binary_resources.vpc_cidr;
231 let peer_id = create_vpc_peering_connection(
232 &ec2_clients[&monitoring_region],
233 monitoring_vpc_id,
234 binary_vpc_id,
235 region,
236 tag,
237 )
238 .await?;
239 info!(
240 peer = peer_id.as_str(),
241 monitoring = monitoring_vpc_id.as_str(),
242 binary = binary_vpc_id.as_str(),
243 region = region.as_str(),
244 "created VPC peering connection"
245 );
246 wait_for_vpc_peering_connection(&ec2_clients[region], &peer_id).await?;
247 info!(
248 peer = peer_id.as_str(),
249 region = region.as_str(),
250 "VPC peering connection is available"
251 );
252 accept_vpc_peering_connection(&ec2_clients[region], &peer_id).await?;
253 info!(
254 peer = peer_id.as_str(),
255 region = region.as_str(),
256 "accepted VPC peering connection"
257 );
258 add_route(
259 &ec2_clients[&monitoring_region],
260 &monitoring_resources.route_table_id,
261 binary_cidr,
262 &peer_id,
263 )
264 .await?;
265 add_route(
266 &ec2_clients[region],
267 &binary_resources.route_table_id,
268 monitoring_cidr,
269 &peer_id,
270 )
271 .await?;
272 info!(
273 peer = peer_id.as_str(),
274 monitoring = monitoring_vpc_id.as_str(),
275 binary = binary_vpc_id.as_str(),
276 region = region.as_str(),
277 "added routes for VPC peering connection"
278 );
279 }
280 }
281 info!("initialized VPC peering connections");
282
283 info!("launching monitoring instance");
285 let monitoring_instance_id;
286 let monitoring_ip;
287 let monitoring_private_ip;
288 let monitoring_sg_id;
289 {
290 let monitoring_ec2_client = &ec2_clients[&monitoring_region];
291 let ami_id = find_latest_ami(monitoring_ec2_client).await?;
292 let monitoring_instance_type = InstanceType::try_parse(&config.monitoring.instance_type)
293 .expect("Invalid instance type");
294 let monitoring_storage_class =
295 VolumeType::try_parse(&config.monitoring.storage_class).expect("Invalid storage class");
296 monitoring_sg_id = monitoring_resources
297 .monitoring_sg_id
298 .as_ref()
299 .unwrap()
300 .clone();
301 monitoring_instance_id = launch_instances(
302 monitoring_ec2_client,
303 &ami_id,
304 monitoring_instance_type,
305 config.monitoring.storage_size,
306 monitoring_storage_class,
307 &key_name,
308 &monitoring_resources.subnet_id,
309 &monitoring_sg_id,
310 1,
311 MONITORING_NAME,
312 tag,
313 )
314 .await?[0]
315 .clone();
316 monitoring_ip = wait_for_instances_running(
317 monitoring_ec2_client,
318 slice::from_ref(&monitoring_instance_id),
319 )
320 .await?[0]
321 .clone();
322 monitoring_private_ip =
323 get_private_ip(monitoring_ec2_client, &monitoring_instance_id).await?;
324 }
325 info!(ip = monitoring_ip.as_str(), "launched monitoring instance");
326
327 info!("creating security groups");
329 for (region, resources) in region_resources.iter_mut() {
330 let binary_sg_id = create_security_group_binary(
331 &ec2_clients[region],
332 &resources.vpc_id,
333 &deployer_ip,
334 &monitoring_ip,
335 tag,
336 &config.ports,
337 )
338 .await?;
339 info!(
340 sg = binary_sg_id.as_str(),
341 vpc = resources.vpc_id.as_str(),
342 region = region.as_str(),
343 "created binary security group"
344 );
345 resources.binary_sg_id = Some(binary_sg_id);
346 }
347 info!("created security groups");
348
349 info!("launching binary instances");
351 let mut launch_futures = Vec::new();
352 for instance in &config.instances {
353 let key_name = key_name.clone();
354 let region = instance.region.clone();
355 let resources = region_resources.get(®ion).unwrap();
356 let ec2_client = ec2_clients.get(®ion).unwrap();
357 let ami_id = find_latest_ami(ec2_client).await?;
358 let instance_type =
359 InstanceType::try_parse(&instance.instance_type).expect("Invalid instance type");
360 let storage_class =
361 VolumeType::try_parse(&instance.storage_class).expect("Invalid storage class");
362 let binary_sg_id = resources.binary_sg_id.as_ref().unwrap();
363 let tag = tag.clone();
364 let future = async move {
365 let instance_id = launch_instances(
366 ec2_client,
367 &ami_id,
368 instance_type,
369 instance.storage_size,
370 storage_class,
371 &key_name,
372 &resources.subnet_id,
373 binary_sg_id,
374 1,
375 &instance.name,
376 &tag,
377 )
378 .await?[0]
379 .clone();
380 let ip = wait_for_instances_running(ec2_client, slice::from_ref(&instance_id)).await?
381 [0]
382 .clone();
383 info!(
384 ip = ip.as_str(),
385 instance = instance.name.as_str(),
386 "launched instance"
387 );
388 Ok::<Deployment, Error>(Deployment {
389 instance: instance.clone(),
390 id: instance_id,
391 ip,
392 })
393 };
394 launch_futures.push(future);
395 }
396 let deployments: Vec<Deployment> = try_join_all(launch_futures).await?;
397 info!("launched binary instances");
398
399 let prometheus_service_path = tag_directory.join("prometheus.service");
401 std::fs::write(&prometheus_service_path, PROMETHEUS_SERVICE)?;
402 let loki_service_path = tag_directory.join("loki.service");
403 std::fs::write(&loki_service_path, LOKI_SERVICE)?;
404 let pyroscope_service_path = tag_directory.join("pyroscope.service");
405 std::fs::write(&pyroscope_service_path, PYROSCOPE_SERVICE)?;
406 let tempo_service_path = tag_directory.join("tempo.service");
407 std::fs::write(&tempo_service_path, TEMPO_SERVICE)?;
408 let promtail_service_path = tag_directory.join("promtail.service");
409 std::fs::write(&promtail_service_path, PROMTAIL_SERVICE)?;
410 let node_exporter_service_path = tag_directory.join("node_exporter.service");
411 std::fs::write(&node_exporter_service_path, NODE_EXPORTER_SERVICE)?;
412 let pyroscope_agent_service_path = tag_directory.join("pyroscope-agent.service");
413 std::fs::write(&pyroscope_agent_service_path, PYROSCOPE_AGENT_SERVICE)?;
414 let pyroscope_agent_timer_path = tag_directory.join("pyroscope-agent.timer");
415 std::fs::write(&pyroscope_agent_timer_path, PYROSCOPE_AGENT_TIMER)?;
416 let binary_service_path = tag_directory.join("binary.service");
417 std::fs::write(&binary_service_path, BINARY_SERVICE)?;
418
419 let logrotate_conf_path = tag_directory.join("logrotate.conf");
421 std::fs::write(&logrotate_conf_path, LOGROTATE_CONF)?;
422
423 let bbr_conf_path = tag_directory.join("99-bbr.conf");
425 std::fs::write(&bbr_conf_path, BBR_CONF)?;
426
427 info!("configuring monitoring instance");
429 wait_for_instances_ready(&ec2_clients[&monitoring_region], &[monitoring_instance_id]).await?;
430 let instances: Vec<(&str, &str, &str)> = deployments
431 .iter()
432 .map(|d| {
433 (
434 d.instance.name.as_str(),
435 d.ip.as_str(),
436 d.instance.region.as_str(),
437 )
438 })
439 .collect();
440 let prom_config = generate_prometheus_config(&instances);
441 let prom_path = tag_directory.join("prometheus.yml");
442 std::fs::write(&prom_path, prom_config)?;
443 let datasources_path = tag_directory.join("datasources.yml");
444 std::fs::write(&datasources_path, DATASOURCES_YML)?;
445 let all_yaml_path = tag_directory.join("all.yml");
446 std::fs::write(&all_yaml_path, ALL_YML)?;
447 let loki_config_path = tag_directory.join("loki.yml");
448 std::fs::write(&loki_config_path, LOKI_CONFIG)?;
449 let pyroscope_config_path = tag_directory.join("pyroscope.yml");
450 std::fs::write(&pyroscope_config_path, PYROSCOPE_CONFIG)?;
451 let tempo_yml_path = tag_directory.join("tempo.yml");
452 std::fs::write(&tempo_yml_path, TEMPO_CONFIG)?;
453 rsync_file(
454 private_key,
455 prom_path.to_str().unwrap(),
456 &monitoring_ip,
457 "/home/ubuntu/prometheus.yml",
458 )
459 .await?;
460 rsync_file(
461 private_key,
462 datasources_path.to_str().unwrap(),
463 &monitoring_ip,
464 "/home/ubuntu/datasources.yml",
465 )
466 .await?;
467 rsync_file(
468 private_key,
469 all_yaml_path.to_str().unwrap(),
470 &monitoring_ip,
471 "/home/ubuntu/all.yml",
472 )
473 .await?;
474 rsync_file(
475 private_key,
476 &config.monitoring.dashboard,
477 &monitoring_ip,
478 "/home/ubuntu/dashboard.json",
479 )
480 .await?;
481 rsync_file(
482 private_key,
483 prometheus_service_path.to_str().unwrap(),
484 &monitoring_ip,
485 "/home/ubuntu/prometheus.service",
486 )
487 .await?;
488 rsync_file(
489 private_key,
490 loki_config_path.to_str().unwrap(),
491 &monitoring_ip,
492 "/home/ubuntu/loki.yml",
493 )
494 .await?;
495 rsync_file(
496 private_key,
497 loki_service_path.to_str().unwrap(),
498 &monitoring_ip,
499 "/home/ubuntu/loki.service",
500 )
501 .await?;
502 rsync_file(
503 private_key,
504 node_exporter_service_path.to_str().unwrap(),
505 &monitoring_ip,
506 "/home/ubuntu/node_exporter.service",
507 )
508 .await?;
509 rsync_file(
510 private_key,
511 pyroscope_config_path.to_str().unwrap(),
512 &monitoring_ip,
513 "/home/ubuntu/pyroscope.yml",
514 )
515 .await?;
516 rsync_file(
517 private_key,
518 pyroscope_service_path.to_str().unwrap(),
519 &monitoring_ip,
520 "/home/ubuntu/pyroscope.service",
521 )
522 .await?;
523 rsync_file(
524 private_key,
525 tempo_yml_path.to_str().unwrap(),
526 &monitoring_ip,
527 "/home/ubuntu/tempo.yml",
528 )
529 .await?;
530 rsync_file(
531 private_key,
532 tempo_service_path.to_str().unwrap(),
533 &monitoring_ip,
534 "/home/ubuntu/tempo.service",
535 )
536 .await?;
537 enable_bbr(private_key, &monitoring_ip, bbr_conf_path.to_str().unwrap()).await?;
538 ssh_execute(
539 private_key,
540 &monitoring_ip,
541 &setup_node_exporter_cmd(NODE_EXPORTER_VERSION),
542 )
543 .await?;
544 poll_service_active(private_key, &monitoring_ip, "node_exporter").await?;
545 ssh_execute(
546 private_key,
547 &monitoring_ip,
548 &install_monitoring_cmd(
549 PROMETHEUS_VERSION,
550 GRAFANA_VERSION,
551 LOKI_VERSION,
552 PYROSCOPE_VERSION,
553 TEMPO_VERSION,
554 ),
555 )
556 .await?;
557 poll_service_active(private_key, &monitoring_ip, "prometheus").await?;
558 poll_service_active(private_key, &monitoring_ip, "loki").await?;
559 poll_service_active(private_key, &monitoring_ip, "pyroscope").await?;
560 poll_service_active(private_key, &monitoring_ip, "tempo").await?;
561 poll_service_active(private_key, &monitoring_ip, "grafana-server").await?;
562 info!("configured monitoring instance");
563
564 let hosts = Hosts {
566 monitoring: monitoring_private_ip.clone().parse::<IpAddr>().unwrap(),
567 hosts: deployments
568 .iter()
569 .map(|d| Host {
570 name: d.instance.name.clone(),
571 region: d.instance.region.clone(),
572 ip: d.ip.clone().parse::<IpAddr>().unwrap(),
573 })
574 .collect(),
575 };
576 let hosts_yaml = serde_yaml::to_string(&hosts)?;
577 let hosts_path = tag_directory.join("hosts.yaml");
578 std::fs::write(&hosts_path, hosts_yaml)?;
579
580 info!("configuring binary instances");
582 let mut start_futures = Vec::new();
583 for deployment in &deployments {
584 let tag_directory = tag_directory.clone();
585 let instance = deployment.instance.clone();
586 wait_for_instances_ready(
587 &ec2_clients[&instance.region],
588 slice::from_ref(&deployment.id),
589 )
590 .await?;
591 let ip = deployment.ip.clone();
592 let monitoring_private_ip = monitoring_private_ip.clone();
593 let hosts_path = hosts_path.clone();
594 let logrotate_conf_path = logrotate_conf_path.clone();
595 let bbr_conf_path = bbr_conf_path.clone();
596 let promtail_service_path = promtail_service_path.clone();
597 let node_exporter_service_path = node_exporter_service_path.clone();
598 let binary_service_path = binary_service_path.clone();
599 let pyroscope_agent_service_path = pyroscope_agent_service_path.clone();
600 let pyroscope_agent_timer_path = pyroscope_agent_timer_path.clone();
601 let future = async move {
602 rsync_file(private_key, &instance.binary, &ip, "/home/ubuntu/binary").await?;
603 rsync_file(
604 private_key,
605 &instance.config,
606 &ip,
607 "/home/ubuntu/config.conf",
608 )
609 .await?;
610 rsync_file(
611 private_key,
612 hosts_path.to_str().unwrap(),
613 &ip,
614 "/home/ubuntu/hosts.yaml",
615 )
616 .await?;
617 let promtail_config_path =
618 tag_directory.join(format!("promtail_{}.yml", instance.name));
619 std::fs::write(
620 &promtail_config_path,
621 promtail_config(
622 &monitoring_private_ip,
623 &instance.name,
624 ip.as_str(),
625 instance.region.as_str(),
626 ),
627 )?;
628 rsync_file(
629 private_key,
630 promtail_config_path.to_str().unwrap(),
631 &ip,
632 "/home/ubuntu/promtail.yml",
633 )
634 .await?;
635 rsync_file(
636 private_key,
637 promtail_service_path.to_str().unwrap(),
638 &ip,
639 "/home/ubuntu/promtail.service",
640 )
641 .await?;
642 rsync_file(
643 private_key,
644 node_exporter_service_path.to_str().unwrap(),
645 &ip,
646 "/home/ubuntu/node_exporter.service",
647 )
648 .await?;
649 rsync_file(
650 private_key,
651 binary_service_path.to_str().unwrap(),
652 &ip,
653 "/home/ubuntu/binary.service",
654 )
655 .await?;
656 rsync_file(
657 private_key,
658 logrotate_conf_path.to_str().unwrap(),
659 &ip,
660 "/home/ubuntu/logrotate.conf",
661 )
662 .await?;
663 rsync_file(
664 private_key,
665 pyroscope_agent_service_path.to_str().unwrap(),
666 &ip,
667 "/home/ubuntu/pyroscope-agent.service",
668 )
669 .await?;
670 let pyroscope_agent_script_path =
671 tag_directory.join(format!("pyroscope-agent_{}.sh", instance.name));
672 std::fs::write(
673 &pyroscope_agent_script_path,
674 generate_pyroscope_script(
675 &monitoring_private_ip,
676 &instance.name,
677 &ip,
678 &instance.region,
679 ),
680 )?;
681 rsync_file(
682 private_key,
683 pyroscope_agent_script_path.to_str().unwrap(),
684 &ip,
685 "/home/ubuntu/pyroscope-agent.sh",
686 )
687 .await?;
688 rsync_file(
689 private_key,
690 pyroscope_agent_timer_path.to_str().unwrap(),
691 &ip,
692 "/home/ubuntu/pyroscope-agent.timer",
693 )
694 .await?;
695 enable_bbr(private_key, &ip, bbr_conf_path.to_str().unwrap()).await?;
696 ssh_execute(private_key, &ip, &setup_promtail_cmd(PROMTAIL_VERSION)).await?;
697 poll_service_active(private_key, &ip, "promtail").await?;
698 ssh_execute(
699 private_key,
700 &ip,
701 &setup_node_exporter_cmd(NODE_EXPORTER_VERSION),
702 )
703 .await?;
704 poll_service_active(private_key, &ip, "node_exporter").await?;
705 ssh_execute(private_key, &ip, &install_binary_cmd(instance.profiling)).await?;
706 poll_service_active(private_key, &ip, "binary").await?;
707 info!(
708 ip = ip.as_str(),
709 instance = instance.name.as_str(),
710 "configured instance"
711 );
712 Ok::<String, Error>(ip)
713 };
714 start_futures.push(future);
715 }
716 let all_binary_ips = try_join_all(start_futures).await?;
717 info!("configured binary instances");
718
719 info!("updating monitoring security group to allow traffic from binary instances");
721 let monitoring_ec2_client = &ec2_clients[&monitoring_region];
722 if binary_regions.contains(&monitoring_region) {
723 let binary_sg_id = region_resources[&monitoring_region]
724 .binary_sg_id
725 .clone()
726 .unwrap();
727 monitoring_ec2_client
728 .authorize_security_group_ingress()
729 .group_id(&monitoring_sg_id)
730 .ip_permissions(
731 IpPermission::builder()
732 .ip_protocol("tcp")
733 .from_port(LOGS_PORT as i32)
734 .to_port(LOGS_PORT as i32)
735 .user_id_group_pairs(
736 UserIdGroupPair::builder()
737 .group_id(binary_sg_id.clone())
738 .build(),
739 )
740 .build(),
741 )
742 .ip_permissions(
743 IpPermission::builder()
744 .ip_protocol("tcp")
745 .from_port(PROFILES_PORT as i32)
746 .to_port(PROFILES_PORT as i32)
747 .user_id_group_pairs(
748 UserIdGroupPair::builder()
749 .group_id(binary_sg_id.clone())
750 .build(),
751 )
752 .build(),
753 )
754 .ip_permissions(
755 IpPermission::builder()
756 .ip_protocol("tcp")
757 .from_port(TRACES_PORT as i32)
758 .to_port(TRACES_PORT as i32)
759 .user_id_group_pairs(
760 UserIdGroupPair::builder()
761 .group_id(binary_sg_id.clone())
762 .build(),
763 )
764 .build(),
765 )
766 .send()
767 .await
768 .map_err(|err| err.into_service_error())?;
769 info!(
770 monitoring = monitoring_sg_id.as_str(),
771 binary = binary_sg_id.as_str(),
772 region = monitoring_region.as_str(),
773 "linked monitoring and binary security groups in monitoring region"
774 );
775 }
776 for region in ®ions {
777 if region != &monitoring_region && binary_regions.contains(region) {
778 let binary_cidr = ®ion_resources[region].vpc_cidr;
779 monitoring_ec2_client
780 .authorize_security_group_ingress()
781 .group_id(&monitoring_sg_id)
782 .ip_permissions(
783 IpPermission::builder()
784 .ip_protocol("tcp")
785 .from_port(LOGS_PORT as i32)
786 .to_port(LOGS_PORT as i32)
787 .ip_ranges(IpRange::builder().cidr_ip(binary_cidr).build())
788 .build(),
789 )
790 .ip_permissions(
791 IpPermission::builder()
792 .ip_protocol("tcp")
793 .from_port(PROFILES_PORT as i32)
794 .to_port(PROFILES_PORT as i32)
795 .ip_ranges(IpRange::builder().cidr_ip(binary_cidr).build())
796 .build(),
797 )
798 .ip_permissions(
799 IpPermission::builder()
800 .ip_protocol("tcp")
801 .from_port(TRACES_PORT as i32)
802 .to_port(TRACES_PORT as i32)
803 .ip_ranges(IpRange::builder().cidr_ip(binary_cidr).build())
804 .build(),
805 )
806 .send()
807 .await
808 .map_err(|err| err.into_service_error())?;
809 info!(
810 monitoring = monitoring_sg_id.as_str(),
811 binary = binary_cidr.as_str(),
812 region = region.as_str(),
813 "opened monitoring part to traffic from binary VPC"
814 );
815 }
816 }
817 info!("updated monitoring security group");
818
819 File::create(tag_directory.join(CREATED_FILE_NAME))?;
821 info!(
822 monitoring = monitoring_ip.as_str(),
823 binary = ?all_binary_ips,
824 "deployment complete"
825 );
826 Ok(())
827}