-
Notifications
You must be signed in to change notification settings - Fork 0
feature/fix course save 500 error #190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b0e895e
b5cf9cb
ea7e7a2
de2057e
14e835e
5b7dd0e
c7b50f8
3f0562f
8bc5548
d4bb581
f9c5f26
489a82c
25cb31b
9fb4342
d1f4a02
fe6a721
d3052de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,18 +2,18 @@ version: 0.0 | |
| os: linux | ||
|
|
||
| files: | ||
| - source: / | ||
| destination: /home/ubuntu/app | ||
| - source: / | ||
| destination: /home/ec2-user/app | ||
| overwrite: yes | ||
|
|
||
| permissions: | ||
| - object: / | ||
| pattern: "**" | ||
| owner: ubuntu | ||
| group: ubuntu | ||
| owner: ec2-user | ||
| group: ec2-user | ||
|
Comment on lines
9
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: The AWS CodeDeploy appspec.yml permissions section uses a list of object configurations for EC2/On-Premises deployments. Each object is defined as: permissions: - object: /path/to/target pattern: "" # Optional; "" applies recursively to all matching items except: [] # Optional; list of exceptions (no path separators) owner: username group: groupname mode: 755 # Octal mode like chmod type: - directory # or 'file'; 'directory' with "" recurses into subdirectories # Optional: acls, context (SELinux) Key recursive patterns: - pattern: "" matches everything recursively under object. - type: directory with pattern "" recursively applies permissions to all directories anywhere in the object (not object itself). - Multiple objects can target different levels for fine control (e.g., one for top-level files, one for recursive subdirs). - Permissions applied after files are copied during Install event. Examples from docs: permissions: - object: /tmp/my-app pattern: "" owner: ec2-user mode: 777 type: directory # Recurses all subdirectories - object: /tmp/my-app pattern: "*-3.txt" owner: adm mode: 464 type: file This structure allows recursive permission setting via "" pattern + directory type. For complex cases, use multiple entries or hooks scripts. Citations:
🌐 Web query:
💡 Result: In AWS CodeDeploy's AppSpec.yml file, the permissions section uses glob-style pattern matching with support for asterisk () wildcards and for recursive matching. Key syntax from official AWS documentation: - pattern: Optional string specifying a glob pattern to apply permissions to files/directories matching the object. - "" matches files in the current directory. - "" (special case): If pattern is not specified or set to "", permissions apply to ALL matching files/directories under the object (recursive). - Examples: - pattern: "" → Applies to everything under object (recursive, excludes except patterns). - pattern: ".txt" → Matches all .txt files. - pattern: "/.txt" → Matches all .txt files recursively. - except: ["/path/to/exclude.txt", "*.log"] → Comma-separated list in brackets to exclude specific patterns. Full structure: permissions: - object: /path/to/target pattern: "" except: ["/ReadMe.txt"] owner: bob group: writers mode: 644 type: - file - directory This applies to EC2/On-Premises deployments only (Amazon Linux, Ubuntu, RHEL). Patterns follow standard shell glob syntax with for recursion. Use hooks for complex chmod if needed. Citations:
🌐 Web query:
💡 Result: In CodeDeploy EC2/On-Premises AppSpec permissions, there’s no special meaning for setting pattern to an empty string "". The official behavior is described in terms of whether pattern is provided or not, and whether it’s set to the special glob "". 1) pattern is omitted OR pattern is "" - If the permissions entry’s pattern is not specified, OR it is specified with "", CodeDeploy applies the permissions to all matching files/directories (depending on type: file vs directory). 2) pattern = "" (empty string) - The AWS docs for the permissions pattern field do not define empty-string semantics. So you should not rely on pattern: "" to mean “apply to everything”. - Treat pattern: "" as effectively “no valid glob”, and instead use the documented forms: - omit pattern entirely, or - use pattern: "". Practical guidance - To apply permissions recursively across the object subtree: - use pattern: "" and type: [file] or type: [directory] as needed. - To target only immediate children without recursion: - use type: file or directory with pattern omitted or with a narrower glob (for example, "*.txt"). Note: This is for the EC2/On-Premises AppSpec permissions section only; other AppSpec sections (for ECS/Lambda) are different. Citations:
🌐 Web query:
💡 Result: In CodeDeploy EC2/On-Premises AppSpec files, the permissions section supports a pattern field where "" means “match recursively” (apply permissions to all matching files/directories within the object, including in nested subdirectories). What the docs say (permissions.pattern): - The permissions section applies special permissions after CodeDeploy copies files (EC2/On-Premises only). - pattern is optional. If pattern is not specified or is specified as "", the permissions are applied to all matching files or directories depending on the object type. - type controls whether permissions are applied to files or recursively to directories anywhere under the object. Example from the AWS docs (pattern: ""): - object: /tmp/my-app/my-folder-1 pattern: "" type: - file (and except can be used to exclude specific paths) So, if you set: - permissions: - object: /var/www/APPLICATION_NAME/tmpfiles pattern: "" type: - file …the agent will apply the specified owner/mode (and acls/context, if provided) to all files under /var/www/APPLICATION_NAME/tmpfiles (recursively), and you can use except to exclude specific files. Note: This permissions.pattern/apply-recursively behavior is for EC2/On-Premises deployments; it is not used for AWS Lambda or Amazon ECS deployments. Citations: 🌐 Web query:
💡 Result: Yes, the double asterisk ( ) syntax is valid in the 'pattern' field of the AWS CodeDeploy AppSpec file's 'permissions' section for EC2/On-Premises deployments. It is a special glob pattern that matches all files and directories recursively under the specified 'object'. Official AWS documentation explicitly states: "If not specified or specified with the special characters '', the permissions are applied to all matching files or directories, depending on the 'type'." Multiple examples use pattern: "", such as: - object: /tmp/my-app/my-folder-1 pattern: "" except: [my-file-4.txt, my-file-5.txt] ... - object: /var/www/html/WordPress pattern: "" except: [/var/www/html/WordPress/ReadMe.txt] ... This applies during the Install lifecycle event after files are copied to the instance, for Amazon Linux, Ubuntu, and RHEL instances. Note: This is specific to the AppSpec 'permissions' pattern field, not IAM policies for CodeDeploy (which use single * wildcards in ARNs). Citations:
🌐 Web query:
💡 Result: AWS CodeDeploy security best practices for permissions focus on two main areas: IAM roles with least privilege and AppSpec file permissions for deployed files, plus securing the agent deployment-root directory. Avoid broad root filesystem access. IAM Permissions (Service Role and Instance Profile): - Use AWS managed policies like AWSCodeDeployRole for the service role (least privilege for EC2/On-Premises). Attach to allow CodeDeploy to manage instances, Auto Scaling, ELB, SNS, etc., without excessive perms. - For EC2 instances, use an IAM instance profile with minimal S3 read access to deployment buckets (e.g., AmazonEC2RoleforAWSCodeDeploy). - Limit user/deployer policies to specific CodeDeploy actions and pass-role for service role. Avoid "*" resources where possible; use ARNs. AppSpec 'permissions' Section (EC2/On-Premises only): - Define precise file/directory permissions post-deployment using owner, group, mode (e.g., 755 for dirs, 644 for files), ACLs, SELinux contexts. - Target specific objects (e.g., /var/www/myapp), use patterns/except for scope. Do not apply to entire root (/); scope to deployment paths only. Example: permissions: - object: /var/www/myapp owner: www-data group: www-data mode: 755 type: directory - object: /var/www/myapp/src mode: 644 type: file Agent Deployment-Root (/opt/codedeploy-agent/deployment-root): - Stores revisions/logs; configurable via :root_dir. - Best practice: Run agent as non-root user (e.g., ec2-user). Chown the directory to that user. - Limit retained revisions (:max_revisions: 5 default) to control disk usage. - Secure directory perms (e.g., 700 owned by agent user) to prevent unauthorized access. General: Follow IAM least-privilege, use conditions/MFA, enable CloudTrail. No sources recommend root filesystem perms; always scope narrowly to prevent over-privileging. Citations:
Scope the In CodeDeploy, Suggested fix permissions:
- - object: /
+ - object: /home/ec2-user/app
pattern: "**"
owner: ec2-user
group: ec2-user🤖 Prompt for AI Agents |
||
|
|
||
| hooks: | ||
| AfterInstall: | ||
| - location: deploy.sh | ||
| timeout: 300 | ||
| runas: ubuntu | ||
| runas: ec2-user | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,96 +1,45 @@ | ||||||||||||||||||||||||
| #!/bin/bash | ||||||||||||||||||||||||
| BUILD_PATH=$(ls /home/ubuntu/app/server-0.0.1-SNAPSHOT.jar) | ||||||||||||||||||||||||
| JAR_NAME=$(basename $BUILD_PATH) | ||||||||||||||||||||||||
| echo "> build 파일명: $JAR_NAME" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "> build 파일 복사" | ||||||||||||||||||||||||
| DEPLOY_PATH=/home/ubuntu/app/nonstop/jar/ | ||||||||||||||||||||||||
| cp $BUILD_PATH $DEPLOY_PATH | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "> 현재 구동중인 Set 확인" | ||||||||||||||||||||||||
| CURRENT_PROFILE=$(curl -s http://localhost/profile) | ||||||||||||||||||||||||
| echo "> $CURRENT_PROFILE" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # 쉬고 있는 set 찾기: set1이 사용중이면 set2가 쉬고 있고, 반대면 set1이 쉬고 있음 | ||||||||||||||||||||||||
| if [ $CURRENT_PROFILE == set1 ] | ||||||||||||||||||||||||
| then | ||||||||||||||||||||||||
| IDLE_PROFILE=set2 | ||||||||||||||||||||||||
| IDLE_PORT=8082 | ||||||||||||||||||||||||
| elif [ $CURRENT_PROFILE == set2 ] | ||||||||||||||||||||||||
| then | ||||||||||||||||||||||||
| IDLE_PROFILE=set1 | ||||||||||||||||||||||||
| IDLE_PORT=8081 | ||||||||||||||||||||||||
| set -e | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| APP_DIR=/home/ec2-user/app | ||||||||||||||||||||||||
| JAR_PATH=$(ls $APP_DIR/*.jar | grep -v plain | head -1) | ||||||||||||||||||||||||
| echo "> JAR 파일: $JAR_PATH" | ||||||||||||||||||||||||
|
Comment on lines
+4
to
+6
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don’t pick the first matching JAR. Line 5 is nondeterministic and fails opaquely when no non-plain JAR exists. Because Suggested fix APP_DIR=/home/ec2-user/app
-JAR_PATH=$(ls $APP_DIR/*.jar | grep -v plain | head -1)
+mapfile -t JARS < <(find "$APP_DIR" -maxdepth 1 -type f -name '*.jar' ! -name '*plain*.jar' | sort)
+if [ "${`#JARS`[@]}" -ne 1 ]; then
+ echo "> deployable JAR count mismatch: ${`#JARS`[@]}"
+ exit 1
+fi
+JAR_PATH="${JARS[0]}"
echo "> JAR 파일: $JAR_PATH"📝 Committable suggestion
Suggested change
🧰 Tools🪛 Shellcheck (0.11.0)[warning] 5-5: Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames. (SC2010) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "> 실행 중인 애플리케이션 종료" | ||||||||||||||||||||||||
| CURRENT_PID=$(pgrep -f '\.jar' || true) | ||||||||||||||||||||||||
| if [ -n "$CURRENT_PID" ]; then | ||||||||||||||||||||||||
| echo "> 종료: $CURRENT_PID" | ||||||||||||||||||||||||
| kill -15 $CURRENT_PID | ||||||||||||||||||||||||
| sleep 5 | ||||||||||||||||||||||||
|
Comment on lines
+8
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Narrow the process match before killing. Line 9 matches every Suggested fix-CURRENT_PID=$(pgrep -f '\.jar' || true)
+CURRENT_PID=$(pgrep -f "$APP_DIR/.*\.jar" || true)🧰 Tools🪛 Shellcheck (0.11.0)[info] 12-12: Double quote to prevent globbing and word splitting. (SC2086) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||
| else | ||||||||||||||||||||||||
| echo "> 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE" | ||||||||||||||||||||||||
| echo "> set1을 할당합니다. IDLE_PROFILE: set1" | ||||||||||||||||||||||||
| IDLE_PROFILE=set1 | ||||||||||||||||||||||||
| IDLE_PORT=8081 | ||||||||||||||||||||||||
| echo "> 실행 중인 애플리케이션 없음" | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "> application.jar 교체" | ||||||||||||||||||||||||
| IDLE_APPLICATION=$IDLE_PROFILE-Runnect-Spring-Boot-Server.jar | ||||||||||||||||||||||||
| IDLE_APPLICATION_PATH=$DEPLOY_PATH$IDLE_APPLICATION | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| ln -Tfs $DEPLOY_PATH$JAR_NAME $IDLE_APPLICATION_PATH | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "> $IDLE_PROFILE 에서 구동중인 애플리케이션 pid 확인" | ||||||||||||||||||||||||
| IDLE_PID=$(pgrep -f $IDLE_APPLICATION) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if [ -z $IDLE_PID ] | ||||||||||||||||||||||||
| then | ||||||||||||||||||||||||
| echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다." | ||||||||||||||||||||||||
| else | ||||||||||||||||||||||||
| echo "> kill -15 $IDLE_PID" | ||||||||||||||||||||||||
| kill -15 $IDLE_PID | ||||||||||||||||||||||||
| sleep 20 | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
| echo "> 애플리케이션 시작" | ||||||||||||||||||||||||
| nohup java -jar \ | ||||||||||||||||||||||||
| -Duser.timezone=Asia/Seoul \ | ||||||||||||||||||||||||
| $JAR_PATH \ | ||||||||||||||||||||||||
|
Comment on lines
+19
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n scripts/deploy.sh | head -30Repository: Runnect/Runnect-Spring-Boot-Server Length of output: 934 Move The Java launcher syntax is Suggested fix-nohup java -jar \
- -Duser.timezone=Asia/Seoul \
- $JAR_PATH \
+nohup java \
+ -Duser.timezone=Asia/Seoul \
+ -jar "$JAR_PATH" \
>> /home/ec2-user/app/nohup.out 2>&1 &📝 Committable suggestion
Suggested change
🧰 Tools🪛 Shellcheck (0.11.0)[info] 21-21: Double quote to prevent globbing and word splitting. (SC2086) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||
| >> /home/ec2-user/app/nohup.out 2>&1 & | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "> $IDLE_PROFILE 배포" | ||||||||||||||||||||||||
| nohup java -jar -Duser.timezone=Asia/Seoul -Dspring.profiles.active=$IDLE_PROFILE $IDLE_APPLICATION_PATH >> /home/ubuntu/app/nohup.out 2>&1 & | ||||||||||||||||||||||||
| echo "> 15초 후 헬스체크 시작" | ||||||||||||||||||||||||
| sleep 15 | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "> $IDLE_PROFILE 10초 후 Health check 시작" | ||||||||||||||||||||||||
| echo "> curl -s http://localhost:$IDLE_PORT/health " | ||||||||||||||||||||||||
| sleep 10 | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| for retry_count in {1..10} | ||||||||||||||||||||||||
| do | ||||||||||||||||||||||||
| response=$(curl -s http://localhost:$IDLE_PORT/actuator/health) | ||||||||||||||||||||||||
| up_count=$(echo $response | grep 'UP' | wc -l) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if [ $up_count -ge 1 ] | ||||||||||||||||||||||||
| then # $up_count >= 1 ("UP" 문자열이 있는지 검증) | ||||||||||||||||||||||||
| echo "> Health check 성공" | ||||||||||||||||||||||||
| break | ||||||||||||||||||||||||
| else | ||||||||||||||||||||||||
| echo "> Health check의 응답을 알 수 없거나 혹은 status가 UP이 아닙니다." | ||||||||||||||||||||||||
| echo "> Health check: ${response}" | ||||||||||||||||||||||||
| for i in {1..10}; do | ||||||||||||||||||||||||
| RESPONSE=$(curl -s http://localhost:8080/actuator/health || true) | ||||||||||||||||||||||||
| if echo "$RESPONSE" | grep -q '"status":"UP"'; then | ||||||||||||||||||||||||
| echo "> 헬스체크 성공" | ||||||||||||||||||||||||
| break | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if [ $retry_count -eq 10 ] | ||||||||||||||||||||||||
| then | ||||||||||||||||||||||||
| echo "> Health check 실패. " | ||||||||||||||||||||||||
| echo "> Nginx에 연결하지 않고 배포를 종료합니다." | ||||||||||||||||||||||||
| echo "> 헬스체크 실패($i/10): $RESPONSE" | ||||||||||||||||||||||||
| if [ $i -eq 10 ]; then | ||||||||||||||||||||||||
| echo "> 배포 실패" | ||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "> Health check 연결 실패. 재시도..." | ||||||||||||||||||||||||
| sleep 10 | ||||||||||||||||||||||||
| done | ||||||||||||||||||||||||
|
Comment on lines
+12
to
39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait for the old PID to exit and track the new one. The fixed 🧰 Tools🪛 Shellcheck (0.11.0)[info] 12-12: Double quote to prevent globbing and word splitting. (SC2086) [info] 21-21: Double quote to prevent globbing and word splitting. (SC2086) [info] 34-34: Double quote to prevent globbing and word splitting. (SC2086) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "> Nginx 상태 확인" | ||||||||||||||||||||||||
| if ! sudo systemctl is-active --quiet nginx; then | ||||||||||||||||||||||||
| echo "> Nginx가 중지되어 있습니다. 재시작합니다." | ||||||||||||||||||||||||
| sudo systemctl start nginx | ||||||||||||||||||||||||
| sleep 2 | ||||||||||||||||||||||||
| if sudo systemctl is-active --quiet nginx; then | ||||||||||||||||||||||||
| echo "> Nginx 재시작 성공" | ||||||||||||||||||||||||
| else | ||||||||||||||||||||||||
| echo "> Nginx 재시작 실패." | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
| else | ||||||||||||||||||||||||
| echo "> Nginx 정상 구동 중" | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
| echo "> Nginx 시작" | ||||||||||||||||||||||||
| sudo systemctl start nginx || true | ||||||||||||||||||||||||
| sudo systemctl enable nginx || true | ||||||||||||||||||||||||
|
Comment on lines
+41
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don’t mask nginx startup failures.
🤖 Prompt for AI Agents |
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "> 스위칭" | ||||||||||||||||||||||||
| sleep 10 | ||||||||||||||||||||||||
| /home/ubuntu/app/nonstop/switch.sh | ||||||||||||||||||||||||
| echo "> 배포 완료" | ||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep some automated test coverage in this PR workflow.
Line 44 now publishes a green build from completely untested code, so regressions can merge unnoticed. A safer fix is to split DB-bound tests behind a separate task/profile and keep unit tests enabled here.
🤖 Prompt for AI Agents