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