Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion services/post-service/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ require (
github.com/cs6650/proto v0.0.0-00010101000000-000000000000
github.com/gin-gonic/gin v1.11.0
google.golang.org/grpc v1.76.0
google.golang.org/protobuf v1.36.10
)

replace github.com/cs6650/proto => ../../proto
Expand Down Expand Up @@ -61,4 +60,5 @@ require (
golang.org/x/text v0.27.0 // indirect
golang.org/x/tools v0.34.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
google.golang.org/protobuf v1.36.10 // indirect
)
31 changes: 23 additions & 8 deletions services/post-service/internal/repository/post_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,40 @@ func NewPostRepository(client *dynamodb.Client, tableName string) *PostRepositor

// Create a new post and save to dynamodb
func(r *PostRepository) CreatePost(ctx context.Context, post *pb.Post) error {
item, err := attributevalue.MarshalMap(post)
if err != nil {
return fmt.Errorf("failed to marshal post: %w", err)
// Manually create DynamoDB item with correct field names (post_id, user_id, etc.)
item := map[string]types.AttributeValue{
"post_id": &types.AttributeValueMemberS{
Value: fmt.Sprintf("%d", post.PostId),
},
"user_id": &types.AttributeValueMemberN{
Value: fmt.Sprintf("%d", post.UserId),
},
"content": &types.AttributeValueMemberS{
Value: post.Content,
},
"timestamp": &types.AttributeValueMemberN{
Value: fmt.Sprintf("%d", post.Timestamp),
},
}

_, err = r.client.PutItem(ctx, &dynamodb.PutItemInput{
_, err := r.client.PutItem(ctx, &dynamodb.PutItemInput{
TableName: aws.String(r.tableName),
Item: item,
Item: item,
})

return err
if err != nil {
return fmt.Errorf("failed to create post: %w", err)
}

return nil
}

// Retrieves a single post by PostID
func(r *PostRepository)GetPost(ctx context.Context, postID int64)(*pb.Post, error) {
result, err := r.client.GetItem(ctx, &dynamodb.GetItemInput{
TableName: aws.String(r.tableName),
Key: map[string]types.AttributeValue{
"post_id": &types.AttributeValueMemberN{
"post_id": &types.AttributeValueMemberS{
Value: fmt.Sprintf("%d", postID),
},
},
Expand Down
6 changes: 5 additions & 1 deletion services/post-service/terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ locals {
# Configure DynamoDB tables
module "dynamodb" {
source = "./modules/dynamodb"

table_name = var.dynamo_table
environment = var.environment
}

# Service-specific security group for ECS tasks
Expand Down Expand Up @@ -134,6 +137,7 @@ module "ecs" {
subnet_ids = var.public_subnet_ids
security_group_ids = [aws_security_group.app.id]
execution_role_arn = var.execution_role_arn
task_role_arn = var.task_role_arn # Task role for DynamoDB/SNS access
log_group_name = module.logging.log_group_name
target_group_arn = aws_lb_target_group.service.arn
ecs_count = var.ecs_count
Expand All @@ -152,7 +156,7 @@ module "ecs" {
},
{
name = "DYNAMO_TABLE"
value = var.dynamo_table
value = module.dynamodb.table_name
},
{
name = "POST_STRATEGY"
Expand Down
1 change: 1 addition & 0 deletions services/post-service/terraform/modules/ecs/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ resource "aws_ecs_task_definition" "app" {
cpu = var.cpu
memory = var.memory
execution_role_arn = var.execution_role_arn
task_role_arn = var.task_role_arn != "" ? var.task_role_arn : var.execution_role_arn # Use task_role if provided

# Specify CPU architecture for Fargate
runtime_platform {
Expand Down
6 changes: 6 additions & 0 deletions services/post-service/terraform/modules/ecs/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ variable "execution_role_arn" {
description = "ECS Task Execution Role ARN (Innovation Sandbox with ISBStudent=true tag)"
}

variable "task_role_arn" {
type = string
description = "ECS Task Role ARN for application permissions (DynamoDB, SNS)"
default = ""
}

variable "log_group_name" {
type = string
description = "CloudWatch log group name"
Expand Down
6 changes: 6 additions & 0 deletions services/post-service/terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ variable "execution_role_arn" {
type = string
}

variable "task_role_arn" {
description = "ARN of the ECS task role for application permissions"
type = string
default = ""
}

# ALB settings
variable "alb_priority" {
description = "Priority for ALB listener rule"
Expand Down
1 change: 1 addition & 0 deletions terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ module "post_service" {

# IAM role for ECS tasks
execution_role_arn = module.iam.ecs_task_execution_role_arn
task_role_arn = module.iam.post_service_task_role_arn

# Pass through necessary variables
aws_region = var.aws_region
Expand Down
36 changes: 35 additions & 1 deletion terraform/modules/iam/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,41 @@ resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

# Post Service Task Role (for DynamoDB and SNS access)
resource "aws_iam_role" "post_service_task_role" {
name = "${var.project_name}-${var.environment}-post-task-role"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
}
]
})

tags = {
Name = "${var.project_name}-${var.environment}-post-task-role"
Environment = var.environment
ISBStudent = "true" # Required for Innovation Sandbox IAM role creation
}
}

# Attach AWS managed policies for DynamoDB and SNS
resource "aws_iam_role_policy_attachment" "post_dynamodb" {
role = aws_iam_role.post_service_task_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"
}

resource "aws_iam_role_policy_attachment" "post_sns" {
role = aws_iam_role.post_service_task_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSNSFullAccess"
}

# Timeline Service Task Role (for DynamoDB and SQS access)
resource "aws_iam_role" "timeline_service_task_role" {
name = "${var.project_name}-${var.environment}-timeline-task-role"
Expand All @@ -52,7 +87,6 @@ resource "aws_iam_role" "timeline_service_task_role" {
}
}

# Attach AWS managed policies for DynamoDB and SQS
resource "aws_iam_role_policy_attachment" "timeline_dynamodb" {
role = aws_iam_role.timeline_service_task_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"
Expand Down
5 changes: 5 additions & 0 deletions terraform/modules/iam/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ output "ecs_task_execution_role_arn" {
value = aws_iam_role.ecs_task_execution_role.arn
}

output "post_service_task_role_arn" {
description = "ARN of the post service task role"
value = aws_iam_role.post_service_task_role.arn
}

output "timeline_service_task_role_arn" {
description = "ARN of the timeline service task role"
value = aws_iam_role.timeline_service_task_role.arn
Expand Down
2 changes: 1 addition & 1 deletion terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ variable "post_service_ecs_count" {
variable "post_service_post_strategy" {
description = "Post strategy: push, pull, or hybrid"
type = string
default = "hybrid"
default = "pull"
}


Expand Down