Skip to content

Commit 8e745ee

Browse files
committed
Add middleware, update README, update Makefile, and fix issue with JWT principal parsing
Signed-off-by: Andres Tobon <andrest2455@gmail.com>
1 parent 802f7e0 commit 8e745ee

File tree

26 files changed

+787
-167
lines changed

26 files changed

+787
-167
lines changed

charts/lfx-v2-project-service/values.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
---
44
# ingress is the configuration for the ingress routing
55
ingress:
6+
# hostname is the hostname of the ingress
67
hostname: lfx-api.k8s.orb.local
78

89
# nats is the configuration for the NATS server

cmd/project-api/Makefile

Lines changed: 158 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,169 @@
11
# Copyright The Linux Foundation and each contributor to LFX.
22
# SPDX-License-Identifier: MIT
3-
.PHONY: deps apigen build run debug test
43

5-
# Install the goa CLI tool.
4+
# Variables
5+
BINARY_NAME=project-api
6+
BINARY_PATH=bin/$(BINARY_NAME)
7+
GO_MODULE=github.com/linuxfoundation/lfx-v2-project-service
8+
CMD_PATH=$(GO_MODULE)/cmd/project-api
9+
DESIGN_MODULE=$(CMD_PATH)/design
10+
GO_FILES=$(shell find . -name '*.go' -not -path './gen/*' -not -path './vendor/*')
11+
GOA_VERSION=v3
12+
13+
# Docker variables
14+
DOCKER_IMAGE=linuxfoundation/lfx-v2-project-service
15+
DOCKER_TAG=0.1.0
16+
17+
# Helm variables
18+
HELM_CHART_PATH=../../charts/lfx-v2-project-service
19+
HELM_RELEASE_NAME=lfx-v2-project-service
20+
HELM_NAMESPACE=lfx
21+
22+
# Build variables
23+
BUILD_TIME=$(shell date -u '+%Y-%m-%d_%H:%M:%S')
24+
GIT_COMMIT=$(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
25+
VERSION=$(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
26+
LDFLAGS=-ldflags "-X main.Version=$(VERSION) -X main.BuildTime=$(BUILD_TIME) -X main.GitCommit=$(GIT_COMMIT)"
27+
28+
# Test variables
29+
TEST_FLAGS=-v -race -cover
30+
TEST_TIMEOUT=5m
31+
32+
.PHONY: all help deps apigen build run debug test test-verbose test-coverage clean lint fmt check verify docker helm-install helm-uninstall
33+
34+
# Default target
35+
all: clean deps apigen fmt lint test build
36+
37+
# Help target
38+
help:
39+
@echo "Available targets:"
40+
@echo " all - Run clean, deps, apigen, fmt, lint, test, and build"
41+
@echo " deps - Install dependencies including goa CLI"
42+
@echo " apigen - Generate API code from design files"
43+
@echo " build - Build the binary"
44+
@echo " run - Run the service"
45+
@echo " debug - Run the service with debug logging"
46+
@echo " test - Run unit tests"
47+
@echo " test-verbose - Run tests with verbose output"
48+
@echo " test-coverage - Run tests with coverage report"
49+
@echo " clean - Remove generated files and binaries"
50+
@echo " lint - Run golangci-lint"
51+
@echo " fmt - Format Go code"
52+
@echo " check - Run fmt and lint without modifying files"
53+
@echo " verify - Verify API generation is up to date"
54+
@echo " docker - Build Docker image"
55+
@echo " helm-install - Install Helm chart"
56+
@echo " helm-uninstall - Uninstall Helm chart"
57+
58+
# Install dependencies
659
deps:
7-
go install goa.design/goa/v3/cmd/goa@latest
60+
@echo "==> Installing dependencies..."
61+
go mod download
62+
go install goa.design/goa/$(GOA_VERSION)/cmd/goa@latest
63+
@command -v golangci-lint >/dev/null 2>&1 || { \
64+
echo "==> Installing golangci-lint..."; \
65+
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest; \
66+
}
867

9-
# Generate the API code from the design files.
68+
# Generate API code from design files
1069
apigen: deps
11-
goa gen github.com/linuxfoundation/lfx-v2-project-service/cmd/project-api/design
70+
@echo "==> Generating API code..."
71+
goa gen $(DESIGN_MODULE)
72+
@echo "==> API generation complete"
1273

13-
# Build the go program to ensure there aren't any build errors.
14-
build:
15-
go build -o bin/project-api .
74+
# Build the binary
75+
build: clean
76+
@echo "==> Building $(BINARY_NAME)..."
77+
@mkdir -p bin
78+
go build $(LDFLAGS) -o $(BINARY_PATH) .
79+
@echo "==> Build complete: $(BINARY_PATH)"
1680

17-
# Run the service.
18-
run:
19-
go run .
81+
# Run the service
82+
run: apigen
83+
@echo "==> Running $(BINARY_NAME)..."
84+
go run $(LDFLAGS) .
2085

21-
# Run the service with debug logging.
22-
debug:
23-
go run . -d
86+
# Run with debug logging
87+
debug: apigen
88+
@echo "==> Running $(BINARY_NAME) in debug mode..."
89+
go run $(LDFLAGS) . -d
2490

25-
# Run the unit tests.
91+
# Run tests
2692
test:
27-
go test .
93+
@echo "==> Running tests..."
94+
go test $(TEST_FLAGS) -timeout $(TEST_TIMEOUT) ./...
95+
96+
# Run tests with verbose output
97+
test-verbose:
98+
@echo "==> Running tests (verbose)..."
99+
go test $(TEST_FLAGS) -v -timeout $(TEST_TIMEOUT) ./...
100+
101+
# Run tests with coverage
102+
test-coverage:
103+
@echo "==> Running tests with coverage..."
104+
@mkdir -p coverage
105+
go test $(TEST_FLAGS) -timeout $(TEST_TIMEOUT) -coverprofile=coverage/coverage.out ./...
106+
go tool cover -html=coverage/coverage.out -o coverage/coverage.html
107+
@echo "==> Coverage report: coverage/coverage.html"
108+
109+
# Clean build artifacts
110+
clean:
111+
@echo "==> Cleaning build artifacts..."
112+
@rm -rf bin/ coverage/
113+
@go clean -cache
114+
@echo "==> Clean complete"
115+
116+
# Run linter
117+
lint:
118+
@echo "==> Running linter..."
119+
@if command -v golangci-lint >/dev/null 2>&1; then \
120+
golangci-lint run ./...; \
121+
else \
122+
echo "golangci-lint not found. Run 'make deps' to install it."; \
123+
exit 1; \
124+
fi
125+
126+
# Format code
127+
fmt:
128+
@echo "==> Formatting code..."
129+
@go fmt ./...
130+
@gofmt -s -w $(GO_FILES)
131+
132+
# Check formatting and linting without modifying files
133+
check:
134+
@echo "==> Checking code format..."
135+
@if [ -n "$$(gofmt -l $(GO_FILES))" ]; then \
136+
echo "The following files need formatting:"; \
137+
gofmt -l $(GO_FILES); \
138+
exit 1; \
139+
fi
140+
@echo "==> Code format check passed"
141+
@$(MAKE) lint
142+
143+
# Verify that generated code is up to date
144+
verify: apigen
145+
@echo "==> Verifying generated code is up to date..."
146+
@if [ -n "$$(git status --porcelain gen/)" ]; then \
147+
echo "Generated code is out of date. Run 'make apigen' and commit the changes."; \
148+
git status --porcelain gen/; \
149+
exit 1; \
150+
fi
151+
@echo "==> Generated code is up to date"
152+
153+
# Build Docker image
154+
docker:
155+
@echo "==> Building Docker image..."
156+
docker build -t $(DOCKER_IMAGE):$(DOCKER_TAG) -f ../../Dockerfile ../../
157+
@echo "==> Docker image built: $(DOCKER_IMAGE):$(DOCKER_TAG)"
158+
159+
# Install Helm chart
160+
helm-install:
161+
@echo "==> Installing Helm chart..."
162+
helm upgrade --install $(HELM_RELEASE_NAME) $(HELM_CHART_PATH) --namespace $(HELM_NAMESPACE)
163+
@echo "==> Helm chart installed: $(HELM_RELEASE_NAME)"
164+
165+
# Uninstall Helm chart
166+
helm-uninstall:
167+
@echo "==> Uninstalling Helm chart..."
168+
helm uninstall $(HELM_RELEASE_NAME) --namespace $(HELM_NAMESPACE)
169+
@echo "==> Helm chart uninstalled: $(HELM_RELEASE_NAME)"

cmd/project-api/README.md

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
# Project API
22

33
This directory contains the Project API service. The service does a couple of things:
4+
45
- It serves HTTP requests via Traefik to perform CRUD operations on project data
56
- It listens on a NATS connection for messages from external services to also perform operations on project data
67

78
Applications with a BFF should use the REST API with HTTP requests to perform the needed operations on projects, while other resource API services should communicate with this service via NATS messages.
89

910
This service contains the following API endpoints:
11+
1012
- `/readyz`:
11-
- `GET`: checks that the service is able to take in inbound requests
13+
- `GET`: checks that the service is able to take in inbound requests
1214
- `/livez`:
13-
- `GET`: checks that the service is alive
15+
- `GET`: checks that the service is alive
1416
- `/projects`
15-
- `GET`: fetch the list of projects (Note: this will be removed in favor of using the query service, once implemented)
16-
- `POST` create a new project
17+
- `GET`: fetch the list of projects (Note: this will be removed in favor of using the query service, once implemented)
18+
- `POST` create a new project
1719
- `/projects/:id`
18-
- `GET`: fetch a project by its UID
19-
- `PUT`: update a project by its UID - only certain attributes can be updated, read the openapi spec for more details
20-
- `DELETE`: delete a project by its UID
20+
- `GET`: fetch a project by its UID
21+
- `PUT`: update a project by its UID - only certain attributes can be updated, read the openapi spec for more details
22+
- `DELETE`: delete a project by its UID
2123

2224
This service handles the following NATS subjects:
25+
2326
- `<lfx_environment>.lfx.projects-api.get_name`: Get a project name from a given project UID
2427
- `<lfx_environment>.lfx.projects-api.slug_to_uid`: Get a project UID from a given project slug
2528

@@ -58,6 +61,7 @@ go install goa.design/goa/v3/cmd/goa@latest
5861
```
5962

6063
Verify the installation:
64+
6165
```bash
6266
goa version
6367
```
@@ -76,6 +80,7 @@ goa gen github.com/linuxfoundation/lfx-v2-project-service/cmd/project-api/design
7680
```
7781

7882
This command generates:
83+
7984
- HTTP server and client code
8085
- OpenAPI specification
8186
- Service interfaces and types
@@ -107,6 +112,9 @@ The service relies on some resources and external services being spun up prior t
107112
|LFX_ENVIRONMENT|the LFX environment (enum: prod, stg, dev)|dev|false|
108113
|LOG_LEVEL|the log level for outputted logs|info|false|
109114
|LOG_ADD_SOURCE|whether to add the source field to outputted logs|false|false|
115+
|JWKS_URL|the URL to the endpoint for verifying ID tokens and JWT access tokens||false|
116+
|AUDIENCE|the audience of the app that the JWT token should have set - for verification of the JWT token|lfx-v2-project-service|false|
117+
|JWT_AUTH_DISABLED_MOCK_LOCAL_PRINCIPAL|a mocked auth principal value for local development (to avoid needing a valid JWT token)||false|
110118

111119
#### 4. Development Workflow
112120

@@ -115,10 +123,13 @@ The service relies on some resources and external services being spun up prior t
115123
2. **Regenerate code**: Run `make apigen` after design changes
116124

117125
3. **Build the service**:
126+
118127
```bash
119128
make build
120129
```
130+
121131
4. **Run the service**:
132+
122133
```bash
123134
make run
124135
@@ -127,11 +138,21 @@ The service relies on some resources and external services being spun up prior t
127138
128139
# or run with the go command to set custom flags
129140
# -bind string interface to bind on (default "*")
130-
# -d enable debug logging (default false)
141+
# -d enable debug logging (default false)
131142
# -p string listen port (default "8080")
132143
go run
133144
```
145+
146+
Once the service is running, make a request to the `/livez` endpoint to ensure that the service is alive.
147+
148+
```bash
149+
curl http://localhost:8080/livez
150+
```
151+
152+
You should get a 200 status code response with a text/plain content payload of `OK`.
153+
134154
5. **Run tests**:
155+
135156
```bash
136157
make test
137158
@@ -140,6 +161,7 @@ The service relies on some resources and external services being spun up prior t
140161
```
141162

142163
6. **Lint the code**
164+
143165
```bash
144166
# From the root of the directory, run megalinter (https://megalinter.io/latest/mega-linter-runner/) to ensure the code passes the linter checks. The CI/CD has a check that uses megalinter.
145167
npx mega-linter-runner .
@@ -164,14 +186,18 @@ The service relies on some resources and external services being spun up prior t
164186
```
165187

166188
### Add new API endpoints
189+
167190
Note: follow the [Development Workflow](#4-development-workflow) section on how to run the service code
191+
168192
1. **Update design files**: Edit project file in `design/` to include specicification of the new endpoint with all of its supported parameters, responses, and errors, etc.
169193
2. **Regenerate code**: Run `make apigen` after design changes
170194
3. **Implement code**: Implement the new endpoint in `service_endpoint.go`. Follow similar standards of the other endpoint methods. Include tests for the new endpoint in `service_endpoint_test.go`.
171195
4. **Update heimdall ruleset**: Ensure that `/charts/lfx-v2-project-service/templates/ruleset.yaml` has the route and method for the endpoint set so that authentication is configured when deployed
172196

173197
### Add new message handlers
198+
174199
Note: follow the [Development Workflow](#4-development-workflow) section on how to run the service code
200+
175201
1. **Update main.go**: In `main.go` is the code for subscribing the service to specific NATS queue subjects. Add the subscription code in the `createNatsSubcriptions` function. If a new subject needs to be subscribed, add the subject to the `../pkg/constants` directory in a similiar fashion as the other subject names (so that it can be referenced by other services that need to send messages for the subject).
176202
2. **Update service_handler.go**: Implement the NATS message handler. Add a new function, such as `HandleProjectGetName` for handling messages with respect to getting the name of a project. The `HandleNatsMessage` function switch statement should also be updated to include the new subject and function call.
177203
3. **Update service_handler_test.go**: Add unit tests for the new handler function. Mock external service calls so that the tests are modular.

cmd/project-api/design/project.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ var _ = Service("project-service", func() {
9494
POST("/projects")
9595
Param("version:v")
9696
Header("bearer_token:Authorization")
97-
Response(StatusOK)
97+
Response(StatusCreated)
9898
Response("BadRequest", StatusBadRequest)
9999
Response("Conflict", StatusConflict)
100100
Response("InternalServerError", StatusInternalServerError)

cmd/project-api/gen/http/openapi.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

cmd/project-api/gen/http/openapi.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ paths:
127127
- description
128128
- name
129129
responses:
130-
"200":
131-
description: OK response.
130+
"201":
131+
description: Created response.
132132
schema:
133133
$ref: '#/definitions/Project'
134134
"400":

cmd/project-api/gen/http/openapi3.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

cmd/project-api/gen/http/openapi3.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ paths:
170170
- user123
171171
- user456
172172
responses:
173-
"200":
174-
description: OK response.
173+
"201":
174+
description: Created response.
175175
content:
176176
application/json:
177177
schema:

cmd/project-api/gen/http/project_service/client/encode_decode.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/project-api/gen/http/project_service/client/types.go

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)