From dbd32d0deef91cecac97c6ef263d17d7bad3a404 Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Sun, 28 Jul 2024 16:07:46 +0330 Subject: [PATCH 01/11] chore: add initial .gitignore file --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c0a063 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +* +!/**/ +!*.* From 3abfca821721666f7d91673157fd834350021b18 Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Sun, 28 Jul 2024 16:09:55 +0330 Subject: [PATCH 02/11] feat(Phase-05): `traceroute` Rest API implemented. Co-authored-by: Mohammad Sadegh Montazeri --- Phase-05/README.txt | 0 Phase-05/dto.go | 19 ++++++ Phase-05/go.mod | 11 ++++ Phase-05/go.sum | 10 ++++ Phase-05/main.go | 6 ++ Phase-05/server.go | 57 ++++++++++++++++++ Phase-05/storage.go | 35 +++++++++++ Phase-05/traceroute.go | 133 +++++++++++++++++++++++++++++++++++++++++ Phase-05/utils.go | 73 ++++++++++++++++++++++ 9 files changed, 344 insertions(+) create mode 100644 Phase-05/README.txt create mode 100644 Phase-05/dto.go create mode 100644 Phase-05/go.mod create mode 100644 Phase-05/go.sum create mode 100644 Phase-05/main.go create mode 100644 Phase-05/server.go create mode 100644 Phase-05/storage.go create mode 100644 Phase-05/traceroute.go create mode 100644 Phase-05/utils.go diff --git a/Phase-05/README.txt b/Phase-05/README.txt new file mode 100644 index 0000000..e69de29 diff --git a/Phase-05/dto.go b/Phase-05/dto.go new file mode 100644 index 0000000..2670e89 --- /dev/null +++ b/Phase-05/dto.go @@ -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(), + } + } +} diff --git a/Phase-05/go.mod b/Phase-05/go.mod new file mode 100644 index 0000000..1f232b2 --- /dev/null +++ b/Phase-05/go.mod @@ -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 +) diff --git a/Phase-05/go.sum b/Phase-05/go.sum new file mode 100644 index 0000000..320b9ba --- /dev/null +++ b/Phase-05/go.sum @@ -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= diff --git a/Phase-05/main.go b/Phase-05/main.go new file mode 100644 index 0000000..c769a7c --- /dev/null +++ b/Phase-05/main.go @@ -0,0 +1,6 @@ +package main + +func main() { + initRedis() + RunTraceRouteServer(":8080") +} diff --git a/Phase-05/server.go b/Phase-05/server.go new file mode 100644 index 0000000..d5bb926 --- /dev/null +++ b/Phase-05/server.go @@ -0,0 +1,57 @@ +package main + +import ( + "log" + "net/http" + "regexp" + "strconv" + "strings" +) + +var AddrRegex = regexp.MustCompile(`^(\d{1,3}\.){3}\d{1,3}$`) + +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) { + WriteBadRequest(w, "Invalid 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 := TraceRoute(addr, maxHops) + + 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) + } +} diff --git a/Phase-05/storage.go b/Phase-05/storage.go new file mode 100644 index 0000000..891b899 --- /dev/null +++ b/Phase-05/storage.go @@ -0,0 +1,35 @@ +package main + +import ( + "context" + + "github.com/go-redis/redis/v8" +) + +var ( + ctx = context.Background() + rdb *redis.Client = nil +) + +func initRedis() { + if rdb == nil { + rdb = redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", + DB: 0, + }) + } +} + +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 +} diff --git a/Phase-05/traceroute.go b/Phase-05/traceroute.go new file mode 100644 index 0000000..87f3849 --- /dev/null +++ b/Phase-05/traceroute.go @@ -0,0 +1,133 @@ +// Copyright © 2016 Alex +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package main + +import ( + "crypto/rand" + "fmt" + "net" + "os" + "time" + + "golang.org/x/net/icmp" + "golang.org/x/net/ipv4" +) + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const ( + ProtocolICMP = 1 + //ProtocolIPv6ICMP = 58 + ListenAddr = "0.0.0.0" +) + +type TraceHop struct { + IPAddr net.IP + RTT time.Duration +} + +func TraceRoute(addr string, maxHops int) []*TraceHop { + c, err := icmp.ListenPacket("ip4:icmp", ListenAddr) + if err != nil { + panic(err) + } + defer c.Close() + + res := make([]*TraceHop, maxHops) + + for i := 0; i < maxHops; i++ { + finished, dst, dur, err := getNthHop(c, addr, i+1) + if err != nil { + res[i] = nil + } else { + res[i] = &TraceHop{IPAddr: dst.IP, RTT: dur} + if finished { + return res[:i+1] + } + } + + } + + return res +} + +// Mostly based on https://github.com/golang/net/blob/master/icmp/ping_test.go +// All ye beware, there be dragons below... + +func getNthHop(c *icmp.PacketConn, addr string, ttl int) (bool, *net.IPAddr, time.Duration, error) { + // Start listening for icmp replies + c.IPv4PacketConn().SetTTL(ttl) + + // Resolve any DNS (if used) and get the real IP of the target + dst, err := net.ResolveIPAddr("ip4", addr) + if err != nil { + panic(err) + } + + data := make([]byte, 64) + rand.Read(data) + + // Make a new ICMP message + m := icmp.Message{ + Type: ipv4.ICMPTypeEcho, Code: 0, + Body: &icmp.Echo{ + ID: os.Getpid() & 0xffff, Seq: 1, //<< uint(seq), // TODO + Data: data, + }, + } + b, err := m.Marshal(nil) + if err != nil { + return false, dst, 0, err + } + + // Send it + start := time.Now() + + n, err := c.WriteTo(b, dst) + if err != nil { + return false, dst, 0, err + } else if n != len(b) { + return false, dst, 0, fmt.Errorf("got %v; want %v", n, len(b)) + } + + // Wait for a reply + reply := make([]byte, 1500) + err = c.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) + if err != nil { + return false, dst, 0, err + } + n, peer, err := c.ReadFrom(reply) + if err != nil { + // fmt.Println("Unable to read!") + return false, dst, 0, err + } + duration := time.Since(start) + + // Pack it up boys, we're done here + rm, err := icmp.ParseMessage(ProtocolICMP, reply[:n]) + if err != nil { + return false, dst, 0, err + } + switch rm.Type { + case ipv4.ICMPTypeEchoReply: + return true, dst, duration, nil + case ipv4.ICMPTypeTimeExceeded: + // Convert peer to IPAddr + return false, &net.IPAddr{IP: peer.(*net.IPAddr).IP}, duration, nil + default: + return false, dst, 0, fmt.Errorf("got %+v from %v; want echo reply", rm, peer) + } +} diff --git a/Phase-05/utils.go b/Phase-05/utils.go new file mode 100644 index 0000000..01f758b --- /dev/null +++ b/Phase-05/utils.go @@ -0,0 +1,73 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "regexp" + "time" +) + +func defaultString(s, def string) string { + if s == "" { + return def + } + return s +} + +type route struct { + pattern *regexp.Regexp + handler http.Handler +} + +type RegexpHandler struct { + routes []*route +} + +func (h *RegexpHandler) Handler(pattern *regexp.Regexp, handler http.Handler) { + h.routes = append(h.routes, &route{pattern, handler}) +} + +func (h *RegexpHandler) HandleFunc(pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request)) { + h.routes = append(h.routes, &route{pattern, http.HandlerFunc(handler)}) +} + +func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + for _, route := range h.routes { + if route.pattern.MatchString(r.URL.Path) { + route.handler.ServeHTTP(w, r) + return + } + } + // no pattern matched; send 404 response + http.NotFound(w, r) +} + +func WriteBadRequest(w http.ResponseWriter, msg string) []byte { + w.WriteHeader(http.StatusBadRequest) + resp, _ := json.Marshal(map[string]string{"error": msg}) + + log.Printf("Bad request: %s\n", resp) + + w.Write(resp) + return resp +} + +func WriteJSON(w http.ResponseWriter, data interface{}) ([]byte, error) { + w.Header().Set("Content-Type", "application/json") + jsonData, err := json.Marshal(data) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return nil, err + } + + w.Write(jsonData) + + return jsonData, nil +} + +func GenerateRedisKey(addr string, maxHops int) string { + timestamp := time.Now().Unix() + return fmt.Sprintf("%s:%d:%d", addr, maxHops, timestamp) +} From 3c4d335f5d3bfc1209cc995c8fd0e6028a2562a3 Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Sun, 28 Jul 2024 16:15:47 +0330 Subject: [PATCH 03/11] docs: README.md --- Phase-05/README.md | 28 ++++++++++++++++++++++++++++ Phase-05/README.txt | 0 2 files changed, 28 insertions(+) create mode 100644 Phase-05/README.md delete mode 100644 Phase-05/README.txt diff --git a/Phase-05/README.md b/Phase-05/README.md new file mode 100644 index 0000000..e492ef2 --- /dev/null +++ b/Phase-05/README.md @@ -0,0 +1,28 @@ +# 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/8.8.8.8?maxHops=10 +``` \ No newline at end of file diff --git a/Phase-05/README.txt b/Phase-05/README.txt deleted file mode 100644 index e69de29..0000000 From 2ddcad50c12b7786709376d6bb1c300b7ec6135a Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Sun, 28 Jul 2024 16:22:32 +0330 Subject: [PATCH 04/11] feat(Phase-05): Update traceroute regex pattern for domain names. --- Phase-05/README.md | 3 +++ Phase-05/server.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Phase-05/README.md b/Phase-05/README.md index e492ef2..47d4f63 100644 --- a/Phase-05/README.md +++ b/Phase-05/README.md @@ -24,5 +24,8 @@ $ curl http://localhost:8080/trace/{ip}?maxHops={max_hops} $ 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 ``` \ No newline at end of file diff --git a/Phase-05/server.go b/Phase-05/server.go index d5bb926..aca11c6 100644 --- a/Phase-05/server.go +++ b/Phase-05/server.go @@ -8,7 +8,7 @@ import ( "strings" ) -var AddrRegex = regexp.MustCompile(`^(\d{1,3}\.){3}\d{1,3}$`) +var AddrRegex = regexp.MustCompile(`^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$`) func traceRouteHandler(w http.ResponseWriter, r *http.Request) { path, _, _ := strings.Cut(r.URL.Path, "?") From db5f5faa95ef540ed4a8f196c3440a6e58fc845e Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Tue, 30 Jul 2024 03:52:42 +0330 Subject: [PATCH 05/11] chore: Better error handling and higher customizability --- Phase-05/config.go | 7 +++++++ Phase-05/main.go | 9 ++++++++- Phase-05/server.go | 13 +++++++++---- Phase-05/storage.go | 16 ++++++++++------ Phase-05/traceroute.go | 22 +++++++++++----------- Phase-05/utils.go | 10 ++++++++-- 6 files changed, 53 insertions(+), 24 deletions(-) create mode 100644 Phase-05/config.go diff --git a/Phase-05/config.go b/Phase-05/config.go new file mode 100644 index 0000000..6893cdf --- /dev/null +++ b/Phase-05/config.go @@ -0,0 +1,7 @@ +package main + +import ( + "os" +) + +var redisConnStr = defaultString(os.Getenv("REDIS_CONN_STR"), "redis://localhost:6379") diff --git a/Phase-05/main.go b/Phase-05/main.go index c769a7c..c8a3cdc 100644 --- a/Phase-05/main.go +++ b/Phase-05/main.go @@ -1,6 +1,13 @@ package main +import "log" + func main() { - initRedis() + err := initRedis() + if err != nil { + log.Fatal(err) + } + log.Println("Successfully connected to Redis") + RunTraceRouteServer(":8080") } diff --git a/Phase-05/server.go b/Phase-05/server.go index aca11c6..491231b 100644 --- a/Phase-05/server.go +++ b/Phase-05/server.go @@ -8,15 +8,16 @@ import ( "strings" ) -var AddrRegex = regexp.MustCompile(`^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$`) +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) { - WriteBadRequest(w, "Invalid addr") + if !AddrRegex.MatchString(addr) && !DomainRegex.MatchString(addr) { + WriteBadRequest(w, "Invalid addr "+addr) return } @@ -26,7 +27,11 @@ func traceRouteHandler(w http.ResponseWriter, r *http.Request) { return } - hops := TraceRoute(addr, maxHops) + 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 { diff --git a/Phase-05/storage.go b/Phase-05/storage.go index 891b899..47cfc8c 100644 --- a/Phase-05/storage.go +++ b/Phase-05/storage.go @@ -11,14 +11,18 @@ var ( rdb *redis.Client = nil ) -func initRedis() { +func initRedis() error { if rdb == nil { - rdb = redis.NewClient(&redis.Options{ - Addr: "localhost:6379", - Password: "", - DB: 0, - }) + 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 { diff --git a/Phase-05/traceroute.go b/Phase-05/traceroute.go index 87f3849..7703302 100644 --- a/Phase-05/traceroute.go +++ b/Phase-05/traceroute.go @@ -39,44 +39,44 @@ type TraceHop struct { RTT time.Duration } -func TraceRoute(addr string, maxHops int) []*TraceHop { +func TraceRoute(addr string, maxHops int) ([]*TraceHop, error) { c, err := icmp.ListenPacket("ip4:icmp", ListenAddr) if err != nil { panic(err) } defer c.Close() + // Resolve any DNS (if used) and get the real IP of the target + dst, err := net.ResolveIPAddr("ip4", addr) + if err != nil { + return nil, err + } + res := make([]*TraceHop, maxHops) for i := 0; i < maxHops; i++ { - finished, dst, dur, err := getNthHop(c, addr, i+1) + finished, dst, dur, err := getNthHop(c, dst, i+1) if err != nil { res[i] = nil } else { res[i] = &TraceHop{IPAddr: dst.IP, RTT: dur} if finished { - return res[:i+1] + return res[:i+1], nil } } } - return res + return res, nil } // Mostly based on https://github.com/golang/net/blob/master/icmp/ping_test.go // All ye beware, there be dragons below... -func getNthHop(c *icmp.PacketConn, addr string, ttl int) (bool, *net.IPAddr, time.Duration, error) { +func getNthHop(c *icmp.PacketConn, dst *net.IPAddr, ttl int) (bool, *net.IPAddr, time.Duration, error) { // Start listening for icmp replies c.IPv4PacketConn().SetTTL(ttl) - // Resolve any DNS (if used) and get the real IP of the target - dst, err := net.ResolveIPAddr("ip4", addr) - if err != nil { - panic(err) - } - data := make([]byte, 64) rand.Read(data) diff --git a/Phase-05/utils.go b/Phase-05/utils.go index 01f758b..24b3cad 100644 --- a/Phase-05/utils.go +++ b/Phase-05/utils.go @@ -45,10 +45,16 @@ func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } func WriteBadRequest(w http.ResponseWriter, msg string) []byte { - w.WriteHeader(http.StatusBadRequest) + resp := WriteError(w, msg, http.StatusBadRequest) + log.Printf("Bad request: %s\n", resp) + return resp +} + +func WriteError(w http.ResponseWriter, msg string, code int) []byte { + w.WriteHeader(code) resp, _ := json.Marshal(map[string]string{"error": msg}) - log.Printf("Bad request: %s\n", resp) + log.Printf("%s: %s\n", http.StatusText(code), resp) w.Write(resp) return resp From 3be995233bf10634d17806e733243dcee55b7204 Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Sat, 3 Aug 2024 20:47:19 +0000 Subject: [PATCH 06/11] Dockerfile added. --- .gitignore | 1 + Phase-05/Dockerfile | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 Phase-05/Dockerfile diff --git a/.gitignore b/.gitignore index 0c0a063..11d5bbe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ * !/**/ !*.* +!Dockerfile diff --git a/Phase-05/Dockerfile b/Phase-05/Dockerfile new file mode 100644 index 0000000..6acdc46 --- /dev/null +++ b/Phase-05/Dockerfile @@ -0,0 +1,27 @@ +# +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 +# + +# +FROM alpine:3.20.0 AS final + +WORKDIR /app + +COPY --from=build --chown=root:root /app/traceroute-api ./traceroute-api + +EXPOSE 8080 + +CMD ["./traceroute-api"] +# From ee86ed3c693bd68f33b4f44db992f5a4b3a74079 Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Sun, 4 Aug 2024 10:51:59 +0000 Subject: [PATCH 07/11] Empty From 8737e0a68dff1801b63fbf835b1d01cbb5c064e9 Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Sun, 4 Aug 2024 10:58:16 +0000 Subject: [PATCH 08/11] Version 1.0.0 From f027e6dd067e97e71e36cfd836244c312470ca16 Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Sun, 4 Aug 2024 14:40:18 +0000 Subject: [PATCH 09/11] chore: Add source label to Dockerfile --- Phase-05/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Phase-05/Dockerfile b/Phase-05/Dockerfile index 6acdc46..2387374 100644 --- a/Phase-05/Dockerfile +++ b/Phase-05/Dockerfile @@ -19,6 +19,8 @@ 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 From 4157fbd1156290c517211d888008a4fa82f2de2f Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Mon, 5 Aug 2024 07:30:45 +0000 Subject: [PATCH 10/11] chore(Dockerfile): New style LABEL. --- Phase-05/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Phase-05/Dockerfile b/Phase-05/Dockerfile index 2387374..83f762d 100644 --- a/Phase-05/Dockerfile +++ b/Phase-05/Dockerfile @@ -19,7 +19,7 @@ FROM alpine:3.20.0 AS final WORKDIR /app -LABEL org.opencontainers.image.source https://github.com/Star-Academy/Summer1403-Devops-Team12 +LABEL org.opencontainers.image.source=https://github.com/Star-Academy/Summer1403-Devops-Team12 COPY --from=build --chown=root:root /app/traceroute-api ./traceroute-api From 55af17a2998cd66311ed9b3ce3d23238604bf73f Mon Sep 17 00:00:00 2001 From: Alireza Jafari Date: Wed, 7 Aug 2024 09:19:50 +0000 Subject: [PATCH 11/11] feat(Phase-05): Updated traceRouteHandler() to just log redis errors instead of panic. --- Phase-05/server.go | 2 +- Phase-05/storage.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Phase-05/server.go b/Phase-05/server.go index 491231b..b0a1409 100644 --- a/Phase-05/server.go +++ b/Phase-05/server.go @@ -46,7 +46,7 @@ func traceRouteHandler(w http.ResponseWriter, r *http.Request) { err = saveToRedis(GenerateRedisKey(addr, maxHops), response) if err != nil { - log.Fatal(err) + log.Println(err) } } diff --git a/Phase-05/storage.go b/Phase-05/storage.go index 47cfc8c..697ef39 100644 --- a/Phase-05/storage.go +++ b/Phase-05/storage.go @@ -2,6 +2,7 @@ package main import ( "context" + "log" "github.com/go-redis/redis/v8" ) @@ -27,6 +28,7 @@ func initRedis() error { func saveToRedis(key string, value []byte) error { if rdb == nil { + log.Println("Redis not initialized. Initializing now...") initRedis() }