def _setup_opensearch_1_0(self) -> None:
        domain_name = "wrangler-os-1-0"
        validate_domain_name(domain_name)
        domain_arn = f"arn:aws:es:{self.region}:{self.account}:domain/{domain_name}"
        domain = opensearch.Domain(
            self,
            domain_name,
            domain_name=domain_name,
            version=opensearch.EngineVersion.OPENSEARCH_1_0,
            capacity=opensearch.CapacityConfig(
                data_node_instance_type="t3.small.search", data_nodes=1),
            access_policies=[
                iam.PolicyStatement(
                    effect=iam.Effect.ALLOW,
                    actions=["es:*"],
                    principals=[iam.AccountRootPrincipal()],
                    resources=[f"{domain_arn}/*"],
                )
            ],
            removal_policy=RemovalPolicy.DESTROY,
        )

        CfnOutput(self,
                  f"DomainEndpoint-{domain_name}",
                  value=domain.domain_endpoint)
    def _setup_elasticsearch_7_10_fgac(self) -> None:
        domain_name = "wrangler-es-7-10-fgac"
        validate_domain_name(domain_name)
        domain_arn = f"arn:aws:es:{self.region}:{self.account}:domain/{domain_name}"
        domain = opensearch.Domain(
            self,
            domain_name,
            domain_name=domain_name,
            version=opensearch.EngineVersion.ELASTICSEARCH_7_10,
            capacity=opensearch.CapacityConfig(
                data_node_instance_type="t3.small.search", data_nodes=1),
            access_policies=[
                iam.PolicyStatement(
                    effect=iam.Effect.ALLOW,
                    actions=["es:*"],
                    principals=[iam.AnyPrincipal()],  # FGACs
                    resources=[f"{domain_arn}/*"],
                )
            ],
            fine_grained_access_control=opensearch.AdvancedSecurityOptions(
                master_user_name=self.username,
                master_user_password=self.password_secret,
            ),
            node_to_node_encryption=True,
            encryption_at_rest=opensearch.EncryptionAtRestOptions(
                enabled=True, kms_key=self.key),
            enforce_https=True,
            removal_policy=RemovalPolicy.DESTROY,
        )

        CfnOutput(self,
                  f"DomainEndpoint-{domain_name}",
                  value=domain.domain_endpoint)
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        ################################################################################
        # VPC
        vpc = ec2.Vpc(self, "Monitoring VPC", max_azs=3)

        ################################################################################
        # Amazon OpenSearch Service domain
        es_sec_grp = ec2.SecurityGroup(
            self,
            'OpenSearchSecGrpMonitoring',
            vpc=vpc,
            allow_all_outbound=True,
            security_group_name='OpenSearchSecGrpMonitoring')
        es_sec_grp.add_ingress_rule(ec2.Peer.any_ipv4(), ec2.Port.tcp(80))
        es_sec_grp.add_ingress_rule(ec2.Peer.any_ipv4(), ec2.Port.tcp(443))

        domain = opensearch.Domain(
            self,
            'opensearch-service-monitor',
            version=opensearch.EngineVersion.
            OPENSEARCH_1_0,  # Upgrade when CDK upgrades
            domain_name=DOMAIN_NAME,
            removal_policy=core.RemovalPolicy.DESTROY,
            capacity=opensearch.CapacityConfig(
                data_node_instance_type=DOMAIN_DATA_NODE_INSTANCE_TYPE,
                data_nodes=DOMAIN_DATA_NODE_INSTANCE_COUNT,
                master_node_instance_type=DOMAIN_MASTER_NODE_INSTANCE_TYPE,
                master_nodes=DOMAIN_MASTER_NODE_INSTANCE_COUNT,
                warm_instance_type=DOMAIN_UW_NODE_INSTANCE_TYPE,
                warm_nodes=DOMAIN_UW_NODE_INSTANCE_COUNT),
            ebs=opensearch.EbsOptions(enabled=True,
                                      volume_size=DOMAIN_INSTANCE_VOLUME_SIZE,
                                      volume_type=ec2.EbsDeviceVolumeType.GP2),
            vpc=vpc,
            vpc_subnets=[ec2.SubnetType.PUBLIC],
            security_groups=[es_sec_grp],
            zone_awareness=opensearch.ZoneAwarenessConfig(
                enabled=True, availability_zone_count=DOMAIN_AZ_COUNT),
            enforce_https=True,
            node_to_node_encryption=True,
            encryption_at_rest={"enabled": True},
            use_unsigned_basic_auth=True,
            fine_grained_access_control={
                "master_user_name":
                DOMAIN_ADMIN_UNAME,
                "master_user_password":
                core.SecretValue.plain_text(DOMAIN_ADMIN_PW)
            })

        core.CfnOutput(
            self,
            "MasterUser",
            value=DOMAIN_ADMIN_UNAME,
            description="Master User Name for Amazon OpenSearch Service")

        core.CfnOutput(
            self,
            "MasterPW",
            value=DOMAIN_ADMIN_PW,
            description="Master User Password for Amazon OpenSearch Service")

        ################################################################################
        # Dynamo DB table for time stamp tracking
        table = ddb.Table(
            self,
            'opensearch-monitor-lambda-timestamp',
            table_name=TABLE_NAME,
            partition_key=ddb.Attribute(name="domain",
                                        type=ddb.AttributeType.STRING),
            sort_key=ddb.Attribute(name='region',
                                   type=ddb.AttributeType.STRING),
            removal_policy=core.RemovalPolicy.DESTROY)

        ################################################################################
        # Lambda monitoring function
        lambda_func = lambda_.Function(
            self,
            'CWMetricsToOpenSearch',
            function_name="CWMetricsToOpenSearch_monitoring",
            runtime=lambda_.Runtime.PYTHON_3_8,
            code=lambda_.Code.asset('CWMetricsToOpenSearch'),
            handler='handler.handler',
            memory_size=1024,
            timeout=core.Duration.minutes(10),
            vpc=vpc)

        table.grant_read_data(lambda_func)
        table.grant_write_data(lambda_func)
        lambda_func.add_environment('TABLE', table.table_name)
        lambda_func.add_environment('DOMAIN_ENDPOINT',
                                    'https://' + domain.domain_endpoint)
        lambda_func.add_environment('DOMAIN_ADMIN_UNAME', DOMAIN_ADMIN_UNAME)
        lambda_func.add_environment('DOMAIN_ADMIN_PW', DOMAIN_ADMIN_PW)
        lambda_func.add_environment('REGIONS', REGIONS_TO_MONITOR)

        # When the domain is created here, restrict access
        lambda_func.add_to_role_policy(
            iam.PolicyStatement(actions=['es:*'], resources=['*']))

        # The function needs to read CW events. Restrict
        lambda_func.add_to_role_policy(
            iam.PolicyStatement(actions=['cloudwatch:*'], resources=['*']))

        lambda_schedule = events.Schedule.rate(
            core.Duration.seconds(LAMBDA_INTERVAL))
        event_lambda_target = targets.LambdaFunction(handler=lambda_func)
        events.Rule(self,
                    "Monitoring",
                    enabled=True,
                    schedule=lambda_schedule,
                    targets=[event_lambda_target])

        ################################################################################
        # Lambda for CW Logs
        lambda_func_cw_logs = lambda_.Function(
            self,
            'CWLogsToOpenSearch',
            function_name="CWLogsToOpenSearch_monitoring",
            runtime=lambda_.Runtime.NODEJS_12_X,
            code=lambda_.Code.asset('CWLogsToOpenSearch'),
            handler='index.handler',
            vpc=vpc)

        # # Load Amazon OpenSearch Service Domain to env variable
        lambda_func_cw_logs.add_environment('DOMAIN_ENDPOINT',
                                            domain.domain_endpoint)

        # # When the domain is created here, restrict access
        lambda_func_cw_logs.add_to_role_policy(
            iam.PolicyStatement(actions=['es:*'], resources=['*']))

        # # The function needs to read CW Logs. Restrict
        lambda_func_cw_logs.add_to_role_policy(
            iam.PolicyStatement(actions=['logs:*'], resources=['*']))

        # Add permission to create CW logs trigger for all specified region and current account, as region does not have an option to be wildcard
        account_id = boto3.client("sts").get_caller_identity()["Account"]
        for region in json.loads(REGIONS_TO_MONITOR):
            lambda_func_cw_logs.add_permission(
                id="lambda-cw-logs-permission-" + region,
                principal=iam.ServicePrincipal("logs.amazonaws.com"),
                action="lambda:InvokeFunction",
                source_arn="arn:aws:logs:" + region + ":" + account_id +
                ":*:*:*")

        ################################################################################
        # Jump host for SSH tunneling and direct access
        sn_public = ec2.SubnetSelection(subnet_type=ec2.SubnetType.PUBLIC)

        amzn_linux = ec2.MachineImage.latest_amazon_linux(
            generation=ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
            edition=ec2.AmazonLinuxEdition.STANDARD,
            virtualization=ec2.AmazonLinuxVirt.HVM,
            storage=ec2.AmazonLinuxStorage.GENERAL_PURPOSE)

        # Instance Role and SSM Managed Policy
        role = iam.Role(self,
                        "InstanceSSM",
                        assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"))
        role.add_managed_policy(
            iam.ManagedPolicy.from_aws_managed_policy_name(
                "service-role/AmazonEC2RoleforSSM"))
        role.add_managed_policy(
            iam.ManagedPolicy.from_aws_managed_policy_name(
                "AmazonSSMManagedInstanceCore"))

        instance = ec2.Instance(
            self,
            'instance',
            instance_type=ec2.InstanceType(EC2_INSTANCE_TYPE),
            vpc=vpc,
            machine_image=amzn_linux,
            vpc_subnets=sn_public,
            key_name=EC2_KEY_NAME,
            role=role,
        )
        instance.connections.allow_from_any_ipv4(ec2.Port.tcp(22), 'SSH')
        instance.connections.allow_from_any_ipv4(ec2.Port.tcp(443), 'HTTPS')

        stmt = iam.PolicyStatement(actions=['es:*'],
                                   resources=[domain.domain_arn])
        instance.add_to_role_policy(stmt)

        # Create SNS topic, subscription, IAM roles, Policies
        sns_topic = sns.Topic(self, "cdk_monitoring_topic")

        sns_topic.add_subscription(
            subscriptions.EmailSubscription(SNS_NOTIFICATION_EMAIL))

        sns_policy_statement = iam.PolicyStatement(
            actions=["sns:publish"],
            resources=[sns_topic.topic_arn],
            effect=iam.Effect.ALLOW)
        sns_policy = iam.ManagedPolicy(self, "cdk_monitoring_policy")
        sns_policy.add_statements(sns_policy_statement)

        sns_role = iam.Role(
            self,
            "cdk_monitoring_sns_role",
            assumed_by=iam.ServicePrincipal("es.amazonaws.com"))
        sns_role.add_managed_policy(sns_policy)

        dirname = os.path.dirname(__file__)
        dashboards_asset = Asset(
            self,
            "DashboardsAsset",
            path=os.path.join(dirname,
                              'export_opensearch_dashboards_V1_0.ndjson'))
        dashboards_asset.grant_read(instance.role)
        dashboards_asset_path = instance.user_data.add_s3_download_command(
            bucket=dashboards_asset.bucket,
            bucket_key=dashboards_asset.s3_object_key,
        )

        nginx_asset = Asset(self,
                            "NginxAsset",
                            path=os.path.join(dirname,
                                              'nginx_opensearch.conf'))
        nginx_asset.grant_read(instance.role)
        nginx_asset_path = instance.user_data.add_s3_download_command(
            bucket=nginx_asset.bucket,
            bucket_key=nginx_asset.s3_object_key,
        )

        alerting_asset = Asset(self,
                               "AlertingAsset",
                               path=os.path.join(dirname, 'create_alerts.sh'))
        alerting_asset.grant_read(instance.role)
        alerting_asset_path = instance.user_data.add_s3_download_command(
            bucket=alerting_asset.bucket,
            bucket_key=alerting_asset.s3_object_key,
        )

        instance.user_data.add_commands(
            "yum update -y",
            "yum install jq -y",
            "amazon-linux-extras install nginx1.12",
            "cd /tmp/assets",
            "mv {} export_opensearch_dashboards_V1_0.ndjson".format(
                dashboards_asset_path),
            "mv {} nginx_opensearch.conf".format(nginx_asset_path),
            "mv {} create_alerts.sh".format(alerting_asset_path),
            "openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/cert.key -out /etc/nginx/cert.crt -subj /C=US/ST=./L=./O=./CN=.\n"
            "cp nginx_opensearch.conf /etc/nginx/conf.d/",
            "sed -i 's/DEFAULT_DOMAIN_NAME/" + DOMAIN_NAME +
            "/g' /tmp/assets/export_opensearch_dashboards_V1_0.ndjson",
            "sed -i 's/DOMAIN_ENDPOINT/" + domain.domain_endpoint +
            "/g' /etc/nginx/conf.d/nginx_opensearch.conf",
            "sed -i 's/DOMAIN_ENDPOINT/" + domain.domain_endpoint +
            "/g' /tmp/assets/create_alerts.sh",
            "sed -i 's=LAMBDA_CW_LOGS_ROLE_ARN=" +
            lambda_func_cw_logs.role.role_arn +
            "=g' /tmp/assets/create_alerts.sh",
            "sed -i 's=SNS_ROLE_ARN=" + sns_role.role_arn +
            "=g' /tmp/assets/create_alerts.sh",
            "sed -i 's/SNS_TOPIC_ARN/" + sns_topic.topic_arn +
            "/g' /tmp/assets/create_alerts.sh",
            "sed -i 's=DOMAIN_ADMIN_UNAME=" + DOMAIN_ADMIN_UNAME +
            "=g' /tmp/assets/create_alerts.sh",
            "sed -i 's=DOMAIN_ADMIN_PW=" + DOMAIN_ADMIN_PW +
            "=g' /tmp/assets/create_alerts.sh",
            "systemctl restart nginx.service",
            "chmod 500 create_alerts.sh",
            "sleep 5",
            "bash --verbose create_alerts.sh",
        )

        core.CfnOutput(self,
                       "Dashboards URL (via Jump host)",
                       value="https://" + instance.instance_public_ip,
                       description="Dashboards URL via Jump host")

        core.CfnOutput(
            self,
            "SNS Subscription Alert Message",
            value=SNS_NOTIFICATION_EMAIL,
            description="Please confirm your SNS subscription receievedt at")