diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8fa5b33 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +env \ No newline at end of file diff --git a/DeadlineStack/README.md b/DeadlineStack/README.md index 506f5a8..f9938e6 100644 --- a/DeadlineStack/README.md +++ b/DeadlineStack/README.md @@ -34,13 +34,19 @@ These instructions assume that your working directory is `examples/deadline/SIC- npx --package=aws-rfdk@${RFDK_VERSION} stage-deadline --output stage ${RFDK_DEADLINE_VERSION} ``` -5. Deploy all the stacks: +5. Deploy ECR repository and push Spotfleet Mgmt UI related Docker image to it. Run the script like this: + + ```bash + ./deploy_spotfleet_mgmt_ui.sh -a YOUR_AWS_ACCOUNT_ID -r YOUR_AWS_REGION -p YOUR_AWS_PROFILE + ``` + +6. Deploy all the stacks: ```bash cdk deploy "*" ``` -6. Once you are finished with the sample app, you can tear it down by running: +7. Once you are finished with the sample app, you can tear it down by running: **Note:** Any resources created by the Spot Event Plugin will not be deleted with `cdk destroy`. Make sure that all such resources (e.g. Spot Fleet Request or Fleet Instances) are cleaned up, before destroying the stacks. Disable the Spot Event Plugin by setting 'state' property to 'SpotEventPluginState.DISABLED' or via Deadline Monitor, ensure you shutdown all Pulse instances and then terminate any Spot Fleet Requests in the AWS EC2 Instance Console. diff --git a/DeadlineStack/deploy_spotfleet_mgmt_ui.sh b/DeadlineStack/deploy_spotfleet_mgmt_ui.sh new file mode 100755 index 0000000..3e8cdb8 --- /dev/null +++ b/DeadlineStack/deploy_spotfleet_mgmt_ui.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# Script parameters for AWS account, region, and profile +while getopts a:r:p: flag; do + case "${flag}" in + a) + AWS_ACCOUNT=${OPTARG} + ;; + r) + REGION=${OPTARG} + ;; + p) + PROFILE=${OPTARG:-default} + ;; + *) echo "Invalid option: -$flag" ;; + esac +done + +# Function to create ECR repository if it doesn't exist +create_ecr_repo() { + repo_name="spotfleet-mgmt-ui" + echo "Checking if the ECR repository '${repo_name}' exists..." + + if ! aws ecr describe-repositories --region "${REGION}" --repository-names "${repo_name}" > /dev/null 2>&1; then + echo "Repository does not exist. Creating '${repo_name}' repository..." + aws ecr create-repository --region "${REGION}" --repository-name "${repo_name}" + else + echo "Repository '${repo_name}' already exists. Skipping creation." + fi +} + +# Create the ECR repository +create_ecr_repo + +# Define repository URL +SpotfleetMgmtUiRepository="${AWS_ACCOUNT}.dkr.ecr.${REGION}.amazonaws.com/spotfleet-mgmt-ui" + +# Build the Docker image for spotfleet-mgmt-ui +echo "Building the spotfleet-mgmt-ui Docker image..." +docker build -t "${SpotfleetMgmtUiRepository}":latest ./spotfleet-mgmt-ui + +# Login to AWS ECR +echo "Logging in to AWS ECR..." +aws ecr get-login-password --region "${REGION}" | docker login --username AWS --password-stdin "${AWS_ACCOUNT}".dkr.ecr."${REGION}".amazonaws.com + +# Push the image to the ECR repository +echo "Pushing the spotfleet-mgmt-ui image to ECR..." +docker push "${SpotfleetMgmtUiRepository}":latest + +# Output the Docker image URI +echo "Docker image pushed successfully." +echo "Docker Image URI: ${SpotfleetMgmtUiRepository}:latest" diff --git a/DeadlineStack/package/config.py b/DeadlineStack/package/config.py index 76c7510..fe04844 100644 --- a/DeadlineStack/package/config.py +++ b/DeadlineStack/package/config.py @@ -13,17 +13,20 @@ Mapping, ) + class AppConfig: """ Configuration values for the sample app. TODO: Fill these in with your own values. """ + def __init__(self): # A map of regions to Deadline Client Linux AMIs. As an example, the base Linux Deadline 10.1.19.4 AMI ID # from us-west-2 is filled in. It can be used as-is, added to, or replaced. Ideally the version here # should match the one used for staging the render queue and usage based licensing recipes. - self.deadline_client_linux_ami_map: Mapping[str, str] = {'us-west-2': 'ami-067d780e98fe3b09f'} + self.deadline_client_linux_ami_map: Mapping[str, str] = { + 'eu-west-3': 'ami-08afbca41a57b6e72'} # Whether the DeadlineResourceTrackerAccessRole IAM role required by Deadline's Resource Tracker should be created in this CDK app. # @@ -33,17 +36,17 @@ def __init__(self): # Note: Deadline's Resource Tracker only supports being used by a single Deadline Repository per AWS account. self.create_resource_tracker_role: bool = True # AWS region deadline is deployed into (ex: "us-west-2") - self.aws_region:str = "" + self.aws_region: str = "eu-west-3" # Deadline VPC CIDR required (ex:"172.0.0.0/16") - self.vpc_cidr: str = "" + self.vpc_cidr: str = "10.2.0.0/16" # Bucket for workers script - self.s3_bucket_workers: str = "" + self.s3_bucket_workers: str = "deadline-workers-scripts-test" # S3 bucket worker region (verifiy this on S3 service) - self.s3_bucket_workers_region: str = "" + self.s3_bucket_workers_region: str = "eu-west-3" # EC2 test instance AMI - self.custom_ami_id: str = "" + self.custom_ami_id: str = "ami-0c75d0e0e7489cfbe" # EC2 test instance key pair - self.ec2_key_pair_name: str = "" + self.ec2_key_pair_name: str = "deadlinetest" # Spot instance fleet configuration # For each fleet, use those parameters: @@ -56,23 +59,14 @@ def __init__(self): # "user_data_script" expecting filename (sh for Linux, ps1 for Windows) is an additional script file you uploaded to the worker S3 bucket self.fleet_config: dict = { "fleet1": { - "name":"Blender", - "is_linux":1, + "name": "Blender", + "is_linux": 1, # "instance_types":[InstanceType.of(InstanceClass.BURSTABLE3, InstanceSize.LARGE)], - "instance_types":["m5.large","m5.2xlarge"], - "worker_machine_image":"", - "max_capacity":1, - "allocation_strategy":SpotFleetAllocationStrategy.CAPACITY_OPTIMIZED, - "user_data_script":"" - }, - "fleet2": { - "name":"Maya", - "is_linux":1, - "instance_types":["m5.large","m5.2xlarge"], - "worker_machine_image":"", - "max_capacity":1, - "allocation_strategy":SpotFleetAllocationStrategy.CAPACITY_OPTIMIZED, - "user_data_script":"" + "instance_types": ["m5.large", "m5.2xlarge"], + "worker_machine_image": "ami-08afbca41a57b6e72", + "max_capacity": 1, + "allocation_strategy": SpotFleetAllocationStrategy.CAPACITY_OPTIMIZED, + "user_data_script": "" } } diff --git a/DeadlineStack/package/lib/deadline_stack.py b/DeadlineStack/package/lib/deadline_stack.py index ccc64f9..2222f65 100644 --- a/DeadlineStack/package/lib/deadline_stack.py +++ b/DeadlineStack/package/lib/deadline_stack.py @@ -1,6 +1,11 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +from aws_cdk import aws_ecs as ecs +from aws_cdk import aws_ecr as ecr +from aws_cdk.aws_ecr_assets import DockerImageAsset +from aws_cdk import aws_servicediscovery as sd + from dataclasses import dataclass from aws_cdk import ( Duration, @@ -10,8 +15,6 @@ Tags, ) from aws_cdk.aws_ec2 import ( - CfnRoute, - CfnVPCPeeringConnection, IMachineImage, Instance, InstanceClass, @@ -40,12 +43,6 @@ PrivateHostedZone, ) -from aws_cdk.aws_route53resolver import ( - CfnResolverEndpoint, - CfnResolverRule, - CfnResolverRuleAssociation, -) - from aws_cdk.aws_s3 import ( Bucket, ) @@ -100,17 +97,17 @@ class DeadlineStackProps(StackProps): ec2_key_pair_name: str - # USER DATA Handling class UserDataProvider(InstanceUserDataProvider): def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps, os_key: int, user_data_script=None, **kwargs): super().__init__(scope, stack_id, **kwargs) - self.props=props - self.os_key=os_key - self.user_data_script=user_data_script + self.props = props + self.os_key = os_key + self.user_data_script = user_data_script def pre_render_queue_configuration(self, host) -> None: - host.user_data.add_commands("echo 'Entering preRenderQueueConfiguration'") + host.user_data.add_commands( + "echo 'Entering preRenderQueueConfiguration'") try: license_bucket = Bucket.from_bucket_attributes( @@ -126,27 +123,38 @@ def pre_render_queue_configuration(self, host) -> None: bucket_key=f'deadline/{self.user_data_script}', region=self.props.s3_bucket_workers_region ) - host.user_data.add_commands(f"echo 'Downloaded user data script to {user_data_path}'") - host.user_data.add_execute_file_command(file_path=user_data_path) + host.user_data.add_commands( + f"echo 'Downloaded user data script to {user_data_path}'") + host.user_data.add_execute_file_command( + file_path=user_data_path) host.user_data.add_commands("echo 'Executed user data script'") else: - host.user_data.add_commands("echo 'No user_data_script provided'") + host.user_data.add_commands( + "echo 'No user_data_script provided'") except Exception as e: host.user_data.add_commands(f"echo 'Error: {str(e)}'") - host.user_data.add_commands("echo 'Exiting preRenderQueueConfiguration'") + host.user_data.add_commands( + "echo 'Exiting preRenderQueueConfiguration'") + def pre_worker_configuration(self, host) -> None: if self.os_key == 1: - host.user_data.add_commands("/opt/Thinkbox/Deadline10/bin/deadlinecommand -SetIniFileSetting ProxyRoot0 'renderqueue.deadline.internal:4433'") - host.user_data.add_commands("/opt/Thinkbox/Deadline10/bin/deadlinecommand -SetIniFileSetting ProxyRoot 'renderqueue.deadline.internal:4433'") + host.user_data.add_commands( + "/opt/Thinkbox/Deadline10/bin/deadlinecommand -SetIniFileSetting ProxyRoot0 'renderqueue.deadline.internal:4433'") + host.user_data.add_commands( + "/opt/Thinkbox/Deadline10/bin/deadlinecommand -SetIniFileSetting ProxyRoot 'renderqueue.deadline.internal:4433'") else: - host.user_data.add_commands(r"$DEADLINE_PATH = 'C:\Program Files\Thinkbox\Deadline10\bin'") + host.user_data.add_commands( + r"$DEADLINE_PATH = 'C:\Program Files\Thinkbox\Deadline10\bin'") host.user_data.add_commands("pushd $DEADLINE_PATH") - host.user_data.add_commands(".\deadlinecommand.exe -SetIniFileSetting ProxyRoot0 'renderqueue.deadline.internal:4433'") - host.user_data.add_commands(".\deadlinecommand.exe -SetIniFileSetting ProxyRoot 'renderqueue.deadline.internal:4433'") + host.user_data.add_commands( + ".\deadlinecommand.exe -SetIniFileSetting ProxyRoot0 'renderqueue.deadline.internal:4433'") + host.user_data.add_commands( + ".\deadlinecommand.exe -SetIniFileSetting ProxyRoot 'renderqueue.deadline.internal:4433'") pass + class DeadlineStack(Stack): """ This stack contains all the constructs required to set the Spot Event Plugin Configuration. @@ -162,63 +170,163 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps """ super().__init__(scope, stack_id, **kwargs) - # Create Cloud9 IAM group - cloud9IamGroup= Group(self, "Cloud9Admin") - cloud9IamGroup.add_managed_policy(ManagedPolicy.from_aws_managed_policy_name('AWSCloud9Administrator')) + cloud9IamGroup = Group(self, "Cloud9Admin") + cloud9IamGroup.add_managed_policy( + ManagedPolicy.from_aws_managed_policy_name('AWSCloud9Administrator')) - - # The VPC that all components of the render farm will be created in. + # The VPC that all components of the render farm will be created in. vpc = Vpc( self, 'Vpc', max_azs=99, nat_gateways=1, - cidr = props.vpc_cidr, - subnet_configuration = [SubnetConfiguration(subnet_type=SubnetType.PUBLIC, + cidr=props.vpc_cidr, + subnet_configuration=[SubnetConfiguration(subnet_type=SubnetType.PUBLIC, cidr_mask=28, name="public"), - SubnetConfiguration(subnet_type=SubnetType.PRIVATE_WITH_EGRESS, + SubnetConfiguration(subnet_type=SubnetType.PRIVATE_WITH_EGRESS, cidr_mask=19, name="render-") - ] + ] + ) + + #### Sfmt #### + + # Create an ECS cluster + ecs_cluster = ecs.Cluster( + self, + 'Spotfleet-Mgmt-UI-ECS-Cluster', + cluster_name='spotfleet-mgmt-ui', + enable_fargate_capacity_providers=True, + vpc=vpc + ) + + # Create task IAM role + ecs_task_role = Role( + self, + 'TaskRole', + role_name='deadline-ecs-task-access-ecr', + assumed_by=ServicePrincipal('ecs-tasks.amazonaws.com'), + managed_policies=[ + ManagedPolicy.from_aws_managed_policy_name( + 'AmazonEC2ContainerRegistryReadOnly'), + ManagedPolicy.from_aws_managed_policy_name( + 'service-role/AmazonECSTaskExecutionRolePolicy') + ] + ) + + # Create task execution IAM role + ecs_task_execution_role = Role( + self, + 'TaskExecutionRole', + role_name='deadline-ecs-task-execution-access-ecr', + assumed_by=ServicePrincipal('ecs-tasks.amazonaws.com'), + managed_policies=[ + ManagedPolicy.from_aws_managed_policy_name( + 'AmazonEC2ContainerRegistryReadOnly'), + ManagedPolicy.from_aws_managed_policy_name( + 'service-role/AmazonECSTaskExecutionRolePolicy') + ] + ) + + # Reference ECR repository + ecr_repository = ecr.Repository.from_repository_name( + self, "spotfleet-mgmt-ui-repo", repository_name="spotfleet-mgmt-ui") + + # Create an ECS task definition + task_definition = ecs.FargateTaskDefinition( + self, "run-sfmt-ui", + task_role=ecs_task_role, + execution_role=ecs_task_execution_role, + ) + container = task_definition.add_container( + "sfmt-ui-container", + image=ecs.ContainerImage.from_ecr_repository( + ecr_repository, + "latest"), + ) + container.add_port_mappings(ecs.PortMapping(container_port=4242)) + + # Create a private DNS namespace for the Deadline SFMT UI application + namespace = sd.PrivateDnsNamespace( + self, "DeadlineSfmtUiNamespace", + name="deadlinesfmtui.internal", + vpc=vpc + ) + + # Create a service discovery service for the Deadline SFMT UI application + discovery_service = namespace.create_service( + "DeadlineSfmtMgmtUiService", + name="sfmt-mgmt-ui-service" + ) + + # ecs_service = ecs.FargateService( + # self, "DeadlineSfmtMgmtUiFargateService", + # service_name="sfmt-mgmt-ui-fargate-service", + # cluster=ecs_cluster, + # task_definition=task_definition, + # cloud_map_options=ecs.CloudMapOptions( + # cloud_map_namespace=discovery_service.namespace, + # name=discovery_service.service_name + # ) + # ) + + # Security Group for EC2 Instance to communicate with AWS Systems Manager + task_definition_sg = SecurityGroup( + self, + "TaskDefSecurityGroup", + vpc=vpc, + description="Security group for EC2 instance to allow communication with AWS Systems Manager", + allow_all_outbound=True # Allows all outbound traffic by default ) + # Adding ingress rule to allow RDP access from any source + task_definition_sg.add_ingress_rule( + peer=Peer.ipv4("10.2.0.0/16"), + connection=Port.tcp(4242), + description="Allow inbound traffic from VPC CIDR on port 4242" + ) + + #### Sfmt end #### + # security group for resolver endpoint worker_resolver_endpoint_sg = SecurityGroup( - self, - "Deadline_workers_to_ad_sg", - vpc=vpc, - allow_all_outbound=True, - description="Deadline_workers_to_ad", - security_group_name="deadline_worker_to_ad" + self, + "Deadline_workers_to_ad_sg", + vpc=vpc, + allow_all_outbound=True, + description="Deadline_workers_to_ad", + security_group_name="deadline_worker_to_ad" - ) + ) worker_resolver_endpoint_sg.add_ingress_rule( - peer=Peer.ipv4(props.vpc_cidr), - connection=Port.tcp(53), - description="allow workers to connect to studio active directory" - ) + peer=Peer.ipv4(props.vpc_cidr), + connection=Port.tcp(53), + description="allow workers to connect to studio active directory" + ) # create worker IAM role fleet_instance_role = Role( - self, - 'FleetRole', - role_name= 'Deadline-Fleet-Instance-Role', - assumed_by=ServicePrincipal('ec2.amazonaws.com'), - managed_policies= [ManagedPolicy.from_aws_managed_policy_name('AWSThinkboxDeadlineSpotEventPluginWorkerPolicy')], - inline_policies= { - "s3_licence_access": PolicyDocument( - statements=[ - PolicyStatement( - actions=["s3:GetObject"], - resources=["arn:aws:s3:::"+props.s3_bucket_workers+"/*"] - ) - ] - ) - }, - ) + self, + 'FleetRole', + role_name='Deadline-Fleet-Instance-Role', + assumed_by=ServicePrincipal('ec2.amazonaws.com'), + managed_policies=[ManagedPolicy.from_aws_managed_policy_name( + 'AWSThinkboxDeadlineSpotEventPluginWorkerPolicy')], + inline_policies={ + "s3_licence_access": PolicyDocument( + statements=[ + PolicyStatement( + actions=["s3:GetObject"], + resources=["arn:aws:s3:::" + + props.s3_bucket_workers+"/*"] + ) + ] + ) + }, + ) recipes = ThinkboxDockerRecipes( self, @@ -294,7 +402,8 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps internal_protocol=ApplicationProtocol.HTTPS, ), ) - render_queue.connections.allow_default_port_from(Peer.ipv4(props.vpc_cidr)) + render_queue.connections.allow_default_port_from( + Peer.ipv4(props.vpc_cidr)) if props.create_resource_tracker_role: # Creates the Resource Tracker Access role. This role is required to exist in your account so the resource tracker will work properly @@ -302,58 +411,62 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps self, 'ResourceTrackerRole', assumed_by=ServicePrincipal('lambda.amazonaws.com'), - managed_policies= [ManagedPolicy.from_aws_managed_policy_name('AWSThinkboxDeadlineResourceTrackerAccessPolicy')], - role_name= 'DeadlineResourceTrackerAccessRole', + managed_policies=[ManagedPolicy.from_aws_managed_policy_name( + 'AWSThinkboxDeadlineResourceTrackerAccessPolicy')], + role_name='DeadlineResourceTrackerAccessRole', ) # Spot fleet Security group worker_fleet_sg = SecurityGroup( - self, - "Deadline_workers_fleet", - vpc=vpc, - allow_all_outbound=True, - description="Deadline_workers_fleet", - security_group_name="deadline_workers_fleet" + self, + "Deadline_workers_fleet", + vpc=vpc, + allow_all_outbound=True, + description="Deadline_workers_fleet", + security_group_name="deadline_workers_fleet" - ) + ) # iterate through props.fleet_config dict - spot_fleet=[]; + spot_fleet = [] for i, fleet in props.fleet_config.items(): # determine worker AMI OS if fleet["is_linux"] == 1: - ami=MachineImage.generic_linux({props.aws_region:fleet["worker_machine_image"]}) + ami = MachineImage.generic_linux( + {props.aws_region: fleet["worker_machine_image"]}) else: - ami=MachineImage.generic_windows({props.aws_region:fleet["worker_machine_image"]}) + ami = MachineImage.generic_windows( + {props.aws_region: fleet["worker_machine_image"]}) # Format workstation list - instance_type_format_list= [] + instance_type_format_list = [] for l in fleet["instance_types"]: - instance_type_format= InstanceType(l) + instance_type_format = InstanceType(l) instance_type_format_list.append(instance_type_format) if "user_data_script" in fleet: - user_data_script=fleet["user_data_script"] + user_data_script = fleet["user_data_script"] else: - user_data_script=None + user_data_script = None spot_fleet_config = SpotEventPluginFleet( - self, - f'{fleet["name"]}_spot_event_plugin_fleet', - vpc=vpc, - render_queue=render_queue, - deadline_groups=[f'{fleet["name"]}_group'], - security_groups=[worker_fleet_sg], - instance_types=instance_type_format_list, - worker_machine_image=ami, - max_capacity=fleet["max_capacity"], - fleet_instance_role=fleet_instance_role, - # use the following parameter this if you need to connect to workers - # key_name=key_pair_name, - allocation_strategy=fleet["allocation_strategy"], - user_data_provider=UserDataProvider( - self, f'{fleet["name"]}_user_data_provider', props=props, os_key=fleet["is_linux"], user_data_script=user_data_script), + self, + f'{fleet["name"]}_spot_event_plugin_fleet', + vpc=vpc, + render_queue=render_queue, + deadline_groups=[f'{fleet["name"]}_group'], + security_groups=[worker_fleet_sg], + instance_types=instance_type_format_list, + worker_machine_image=ami, + max_capacity=fleet["max_capacity"], + fleet_instance_role=fleet_instance_role, + # use the following parameter this if you need to connect to workers + # key_name=key_pair_name, + allocation_strategy=fleet["allocation_strategy"], + user_data_provider=UserDataProvider( + self, f'{fleet["name"]}_user_data_provider', props=props, os_key=fleet["is_linux"], user_data_script=user_data_script), ) # Optional: Add additional tags to both spot fleet request and spot instances. - Tags.of(spot_fleet_config).add('fleet', f'Deadline-{fleet["name"]}') + Tags.of(spot_fleet_config).add( + 'fleet', f'Deadline-{fleet["name"]}') spot_fleet.append(spot_fleet_config) ConfigureSpotEventPlugin( @@ -383,19 +496,19 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps description="Allow RDP access from any source" ) - # IAM Role for EC2 Fleet Connect through AWS Systems Manager ssm_role = Role( self, "SSMInstanceRole", assumed_by=ServicePrincipal("ec2.amazonaws.com"), managed_policies=[ - ManagedPolicy.from_aws_managed_policy_name("AmazonSSMManagedInstanceCore"), - ManagedPolicy.from_aws_managed_policy_name("service-role/AmazonEC2RoleforSSM") + ManagedPolicy.from_aws_managed_policy_name( + "AmazonSSMManagedInstanceCore"), + ManagedPolicy.from_aws_managed_policy_name( + "service-role/AmazonEC2RoleforSSM") ] ) - # IAM policy to allow EC2 instance to access the S3 bucket s3_access_policy = PolicyStatement( actions=["s3:GetObject"], @@ -409,27 +522,30 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps instance = Instance( self, "RepositoryAccessInstance", - instance_type=InstanceType.of(InstanceClass.COMPUTE5, InstanceSize.LARGE), # c5.large - machine_image=MachineImage.generic_windows({props.aws_region: props.custom_ami_id}), # Custom Windows AMI with Deadline client + instance_type=InstanceType.of( + InstanceClass.COMPUTE5, InstanceSize.LARGE), # c5.large + # Custom Windows AMI with Deadline client + machine_image=MachineImage.generic_windows( + {props.aws_region: props.custom_ami_id}), vpc=vpc, - vpc_subnets={"subnet_type": SubnetType.PUBLIC}, # Deploy in a public subnet + # Deploy in a public subnet + vpc_subnets={"subnet_type": SubnetType.PUBLIC}, security_group=ssm_sg, role=ssm_role, key_name=props.ec2_key_pair_name ) - # Adding user data to connect to the repository instance.user_data.add_commands( "echo 'Configuring instance to access Deadline Repository'", # Add commands here to configure the instance to connect to the repository ) - # Modify user data to download the certificate from S3 instance.user_data.add_commands( "New-Item -ItemType Directory -Path C:\\deadline -Force", - "Read-S3Object -BucketName " + props.s3_bucket_workers + " -Key 'deadline/ca.crt' -File 'C:\\deadline\\ca.crt' -ErrorAction Stop", + "Read-S3Object -BucketName " + props.s3_bucket_workers + + " -Key 'deadline/ca.crt' -File 'C:\\deadline\\ca.crt' -ErrorAction Stop", "Write-Output 'configuring deadline connection'", "$DEADLINE_PATH = 'C:\\Program Files\\Thinkbox\\Deadline10\\bin'", "pushd $DEADLINE_PATH", @@ -440,4 +556,3 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps ".\\deadlinecommand.exe -SetIniFileSetting ClientSSLAuthentication NotRequired", ".\\deadlinecommand.exe -SetIniFileSetting ProxyRoot renderqueue.deadline.internal:4433" ) - diff --git a/DeadlineStack/spotfleet-mgmt-ui/Dockerfile b/DeadlineStack/spotfleet-mgmt-ui/Dockerfile new file mode 100644 index 0000000..217db0e --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/Dockerfile @@ -0,0 +1,20 @@ +# Stage 1: Build React App +FROM node:20-alpine as build +WORKDIR /app +COPY . . +# RUN cd client && npm install && npm run build +RUN cd client && npm install +RUN cd client && npm run build + + +# Stage 2: Build FastAPI App +FROM tiangolo/uvicorn-gunicorn-fastapi:python3.10 as production +WORKDIR /app +COPY --from=build /app/client/build /app/build +COPY server/main.py /app/main.py + +# Expose port 4242 for FastAPI app +EXPOSE 4242 + +# Command to run the application +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "4242"] diff --git a/DeadlineStack/spotfleet-mgmt-ui/README.md b/DeadlineStack/spotfleet-mgmt-ui/README.md new file mode 100644 index 0000000..5f1b54a --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/README.md @@ -0,0 +1,33 @@ +# Deadline SFMT + +This repository contains the Deadline SFMT client and server, which is built with React using TypeScript and python with FastAPI. The application is Dockerized for easy deployment. Follow the steps below to build and run the application. + +## Prerequisites + +Make sure you have Docker installed on your machine. If not, you can download and install it from [Docker's official website](https://docs.docker.com/get-docker/). + +## Build the Application + +To build the application, run the following commands in the terminal: + +```bash +docker build -t name:tag . +``` + +Replace name with the desired name for your Docker image, and tag with the desired tag (e.g., latest). +This command will build the React app (written in TypeScript) in the first stage and the FastAPI app in the second stage of the Dockerfile. + +## Run the Application + +After building the application, you can run it with the following command: + +```bash +docker run -p 4242:4242 name:tag +``` + +Replace name and tag with the same values you used during the build. +This command will start the application, and you can access it in your web browser at http://localhost:4242. + +## Access the Application + +Open your web browser and go to http://localhost:4242 to access the Deadline SFMT application. diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/.eslintrc.js b/DeadlineStack/spotfleet-mgmt-ui/client/.eslintrc.js new file mode 100644 index 0000000..95b2b43 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/.eslintrc.js @@ -0,0 +1,34 @@ +module.exports = { + env: { + browser: true, + es2021: true + }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended' + ], + overrides: [], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaFeatures: { + jsx: true + }, + ecmaVersion: 'latest', + sourceType: 'module' + }, + plugins: [ + 'react', + '@typescript-eslint', + 'react-hooks' + ], + rules: { + '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], + }, + settings: { + react: { + version: 'detect' + } + } +}; \ No newline at end of file diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/.gitignore b/DeadlineStack/spotfleet-mgmt-ui/client/.gitignore new file mode 100644 index 0000000..4d29575 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/README.md b/DeadlineStack/spotfleet-mgmt-ui/client/README.md new file mode 100644 index 0000000..b87cb00 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/README.md @@ -0,0 +1,46 @@ +# Getting Started with Create React App + +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `npm start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.\ +You will also see any lint errors in the console. + +### `npm test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `npm run build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `npm run eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/config-overrides.js b/DeadlineStack/spotfleet-mgmt-ui/client/config-overrides.js new file mode 100644 index 0000000..ccc1b75 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/config-overrides.js @@ -0,0 +1,15 @@ +const { override, fixBabelImports, addLessLoader } = require('customize-cra'); + +module.exports = override( + fixBabelImports('import', { + libraryName: 'antd', + libraryDirectory: 'es', + style: true, + }), + addLessLoader({ + lessOptions: { + javascriptEnabled: true, + modifyVars: { '@primary-color': '#1DA57A' }, // Vous pouvez personnaliser les couleurs ici + }, + }), +); diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/package.json b/DeadlineStack/spotfleet-mgmt-ui/client/package.json new file mode 100644 index 0000000..4717476 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/package.json @@ -0,0 +1,51 @@ +{ + "name": "client", + "version": "0.1.0", + "private": true, + "dependencies": { + "@ant-design/icons": "^5.3.0", + "@testing-library/jest-dom": "^5.17.0", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "@types/jest": "^27.5.2", + "@types/node": "^16.18.79", + "@types/react": "^18.2.55", + "antd": "^5.14.0", + "customize-cra": "^1.0.0", + "@types/react-dom": "^18.2.19", + "react": "^18.2.0", + "react-app-rewired": "^2.2.1", + "react-dom": "^18.2.0", + "typescript": "^4.9.5", + "web-vitals": "^2.1.4" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "eslint": "^8.56.0", + "eslint-plugin-react": "^7.33.2", + "react-scripts": "^5.0.1" + } +} diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/public/index.html b/DeadlineStack/spotfleet-mgmt-ui/client/public/index.html new file mode 100644 index 0000000..aa069f2 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/public/index.html @@ -0,0 +1,43 @@ + + +
+ + + + + + + + + +