From 33f9a72cc625bbc476a12dfda1d7ac77eb948e4a Mon Sep 17 00:00:00 2001 From: Nathan Agez Date: Tue, 20 Feb 2024 13:03:57 +0100 Subject: [PATCH 1/5] feat(ui): add base layer --- DeadlineStack/spotfleet-mgmt-ui/Dockerfile | 20 ++++++++ DeadlineStack/spotfleet-mgmt-ui/README.md | 33 ++++++++++++ .../spotfleet-mgmt-ui/client/.eslintrc.js | 34 +++++++++++++ .../spotfleet-mgmt-ui/client/.gitignore | 23 +++++++++ .../spotfleet-mgmt-ui/client/README.md | 46 +++++++++++++++++ .../client/config-overrides.js | 15 ++++++ .../spotfleet-mgmt-ui/client/package.json | 51 +++++++++++++++++++ .../client/public/index.html | 43 ++++++++++++++++ .../client/public/manifest.json | 25 +++++++++ .../client/public/robots.txt | 3 ++ .../spotfleet-mgmt-ui/client/src/App.css | 18 +++++++ .../spotfleet-mgmt-ui/client/src/App.test.tsx | 9 ++++ .../spotfleet-mgmt-ui/client/src/App.tsx | 13 +++++ .../spotfleet-mgmt-ui/client/src/index.css | 13 +++++ .../spotfleet-mgmt-ui/client/src/index.tsx | 19 +++++++ .../client/src/react-app-env.d.ts | 1 + .../client/src/reportWebVitals.ts | 15 ++++++ .../client/src/setupTests.ts | 5 ++ .../spotfleet-mgmt-ui/client/tsconfig.json | 26 ++++++++++ .../spotfleet-mgmt-ui/server/.gitignore | 1 + .../spotfleet-mgmt-ui/server/main.py | 23 +++++++++ .../spotfleet-mgmt-ui/server/requirements.txt | 2 + 22 files changed, 438 insertions(+) create mode 100644 DeadlineStack/spotfleet-mgmt-ui/Dockerfile create mode 100644 DeadlineStack/spotfleet-mgmt-ui/README.md create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/.eslintrc.js create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/.gitignore create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/README.md create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/config-overrides.js create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/package.json create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/public/index.html create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/public/manifest.json create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/public/robots.txt create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/src/App.css create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/src/App.test.tsx create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/src/App.tsx create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/src/index.css create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/src/index.tsx create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/src/react-app-env.d.ts create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/src/reportWebVitals.ts create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/src/setupTests.ts create mode 100644 DeadlineStack/spotfleet-mgmt-ui/client/tsconfig.json create mode 100644 DeadlineStack/spotfleet-mgmt-ui/server/.gitignore create mode 100644 DeadlineStack/spotfleet-mgmt-ui/server/main.py create mode 100644 DeadlineStack/spotfleet-mgmt-ui/server/requirements.txt 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 @@ + + + + + + + + + + + + + React App + + + +
+ + + diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/public/manifest.json b/DeadlineStack/spotfleet-mgmt-ui/client/public/manifest.json new file mode 100644 index 0000000..080d6c7 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/public/robots.txt b/DeadlineStack/spotfleet-mgmt-ui/client/public/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/src/App.css b/DeadlineStack/spotfleet-mgmt-ui/client/src/App.css new file mode 100644 index 0000000..50b63a3 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/src/App.css @@ -0,0 +1,18 @@ +.App { + text-align: center; +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/src/App.test.tsx b/DeadlineStack/spotfleet-mgmt-ui/client/src/App.test.tsx new file mode 100644 index 0000000..2a68616 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/src/App.test.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + render(); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/src/App.tsx b/DeadlineStack/spotfleet-mgmt-ui/client/src/App.tsx new file mode 100644 index 0000000..a3a5dbe --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/src/App.tsx @@ -0,0 +1,13 @@ +import React, { useEffect } from 'react'; +import './App.css'; + +function App() { + useEffect(() => { + document.title = 'DeadLine SFMT'; + }, []); + + return ( +
+ ); +} +export default App; diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/src/index.css b/DeadlineStack/spotfleet-mgmt-ui/client/src/index.css new file mode 100644 index 0000000..ec2585e --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/src/index.tsx b/DeadlineStack/spotfleet-mgmt-ui/client/src/index.tsx new file mode 100644 index 0000000..032464f --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/src/index.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import './index.css'; +import App from './App'; +import reportWebVitals from './reportWebVitals'; + +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement +); +root.render( + + + +); + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals(); diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/src/react-app-env.d.ts b/DeadlineStack/spotfleet-mgmt-ui/client/src/react-app-env.d.ts new file mode 100644 index 0000000..6431bc5 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/src/reportWebVitals.ts b/DeadlineStack/spotfleet-mgmt-ui/client/src/reportWebVitals.ts new file mode 100644 index 0000000..49a2a16 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/src/reportWebVitals.ts @@ -0,0 +1,15 @@ +import { ReportHandler } from 'web-vitals'; + +const reportWebVitals = (onPerfEntry?: ReportHandler) => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/src/setupTests.ts b/DeadlineStack/spotfleet-mgmt-ui/client/src/setupTests.ts new file mode 100644 index 0000000..8f2609b --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/src/setupTests.ts @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; diff --git a/DeadlineStack/spotfleet-mgmt-ui/client/tsconfig.json b/DeadlineStack/spotfleet-mgmt-ui/client/tsconfig.json new file mode 100644 index 0000000..a273b0c --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/client/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": [ + "src" + ] +} diff --git a/DeadlineStack/spotfleet-mgmt-ui/server/.gitignore b/DeadlineStack/spotfleet-mgmt-ui/server/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/server/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/DeadlineStack/spotfleet-mgmt-ui/server/main.py b/DeadlineStack/spotfleet-mgmt-ui/server/main.py new file mode 100644 index 0000000..1a5d369 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/server/main.py @@ -0,0 +1,23 @@ +from fastapi import FastAPI +from fastapi.staticfiles import StaticFiles +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import HTMLResponse, FileResponse + +app = FastAPI() + + +app.add_middleware( + CORSMiddleware, + # We should specify allowed origins more restrictively in production + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +app.mount("/", StaticFiles(directory="build", html=True), name="static") + + +@app.get("/", response_class=HTMLResponse) +async def serve_client(): + return FileResponse("build/index.html") diff --git a/DeadlineStack/spotfleet-mgmt-ui/server/requirements.txt b/DeadlineStack/spotfleet-mgmt-ui/server/requirements.txt new file mode 100644 index 0000000..37aff91 --- /dev/null +++ b/DeadlineStack/spotfleet-mgmt-ui/server/requirements.txt @@ -0,0 +1,2 @@ +uvicorn==0.27.0.post1 +fastapi==0.109.2 \ No newline at end of file From b248b4144fe8c1f8b13181d125ca9ec6e578055b Mon Sep 17 00:00:00 2001 From: Clarisse Eynard Date: Fri, 23 Feb 2024 09:23:34 +0100 Subject: [PATCH 2/5] feat(python): Add ECS cluster and task to CDK --- .gitignore | 1 + DeadlineStack/package/config.py | 40 ++- DeadlineStack/package/lib/deadline_stack.py | 263 +++++++++++++------- 3 files changed, 187 insertions(+), 117 deletions(-) create mode 100644 .gitignore 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/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..f57f766 100644 --- a/DeadlineStack/package/lib/deadline_stack.py +++ b/DeadlineStack/package/lib/deadline_stack.py @@ -1,6 +1,16 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +from os import path +from aws_cdk import aws_ecs as ecs +from aws_cdk.aws_ecr import Repository as EcrRepository +from aws_cdk.aws_ecr_assets import DockerImageAsset +# from aws_cdk.aws_ecr_deployment import ( +# DockerImageName, +# Source, +# TagParameter, +# ) + from dataclasses import dataclass from aws_cdk import ( Duration, @@ -100,17 +110,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 +136,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 +183,110 @@ 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-") - ] + ] + ) + + + # Create an ECR repository + ecr_repository = EcrRepository( + self, + 'Spotfleet-Mgmt-UI-ECR-Repository', + image_scan_on_push=True, # Enable image scanning on push + removal_policy=RemovalPolicy.DESTROY # Adjust the removal policy as needed + ) + + # Create an asset from the spotfleet-mgmt-ui directory + asset = DockerImageAsset( + self, + "sfmt", + directory="./spotfleet-mgmt-ui", ) + # Deploy the asset to the ECR repository + + # ecr_repository.grant_pull_push(asset.grant_principal) + # asset.repository = ecr_repository + + # ecr_repository.on_image_scan_completed( + # "ImageScanComplete").add_target(asset) + + # docker_image_asset_hash = asset.asset_hash + # destination_image_name = f"{ecr_repository.repository_uri}:{docker_image_asset_hash}" + + # ecr_deploy = ecr_deployment.ECRDeployment( + # self, + # "EcrDeployment", + # src=ecr_deployment.DockerImageName( + # self.docker_image_asset.image_uri), + # dest=ecr_deployment.DockerImageName(destination_image_name), + # ) + + # Create an ECS cluster + ecs_cluster = ecs.Cluster( + self, + 'Spotfleet-Mgmt-UI-ECS-Cluster', + vpc=vpc + ) + + # Create an ECS task definition + # This task must run the image present in the ECR repo + + # 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 +362,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 +371,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 +456,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 +482,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 +516,3 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps ".\\deadlinecommand.exe -SetIniFileSetting ClientSSLAuthentication NotRequired", ".\\deadlinecommand.exe -SetIniFileSetting ProxyRoot renderqueue.deadline.internal:4433" ) - From 6b56f69f63a19c3b58e81538e5fdc3830bba0a1c Mon Sep 17 00:00:00 2001 From: Clarisse Eynard Date: Fri, 23 Feb 2024 18:11:19 +0100 Subject: [PATCH 3/5] feat(ecs): Add ECS cluster and task to CDK --- DeadlineStack/package/lib/deadline_stack.py | 84 +++++++++++---------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/DeadlineStack/package/lib/deadline_stack.py b/DeadlineStack/package/lib/deadline_stack.py index f57f766..6f49b93 100644 --- a/DeadlineStack/package/lib/deadline_stack.py +++ b/DeadlineStack/package/lib/deadline_stack.py @@ -1,15 +1,9 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -from os import path from aws_cdk import aws_ecs as ecs from aws_cdk.aws_ecr import Repository as EcrRepository from aws_cdk.aws_ecr_assets import DockerImageAsset -# from aws_cdk.aws_ecr_deployment import ( -# DockerImageName, -# Source, -# TagParameter, -# ) from dataclasses import dataclass from aws_cdk import ( @@ -20,8 +14,6 @@ Tags, ) from aws_cdk.aws_ec2 import ( - CfnRoute, - CfnVPCPeeringConnection, IMachineImage, Instance, InstanceClass, @@ -50,12 +42,6 @@ PrivateHostedZone, ) -from aws_cdk.aws_route53resolver import ( - CfnResolverEndpoint, - CfnResolverRule, - CfnResolverRuleAssociation, -) - from aws_cdk.aws_s3 import ( Bucket, ) @@ -203,52 +189,72 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps name="render-") ] ) - + + #### Sfmt #### # Create an ECR repository ecr_repository = EcrRepository( self, - 'Spotfleet-Mgmt-UI-ECR-Repository', - image_scan_on_push=True, # Enable image scanning on push - removal_policy=RemovalPolicy.DESTROY # Adjust the removal policy as needed + 'Spotfleet-Mgmt-UI-ECR', + repository_name='spotfleet-mgmt-ui', ) # Create an asset from the spotfleet-mgmt-ui directory asset = DockerImageAsset( self, - "sfmt", + "sfmt-image", directory="./spotfleet-mgmt-ui", ) - # Deploy the asset to the ECR repository - - # ecr_repository.grant_pull_push(asset.grant_principal) - # asset.repository = ecr_repository - - # ecr_repository.on_image_scan_completed( - # "ImageScanComplete").add_target(asset) - - # docker_image_asset_hash = asset.asset_hash - # destination_image_name = f"{ecr_repository.repository_uri}:{docker_image_asset_hash}" - - # ecr_deploy = ecr_deployment.ECRDeployment( - # self, - # "EcrDeployment", - # src=ecr_deployment.DockerImageName( - # self.docker_image_asset.image_uri), - # dest=ecr_deployment.DockerImageName(destination_image_name), - # ) - # 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') + ] + ) + # Create an ECS task definition - # This task must run the image present in the ECR repo + task_definition = ecs.FargateTaskDefinition( + self, "run-sfmt-ui", + task_role=ecs_task_role, + execution_role=ecs_task_execution_role, + ) + container = task_definition.add_container( + "sfmf-ui-container", + image=ecs.ContainerImage.from_ecr_repository( + ecr_repository, asset.image_uri), + ) + #### Sfmt end #### # security group for resolver endpoint worker_resolver_endpoint_sg = SecurityGroup( From 0523a00ead111961786fde10b91e09fe0df57111 Mon Sep 17 00:00:00 2001 From: Clarisse Eynard Date: Mon, 26 Feb 2024 12:38:47 +0100 Subject: [PATCH 4/5] feat(ecs): add a shell script to deploy ECR repo and push Docker image to it. --- DeadlineStack/README.md | 10 +++- DeadlineStack/deploy_spotfleet_mgmt_ui.sh | 52 +++++++++++++++++++++ DeadlineStack/package/lib/deadline_stack.py | 25 ++++------ 3 files changed, 68 insertions(+), 19 deletions(-) create mode 100755 DeadlineStack/deploy_spotfleet_mgmt_ui.sh 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/lib/deadline_stack.py b/DeadlineStack/package/lib/deadline_stack.py index 6f49b93..6d116b2 100644 --- a/DeadlineStack/package/lib/deadline_stack.py +++ b/DeadlineStack/package/lib/deadline_stack.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 from aws_cdk import aws_ecs as ecs -from aws_cdk.aws_ecr import Repository as EcrRepository +from aws_cdk import aws_ecr as ecr from aws_cdk.aws_ecr_assets import DockerImageAsset from dataclasses import dataclass @@ -192,20 +192,6 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps #### Sfmt #### - # Create an ECR repository - ecr_repository = EcrRepository( - self, - 'Spotfleet-Mgmt-UI-ECR', - repository_name='spotfleet-mgmt-ui', - ) - - # Create an asset from the spotfleet-mgmt-ui directory - asset = DockerImageAsset( - self, - "sfmt-image", - directory="./spotfleet-mgmt-ui", - ) - # Create an ECS cluster ecs_cluster = ecs.Cluster( self, @@ -242,6 +228,10 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps ] ) + # 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", @@ -249,9 +239,10 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps execution_role=ecs_task_execution_role, ) container = task_definition.add_container( - "sfmf-ui-container", + "sfmt-ui-container", image=ecs.ContainerImage.from_ecr_repository( - ecr_repository, asset.image_uri), + ecr_repository, + "latest"), ) #### Sfmt end #### From 9c844ca38036b8d422116997eb0c5bd8379b3114 Mon Sep 17 00:00:00 2001 From: Clarisse Eynard Date: Tue, 27 Feb 2024 16:17:33 +0100 Subject: [PATCH 5/5] feature(cdk): create new security group for the task definition --- DeadlineStack/package/lib/deadline_stack.py | 43 +++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/DeadlineStack/package/lib/deadline_stack.py b/DeadlineStack/package/lib/deadline_stack.py index 6d116b2..2222f65 100644 --- a/DeadlineStack/package/lib/deadline_stack.py +++ b/DeadlineStack/package/lib/deadline_stack.py @@ -4,6 +4,7 @@ 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 ( @@ -214,6 +215,7 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps 'service-role/AmazonECSTaskExecutionRolePolicy') ] ) + # Create task execution IAM role ecs_task_execution_role = Role( self, @@ -244,6 +246,47 @@ def __init__(self, scope: Construct, stack_id: str, *, props: DeadlineStackProps 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 ####