-
Notifications
You must be signed in to change notification settings - Fork 0
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
Phase11 #10
base: main
Are you sure you want to change the base?
Phase11 #10
Changes from all commits
dbd32d0
3abfca8
3c4d335
2ddcad5
db5f5fa
3be9952
ee86ed3
8737e0a
f027e6d
4157fbd
d9c8db5
8879a58
4123964
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 |
---|---|---|
@@ -0,0 +1,85 @@ | ||
name: Release | ||
|
||
on: | ||
pull_request: | ||
branches: | ||
- main | ||
types: | ||
- closed | ||
|
||
jobs: | ||
tag: | ||
# If the PR is merged from phase05, then we will bump the version and push a new tag | ||
if: ${{ github.event.pull_request.merged == true && github.head_ref == 'phase05' }} | ||
runs-on: ubuntu-latest | ||
|
||
permissions: | ||
contents: write | ||
|
||
outputs: | ||
new_tag: ${{ steps.generate_tag.outputs.new_tag }} | ||
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. این کجا استفاده میشه؟ 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. فعلا جای خاصی استفاده نمیشه اما jobی که کارش tag زدنه به نظرم منطقی باشه تگی که زده رو هم برکردونه. |
||
vversion: ${{ steps.generate_tag.outputs.new_tag }} | ||
version: ${{ steps.pure_version.outputs.version }} | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
|
||
- name: Bump version and push tag | ||
id: generate_tag | ||
uses: anothrNick/github-tag-action@v1 | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
WITH_V: true | ||
DEFAULT_BUMP: patch | ||
PATCH_STRING_TOKEN: fix | ||
MINOR_STRING_TOKEN: feat | ||
MAJOR_STRING_TOKEN: BREAKING | ||
|
||
- name: Pure version | ||
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. چه نیازی به این کار هست؟ 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. منظورتون pure_version هست؟ راستش چون actionی که استفاده کردم خودش tag میزنه و push میکنه و من میخواستم تگ ها قبلشون v داشته باشن WITH_V رو روشن گذاشتم اما ایمیج های داکر رو نمیخواستم v داشته باشن برای همین با sed حرف v رو از اول tag حذف میکنم و برمیگردونم. البته در نهایت هردو تگ با و بدون v رو گذاشتم برای داکر. |
||
id: pure_version | ||
run: echo "version=$(echo ${{ steps.generate_tag.outputs.new_tag }} | sed 's/^v//')" | tee -a $GITHUB_ENV | ||
|
||
release: | ||
runs-on: ubuntu-latest | ||
needs: | ||
- tag | ||
|
||
permissions: | ||
packages: write | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
|
||
- name: Metadata extraction | ||
id: metadata | ||
uses: docker/metadata-action@v5 | ||
with: | ||
# List of Docker images to use as base name for tags | ||
images: | | ||
ghcr.io/${{ github.repository }}/traceroute-api | ||
|
||
# Generates Docker tags based on the following events/attributes | ||
tags: | | ||
type=raw,value=${{ needs.tag.outputs.version }} | ||
type=raw,value=${{ needs.tag.outputs.vversion }} | ||
latest | ||
|
||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v2 | ||
|
||
- name: Login to GitHub Container Registry | ||
uses: docker/login-action@v2 | ||
with: | ||
registry: ghcr.io | ||
username: ${{ github.repository_owner }} | ||
password: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
- name: Build and push | ||
uses: docker/build-push-action@v3 | ||
with: | ||
push: true | ||
context: "{{defaultContext}}:Phase-05" | ||
tags: ${{ steps.metadata.outputs.tags }} | ||
labels: ${{ steps.metadata.outputs.labels }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
* | ||
!/**/ | ||
!*.* | ||
!Dockerfile |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# <Build stage> | ||
FROM golang:1.22.5-alpine3.20 AS build | ||
|
||
WORKDIR /app | ||
|
||
RUN adduser -D -g '' -u 10001 builder | ||
RUN chown -R builder:builder /app | ||
USER builder | ||
|
||
COPY go.mod go.sum ./ | ||
RUN go mod download | ||
|
||
COPY *.go ./ | ||
RUN go build -o ./traceroute-api | ||
# </Build stage> | ||
|
||
# <Final stage> | ||
FROM alpine:3.20.0 AS final | ||
|
||
WORKDIR /app | ||
|
||
LABEL org.opencontainers.image.source=https://github.com/Star-Academy/Summer1403-Devops-Team12 | ||
|
||
COPY --from=build --chown=root:root /app/traceroute-api ./traceroute-api | ||
|
||
EXPOSE 8080 | ||
|
||
CMD ["./traceroute-api"] | ||
# </Final stage> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# How to run | ||
|
||
## build | ||
```bash | ||
$ go build -o main | ||
``` | ||
|
||
## Run | ||
```bash | ||
# Listening to ICMP packets requires root privileges | ||
$ sudo ./main | ||
``` | ||
|
||
## Usage | ||
```bash | ||
$ curl http://localhost:8080/trace/{ip} | ||
``` | ||
```bash | ||
$ curl http://localhost:8080/trace/{ip}?maxHops={max_hops} | ||
``` | ||
|
||
## Example | ||
```bash | ||
$ curl http://localhost:8080/trace/8.8.8.8 | ||
``` | ||
```bash | ||
$ curl http://localhost:8080/trace/google.com | ||
``` | ||
```bash | ||
$ curl http://localhost:8080/trace/8.8.8.8?maxHops=10 | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
) | ||
|
||
var redisConnStr = defaultString(os.Getenv("REDIS_CONN_STR"), "redis://localhost:6379") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package main | ||
|
||
type TraceHopResponse struct { | ||
Hop int `json:"hop"` | ||
IPAddr string `json:"ip"` | ||
RTT int64 `json:"rtt"` | ||
} | ||
|
||
func (hop *TraceHop) toTraceHopResponse(hopIndex int) *TraceHopResponse { | ||
if hop == nil { | ||
return &TraceHopResponse{Hop: hopIndex + 1, IPAddr: "", RTT: -1} | ||
} else { | ||
return &TraceHopResponse{ | ||
Hop: hopIndex + 1, | ||
IPAddr: hop.IPAddr.String(), | ||
RTT: hop.RTT.Milliseconds(), | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module phase05 | ||
|
||
go 1.22.5 | ||
|
||
require ( | ||
github.com/cespare/xxhash/v2 v2.1.2 // indirect | ||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect | ||
github.com/go-redis/redis/v8 v8.11.5 // indirect | ||
golang.org/x/net v0.27.0 // indirect | ||
golang.org/x/sys v0.22.0 // indirect | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= | ||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= | ||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= | ||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | ||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= | ||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= | ||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= | ||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= | ||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= | ||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package main | ||
|
||
import "log" | ||
|
||
func main() { | ||
err := initRedis() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
log.Println("Successfully connected to Redis") | ||
|
||
RunTraceRouteServer(":8080") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"net/http" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
var DomainRegex = regexp.MustCompile(`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`) | ||
var AddrRegex = regexp.MustCompile(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`) | ||
|
||
func traceRouteHandler(w http.ResponseWriter, r *http.Request) { | ||
path, _, _ := strings.Cut(r.URL.Path, "?") | ||
trimmedPath := strings.Trim(path, "/") | ||
addr := trimmedPath[strings.LastIndex(trimmedPath, "/")+1:] | ||
|
||
if !AddrRegex.MatchString(addr) && !DomainRegex.MatchString(addr) { | ||
WriteBadRequest(w, "Invalid addr "+addr) | ||
return | ||
} | ||
|
||
maxHops, err := strconv.Atoi(defaultString(r.URL.Query().Get("maxHops"), "30")) | ||
if err != nil { | ||
WriteBadRequest(w, "maxHops must be an integer") | ||
return | ||
} | ||
|
||
hops, err := TraceRoute(addr, maxHops) | ||
if err != nil { | ||
WriteError(w, err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
result := make([]*TraceHopResponse, len(hops)) | ||
for i, hop := range hops { | ||
result[i] = hop.toTraceHopResponse(i) | ||
} | ||
|
||
response, err := WriteJSON(w, result) | ||
if err != nil { | ||
http.Error(w, err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
err = saveToRedis(GenerateRedisKey(addr, maxHops), response) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func RunTraceRouteServer(listen string) { | ||
handler := &RegexpHandler{} | ||
handler.HandleFunc(regexp.MustCompile(`^/trace/[^/]+$`), traceRouteHandler) | ||
|
||
log.Printf("Listening on %s\n", listen) | ||
err := http.ListenAndServe(listen, handler) | ||
if err != nil { | ||
log.Fatalf("Failed to start server. %v", err) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/go-redis/redis/v8" | ||
) | ||
|
||
var ( | ||
ctx = context.Background() | ||
rdb *redis.Client = nil | ||
) | ||
|
||
func initRedis() error { | ||
if rdb == nil { | ||
opts, err := redis.ParseURL(redisConnStr) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
rdb = redis.NewClient(opts) | ||
return rdb.Ping(ctx).Err() | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func saveToRedis(key string, value []byte) error { | ||
if rdb == nil { | ||
initRedis() | ||
} | ||
|
||
err := rdb.Set(ctx, key, value, 0).Err() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
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.
این اوکیه ولی چرا حالت سادهتر push روی main رو انتخاب نکردی؟
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.
یکم دست آدم رو بازتر میذاره. مثلا الان تنظیم کردم فقط موقعی که PRمون از phase05 مرج میشه اجرا بشه چون اگه سورس تغییر نکنه ایمیج نهایی هم تکراری میشه و فقط بی دلیل ورژن میخوره.