summaryrefslogtreecommitdiffstats
path: root/test/vpp_object.py
blob: 088cc39ce0a90742e0022c433881a01ac764b74b (plain)
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
""" abstract vpp object and object registry """

from abc import ABCMeta, abstractmethod


class VppObject(object):
    """ Abstract vpp object """
    __metaclass__ = ABCMeta

    @abstractmethod
    def add_vpp_config(self):
        """ Add the configuration for this object to vpp. """
        pass

    @abstractmethod
    def query_vpp_config(self):
        """Query the vpp configuration.

        :return: True if the object is configured"""
        pass

    @abstractmethod
    def remove_vpp_config(self):
        """ Remove the configuration for this object from vpp. """
        pass

    @abstractmethod
    def object_id(self):
        """ Return a unique string representing this object. """
        pass


class VppObjectRegistry(object):
    """ Class which handles automatic configuration cleanup. """
    _shared_state = {}

    def __init__(self):
        self.__dict__ = self._shared_state
        if not hasattr(self, "_object_registry"):
            self._object_registry = []
        if not hasattr(self, "_object_dict"):
            self._object_dict = dict()

    def register(self, obj, logger):
        """ Register an object in the registry. """
        if obj.object_id() not in self._object_dict:
            self._object_registry.append(obj)
            self._object_dict[obj.object_id()] = obj
            logger.debug("REG: registering %s" % obj)
        else:
            logger.debug("REG: duplicate add, ignoring (%s)" % obj)

    def unregister_all(self, logger):
        """ Remove all object registrations from registry. """
        logger.debug("REG: removing all object registrations")
        self._object_registry = []
        self._object_dict = dict()

    def remove_vpp_config(self, logger):
        """
        Remove configuration (if present) from vpp and then remove all objects
        from the registry.
        """
        if not self._object_registry:
            logger.info("REG: No objects registered for auto-cleanup.")
            return
        logger.info("REG: Removing VPP configuration for registered objects")
        # remove the config in reverse order as there might be dependencies
        failed = []
        for obj in reversed(self._object_registry):
            if obj.query_vpp_config():
                logger.info("REG: Removing configuration for %s" % obj)
                obj.remove_vpp_config()
                if obj.query_vpp_config():
                    failed.append(obj)
            else:
                logger.info(
                    "REG: Skipping removal for %s, configuration not present" %
                    obj)
        self.unregister_all(logger)
        if failed:
            logger.error("REG: Couldn't remove configuration for object(s):")
            for obj in failed:
                logger.error(repr(obj))
            raise Exception("Couldn't remove configuration for object(s): %s" %
                            (", ".join(str(x) for x in failed)))
or: #ae81ff } /* Literal.Number */ .highlight .s { color: #e6db74 } /* Literal.String */ .highlight .na { color: #a6e22e } /* Name.Attribute */ .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ .highlight .nc { color: #a6e22e } /* Name.Class */ .highlight .no { color: #66d9ef } /* Name.Constant */ .highlight .nd { color: #a6e22e } /* Name.Decorator */ .highlight .ni { color: #f8f8f2 } /* Name.Entity */ .highlight .ne { color: #a6e22e } /* Name.Exception */ .highlight .nf { color: #a6e22e } /* Name.Function */ .highlight .nl { color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
data "vault_aws_access_credentials" "creds" {
  backend = "${var.vault-name}-path"
  role    = "${var.vault-name}-role"
}

locals {
  ansible_python_executable = "/usr/bin/python3"
  availability_zone         = "eu-central-1a"
  name                      = "csit-vpc"
  environment               = "csit-vpc-environment"
  key_pair_key_name         = "${var.resource_prefix}-${var.testbed_name}-pk"
  placement_group_name      = "${var.resource_prefix}-${var.testbed_name}-pg"
  security_group_name       = "${var.resource_prefix}-${var.testbed_name}-sg"
  testbed_name              = "testbed1"
  topology_name             = "3n-aws-c5n"
  tg_name                   = "${var.resource_prefix}-${var.testbed_name}-tg"
  sut1_name                 = "${var.resource_prefix}-${var.testbed_name}-sut1"
  sut2_name                 = "${var.resource_prefix}-${var.testbed_name}-sut2"
}

# Create VPC
module "vpc" {
  source                   = "../terraform-aws-vpc"
  security_group_name      = local.security_group_name
  subnet_availability_zone = local.availability_zone
  tags_name                = local.name
  tags_environment         = local.environment
}

# Create Subnet
module "subnet_b" {
  source                   = "../terraform-aws-subnet"
  subnet_cidr_block        = "192.168.10.0/24"
  subnet_ipv6_cidr_block   = cidrsubnet(module.vpc.vpc_ipv6_cidr_block, 8, 2)
  subnet_availability_zone = local.availability_zone
  tags_name                = local.name
  tags_environment         = local.environment
  subnet_vpc_id            = module.vpc.vpc_id
}

module "subnet_c" {
  source                   = "../terraform-aws-subnet"
  subnet_cidr_block        = "200.0.0.0/24"
  subnet_ipv6_cidr_block   = cidrsubnet(module.vpc.vpc_ipv6_cidr_block, 8, 3)
  subnet_availability_zone = local.availability_zone
  tags_name                = local.name
  tags_environment         = local.environment
  subnet_vpc_id            = module.vpc.vpc_id
}

module "subnet_d" {
  source                   = "../terraform-aws-subnet"
  subnet_cidr_block        = "192.168.20.0/24"
  subnet_ipv6_cidr_block   = cidrsubnet(module.vpc.vpc_ipv6_cidr_block, 8, 4)
  subnet_availability_zone = local.availability_zone
  tags_name                = local.name
  tags_environment         = local.environment
  subnet_vpc_id            = module.vpc.vpc_id
}

# Create Private Key
module "private_key" {
  source  = "pmikus/private-key/tls"
  version = "4.0.4"

  private_key_algorithm = var.private_key_algorithm
}

# Create Key Pair
module "key_pair" {
  source  = "pmikus/key-pair/aws"
  version = "5.7.0"

  key_pair_key_name   = local.key_pair_key_name
  key_pair_public_key = module.private_key.public_key_openssh

  key_pair_tags = {
    "Environment" = local.environment
  }
}

# Create Placement Group
resource "aws_placement_group" "placement_group" {
  name     = local.placement_group_name
  strategy = var.placement_group_strategy
}

# Create Instance
resource "aws_instance" "tg" {
  depends_on = [
    module.vpc,
    aws_placement_group.placement_group
  ]
  ami                                  = var.tg_ami
  availability_zone                    = local.availability_zone
  associate_public_ip_address          = var.tg_associate_public_ip_address
  instance_initiated_shutdown_behavior = var.tg_instance_initiated_shutdown_behavior
  instance_type                        = var.tg_instance_type
  key_name                             = module.key_pair.key_pair_key_name
  placement_group                      = aws_placement_group.placement_group.id
  private_ip                           = var.tg_private_ip
  source_dest_check                    = var.tg_source_dest_check
  subnet_id                            = module.vpc.vpc_subnet_id
  vpc_security_group_ids               = [module.vpc.vpc_security_group_id]
  # host_id                            = "1"

  root_block_device {
    delete_on_termination = true
    volume_size           = 50
  }

  tags = {
    "Name"        = local.tg_name
    "Environment" = local.environment
  }
}

resource "aws_network_interface" "tg_if1" {
  depends_on = [
    module.subnet_b,
    aws_instance.tg
  ]
  private_ip        = var.tg_if1_private_ip
  private_ips       = [var.tg_if1_private_ip]
  security_groups   = [module.vpc.vpc_security_group_id]
  source_dest_check = var.tg_source_dest_check
  subnet_id         = module.subnet_b.subnet_id

  attachment {
    instance     = aws_instance.tg.id
    device_index = 1
  }

  tags = {
    "Name"        = local.tg_name
    "Environment" = local.environment
  }
}

resource "aws_network_interface" "tg_if2" {
  depends_on = [
    module.subnet_d,
    aws_instance.tg
  ]
  private_ips       = [var.tg_if2_private_ip]
  security_groups   = [module.vpc.vpc_security_group_id]
  source_dest_check = var.tg_source_dest_check
  subnet_id         = module.subnet_d.subnet_id

  attachment {
    instance     = aws_instance.tg.id
    device_index = 2
  }

  tags = {
    "Name"        = local.tg_name
    "Environment" = local.environment
  }
}

data "aws_network_interface" "tg_if1" {
  id = aws_network_interface.tg_if1.id
}

data "aws_network_interface" "tg_if2" {
  id = aws_network_interface.tg_if2.id
}

resource "aws_route" "route_tg_if1" {
  depends_on = [
    aws_instance.tg
  ]
  destination_cidr_block = var.destination_cidr_block_tg_if1
  network_interface_id   = aws_instance.tg.primary_network_interface_id
  route_table_id         = module.vpc.vpc_main_route_table_id
}

resource "aws_route" "route_tg_if2" {
  depends_on = [
    aws_instance.tg
  ]
  destination_cidr_block = var.destination_cidr_block_tg_if2
  network_interface_id   = aws_instance.tg.primary_network_interface_id
  route_table_id         = module.vpc.vpc_main_route_table_id
}

resource "aws_instance" "sut1" {
  depends_on = [
    module.vpc,
    aws_placement_group.placement_group
  ]
  ami                                  = var.sut1_ami
  availability_zone                    = local.availability_zone
  associate_public_ip_address          = var.sut1_associate_public_ip_address
  instance_initiated_shutdown_behavior = var.sut1_instance_initiated_shutdown_behavior
  instance_type                        = var.sut1_instance_type
  key_name                             = module.key_pair.key_pair_key_name
  placement_group                      = aws_placement_group.placement_group.id
  private_ip                           = var.sut1_private_ip
  source_dest_check                    = var.sut1_source_dest_check
  subnet_id                            = module.vpc.vpc_subnet_id
  vpc_security_group_ids               = [module.vpc.vpc_security_group_id]
  # host_id                            = "2"

  root_block_device {
    delete_on_termination = true
    volume_size           = 50
  }

  tags = {
    "Name"        = local.sut1_name
    "Environment" = local.environment
  }
}

resource "aws_network_interface" "sut1_if1" {
  depends_on = [
    module.subnet_b,
    aws_instance.sut1
  ]
  private_ips       = [var.sut1_if1_private_ip]
  security_groups   = [module.vpc.vpc_security_group_id]
  source_dest_check = var.sut1_source_dest_check
  subnet_id         = module.subnet_b.subnet_id

  attachment {
    instance     = aws_instance.sut1.id
    device_index = 1
  }

  tags = {
    "Name"        = local.sut1_name
    "Environment" = local.environment
  }
}

resource "aws_network_interface" "sut1_if2" {
  depends_on = [
    module.subnet_c,
    aws_instance.sut1
  ]
  private_ips       = [var.sut1_if2_private_ip]
  security_groups   = [module.vpc.vpc_security_group_id]
  source_dest_check = var.sut1_source_dest_check
  subnet_id         = module.subnet_c.subnet_id

  attachment {
    instance     = aws_instance.sut1.id
    device_index = 2
  }

  tags = {
    "Name"        = local.sut1_name
    "Environment" = local.environment
  }
}

data "aws_network_interface" "sut1_if1" {
  id = aws_network_interface.sut1_if1.id
}

data "aws_network_interface" "sut1_if2" {
  id = aws_network_interface.sut1_if2.id
}

resource "aws_instance" "sut2" {
  depends_on = [
    module.vpc,
    aws_placement_group.placement_group
  ]
  ami                                  = var.sut2_ami
  availability_zone                    = local.availability_zone
  associate_public_ip_address          = var.sut2_associate_public_ip_address
  instance_initiated_shutdown_behavior = var.sut2_instance_initiated_shutdown_behavior
  instance_type                        = var.sut2_instance_type
  key_name                             = module.key_pair.key_pair_key_name
  placement_group                      = aws_placement_group.placement_group.id
  private_ip                           = var.sut2_private_ip
  source_dest_check                    = var.sut2_source_dest_check
  subnet_id                            = module.vpc.vpc_subnet_id
  vpc_security_group_ids               = [module.vpc.vpc_security_group_id]
  # host_id                            = "2"

  root_block_device {
    delete_on_termination = true
    volume_size           = 50
  }

  tags = {
    "Name"        = local.sut2_name
    "Environment" = local.environment
  }
}

resource "aws_network_interface" "sut2_if1" {
  depends_on = [
    module.subnet_c,
    aws_instance.sut2
  ]
  private_ips       = [var.sut2_if1_private_ip]
  security_groups   = [module.vpc.vpc_security_group_id]
  source_dest_check = var.sut2_source_dest_check
  subnet_id         = module.subnet_c.subnet_id

  attachment {
    instance     = aws_instance.sut2.id
    device_index = 1
  }

  tags = {
    "Name"        = local.sut2_name
    "Environment" = local.environment
  }
}

resource "aws_network_interface" "sut2_if2" {
  depends_on = [
    module.subnet_d,
    aws_instance.sut2
  ]
  private_ips       = [var.sut2_if2_private_ip]
  security_groups   = [module.vpc.vpc_security_group_id]
  source_dest_check = var.sut2_source_dest_check
  subnet_id         = module.subnet_d.subnet_id

  attachment {
    instance     = aws_instance.sut2.id
    device_index = 2
  }

  tags = {
    "Name"        = local.sut2_name
    "Environment" = local.environment
  }
}

data "aws_network_interface" "sut2_if1" {
  id = aws_network_interface.sut2_if1.id
}

data "aws_network_interface" "sut2_if2" {
  id = aws_network_interface.sut2_if2.id
}

resource "null_resource" "deploy_tg" {
  depends_on = [
    aws_instance.tg,
    aws_network_interface.tg_if1,
    aws_network_interface.tg_if2,
    aws_instance.sut1,
    aws_network_interface.sut1_if1,
    aws_network_interface.sut1_if2,
    aws_instance.sut2,
    aws_network_interface.sut2_if1,
    aws_network_interface.sut2_if2
  ]

  connection {
    user        = "ubuntu"
    host        = aws_instance.tg.public_ip
    private_key = module.private_key.private_key_pem
  }

  provisioner "remote-exec" {
    inline = var.first_run_commands
  }
}

resource "null_resource" "deploy_sut1" {
  depends_on = [
    aws_instance.tg,
    aws_network_interface.tg_if1,
    aws_network_interface.tg_if2,
    aws_instance.sut1,
    aws_network_interface.sut1_if1,
    aws_network_interface.sut1_if2,
    aws_instance.sut2,
    aws_network_interface.sut2_if1,
    aws_network_interface.sut2_if2
  ]

  connection {
    user        = "ubuntu"
    host        = aws_instance.sut1.public_ip
    private_key = module.private_key.private_key_pem
  }

  provisioner "remote-exec" {
    inline = var.first_run_commands
  }
}

resource "null_resource" "deploy_sut2" {
  depends_on = [
    aws_instance.tg,
    aws_network_interface.tg_if1,
    aws_network_interface.tg_if2,
    aws_instance.sut1,
    aws_network_interface.sut1_if1,
    aws_network_interface.sut1_if2,
    aws_instance.sut2,
    aws_network_interface.sut2_if1,
    aws_network_interface.sut2_if2
  ]

  connection {
    user        = "ubuntu"
    host        = aws_instance.sut2.public_ip
    private_key = module.private_key.private_key_pem
  }

  provisioner "remote-exec" {
    inline = var.first_run_commands
  }
}

resource "local_file" "topology_file" {
  depends_on = [
    aws_instance.tg,
    aws_instance.sut1,
    aws_instance.sut2
  ]

  content = templatefile(
    "${path.module}/topology-${local.topology_name}.tftpl",
    {
      tg_if1_mac     = data.aws_network_interface.tg_if1.mac_address
      tg_if2_mac     = data.aws_network_interface.tg_if2.mac_address
      dut1_if1_mac   = data.aws_network_interface.sut1_if1.mac_address
      dut1_if2_mac   = data.aws_network_interface.sut1_if2.mac_address
      dut2_if1_mac   = data.aws_network_interface.sut2_if1.mac_address
      dut2_if2_mac   = data.aws_network_interface.sut2_if2.mac_address
      tg_public_ip   = aws_instance.tg.public_ip
      dut1_public_ip = aws_instance.sut1.public_ip
      dut2_public_ip = aws_instance.sut2.public_ip
    }
  )
  filename = "${path.module}/../../topologies/available/${local.topology_name}-${local.testbed_name}.yaml"
}

resource "local_file" "hosts" {
  depends_on = [
    aws_instance.tg,
    aws_instance.sut1,
    aws_instance.sut2
  ]

  content = templatefile(
    "${path.module}/hosts.tftpl",
    {
      tg_public_ip   = aws_instance.tg.public_ip
      dut1_public_ip = aws_instance.sut1.public_ip
      dut2_public_ip = aws_instance.sut2.public_ip
    }
  )
  filename = "${path.module}/../../fdio.infra.ansible/inventories/cloud_inventory/hosts.yaml"
}