def build_virtual_desktop_controller()

in source/idea/idea-administrator/src/ideaadministrator/app/cdk/stacks/virtual_desktop_controller_stack.py [0:0]


    def build_virtual_desktop_controller(self):
        self.controller_security_group = VirtualDesktopPublicLoadBalancerAccessSecurityGroup(
            context=self.context,
            name=f'{self.module_id}-{self.COMPONENT_CONTROLLER}-security-group',
            scope=self.stack,
            vpc=self.cluster.vpc,
            bastion_host_security_group=self.cluster.get_security_group('bastion-host'),
            public_loadbalancer_security_group=self.cluster.get_security_group('external-load-balancer'),
            description='Security Group for Virtual Desktop Controller',
            directory_service_access=True,
            component_name='Virtual Desktop Controller'
        )

        controller_bootstrap_package_uri = self.stack.node.try_get_context('controller_bootstrap_package_uri')
        if Utils.is_empty(controller_bootstrap_package_uri):
            controller_bootstrap_package_uri = 'not-provided'

        self.controller_role = self._build_iam_role(
            role_description=f'IAM role assigned to virtual-desktop-{self.COMPONENT_CONTROLLER}',
            component_name=self.COMPONENT_CONTROLLER,
            component_jinja='virtual-desktop-controller.yml'
        )

        https_proxy = self.context.config().get_string('cluster.network.https_proxy', required=False, default='')
        no_proxy = self.context.config().get_string('cluster.network.no_proxy', required=False, default='')
        proxy_config = {}
        if Utils.is_not_empty(https_proxy):
            proxy_config = {
                'http_proxy': https_proxy,
                'https_proxy': https_proxy,
                'no_proxy': no_proxy
            }

        self.controller_auto_scaling_group = self._build_auto_scaling_group(
            component_name=self.COMPONENT_CONTROLLER,
            security_group=self.controller_security_group,
            iam_role=self.controller_role,
            substituted_userdata=cdk.Fn.sub(BootstrapUserDataBuilder(
                aws_region=self.aws_region,
                bootstrap_package_uri=controller_bootstrap_package_uri,
                install_commands=[
                    '/bin/bash virtual-desktop-controller/setup.sh'
                ],
                proxy_config=proxy_config,
                bootstrap_source_dir_path=ideaadministrator.props.bootstrap_source_dir,
                base_os=self.context.config().get_string('virtual-desktop-controller.controller.autoscaling.base_os', required=True)
            ).build()),
            node_type=constants.NODE_TYPE_APP
        )

        self.controller_auto_scaling_group.node.add_dependency(self.event_sqs_queue)
        self.controller_auto_scaling_group.node.add_dependency(self.controller_sqs_queue)

        # external target group
        external_target_group = elbv2.ApplicationTargetGroup(
            self.stack,
            'controller-target-group-ext',
            port=8443,
            protocol=elbv2.ApplicationProtocol.HTTPS,
            protocol_version=elbv2.ApplicationProtocolVersion.HTTP1,
            target_type=elbv2.TargetType.INSTANCE,
            vpc=self.cluster.vpc,
            target_group_name=self.get_target_group_name('vdc-ext')
        )
        external_target_group.configure_health_check(
            enabled=True,
            path='/healthcheck'
        )

        external_https_listener_arn = self.context.config().get_string('cluster.load_balancers.external_alb.https_listener_arn', required=True)
        path_patterns = self.context.config().get_list('virtual-desktop-controller.controller.endpoints.external.path_patterns', required=True)
        priority = self.context.config().get_int('virtual-desktop-controller.controller.endpoints.external.priority', required=True)
        cdk.CustomResource(
            self.stack,
            'controller-endpoint-ext',
            service_token=self.CLUSTER_ENDPOINTS_LAMBDA_ARN,
            properties={
                'endpoint_name': f'{self.module_id}-controller-endpoint-ext',
                'listener_arn': external_https_listener_arn,
                'priority': priority,
                'conditions': [
                    {
                        'Field': 'path-pattern',
                        'Values': path_patterns
                    }
                ],
                'actions': [
                    {
                        'Type': 'forward',
                        'TargetGroupArn': external_target_group.target_group_arn
                    }
                ]
            },
            resource_type='Custom::ControllerEndpointExternal'
        )

        # internal target group
        internal_target_group = elbv2.ApplicationTargetGroup(
            self.stack,
            'controller-target-group-int',
            port=8443,
            protocol=elbv2.ApplicationProtocol.HTTPS,
            protocol_version=elbv2.ApplicationProtocolVersion.HTTP1,
            target_type=elbv2.TargetType.INSTANCE,
            vpc=self.cluster.vpc,
            target_group_name=self.get_target_group_name('vdc-int')
        )
        internal_target_group.configure_health_check(
            enabled=True,
            path='/healthcheck'
        )

        internal_https_listener_arn = self.context.config().get_string('cluster.load_balancers.internal_alb.https_listener_arn', required=True)
        path_patterns = self.context.config().get_list('virtual-desktop-controller.controller.endpoints.internal.path_patterns', required=True)
        priority = self.context.config().get_int('virtual-desktop-controller.controller.endpoints.internal.priority', required=True)
        cdk.CustomResource(
            self.stack,
            'controller-endpoint-int',
            service_token=self.CLUSTER_ENDPOINTS_LAMBDA_ARN,
            properties={
                'endpoint_name': f'{self.module_id}-controller-endpoint-int',
                'listener_arn': internal_https_listener_arn,
                'priority': priority,
                'conditions': [
                    {
                        'Field': 'path-pattern',
                        'Values': path_patterns
                    }
                ],
                'actions': [
                    {
                        'Type': 'forward',
                        'TargetGroupArn': internal_target_group.target_group_arn
                    }
                ]
            },
            resource_type='Custom::ControllerEndpointInternal'
        )

        # receiving error jsii.errors.JSIIError: Cannot add AutoScalingGroup to 2nd Target Group
        # if same ASG is added to both internal and external target groups.
        # workaround below - reference to https://github.com/aws/aws-cdk/issues/5667#issuecomment-827549394
        self.controller_auto_scaling_group.node.default_child.target_group_arns = [
            internal_target_group.target_group_arn,
            external_target_group.target_group_arn
        ]