Skip to content
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7c3f450
fix: Security fixes for Akamai DNS metrics API - Fix URL injection vu…
abdullah-karatas May 26, 2025
ce8bd4f
security: fix domain authorization bypass in Akamai DNS metrics API
abdullah-karatas May 26, 2025
7b24fb5
WIP
notandy May 28, 2025
aa9268e
move everything to generated RPC framework
notandy May 29, 2025
5ecae81
Fix REUSE and go mod tidy
notandy May 30, 2025
a7ba1d5
Added missing parameter
ronchi-oss Jun 11, 2025
1656693
Add comprehensive unit tests for Akamai metrics functionality
abdullah-karatas Jun 11, 2025
d840ef1
fix: use switch statement instead of if-else for datacenter ID compar…
abdullah-karatas Jun 11, 2025
815416f
fix: handle Akamai historical data without explicit timestamps
abdullah-karatas Jul 9, 2025
866f917
fix: remove unused extractMetricName function to satisfy linter
abdullah-karatas Jul 9, 2025
52a4935
fix: add nil check for agent in PendingSync to prevent test panics
abdullah-karatas Jul 9, 2025
a62fe12
refactor: remove non-functional unit tests per team feedback
abdullah-karatas Jul 13, 2025
1bc5e05
fix: resolve Akamai agent startup issues for RPC communication
abdullah-karatas Jul 14, 2025
ea94163
fix: prevent panic when Akamai dataRow has empty datacenters array
abdullah-karatas Jul 15, 2025
ec51ca6
Merge remote-tracking branch 'origin/main' into add-unit-tests-akamai…
abdullah-karatas Jul 16, 2025
b3bf1a8
Merge upstream main into add-unit-tests-akamai-metrics
abdullah-karatas Jul 16, 2025
2315d6b
fix: correct CidrBlocksController initialization after merge
abdullah-karatas Jul 16, 2025
f92a9b3
fix: remove duplicate restapi/** entry in REUSE.toml
abdullah-karatas Jul 18, 2025
e1b8dcc
refactor: remove unused NewCidrBlocksController function
abdullah-karatas Jul 18, 2025
bbb2121
style: remove redundant akamai import alias
abdullah-karatas Jul 18, 2025
c0351c4
style: remove redundant akamaiAgent import alias
abdullah-karatas Jul 18, 2025
1d42796
refactor: remove redundant global akamaiAgent and standalone RPC hand…
abdullah-karatas Jul 18, 2025
028c5a5
refactor: remove unused GetDNSMetricsAkamai RPC method
abdullah-karatas Jul 18, 2025
f72ecfc
fix: remove unused imports after GetDNSMetricsAkamai removal
abdullah-karatas Jul 18, 2025
48edb0e
chore: remove accidentally committed test files
abdullah-karatas Jul 18, 2025
8b2ccb3
fix: address code review feedback in akamai driver
abdullah-karatas Jul 31, 2025
2eff6ac
Merge branch 'main' into add-unit-tests-akamai-metrics
AbdullahKaratas Aug 6, 2025
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
1 change: 1 addition & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ path = [
"models/**",
"etc/**",
"web/**",
"internal/rpc/**.pb.go",
]
precedence = "aggregate"
SPDX-FileCopyrightText = "2022-2025 SAP SE or an SAP affiliate company and andromeda contributors"
Expand Down
12 changes: 0 additions & 12 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ require (
github.com/cockroachdb/cockroach-go/v2 v2.4.1
github.com/didip/tollbooth v4.0.2+incompatible
github.com/dlmiddlecote/sqlstats v1.0.2
github.com/dre1080/recovr v1.0.3
github.com/getsentry/sentry-go v0.20.0
github.com/go-openapi/errors v0.22.1
github.com/go-openapi/loads v0.22.0
Expand Down Expand Up @@ -72,9 +71,6 @@ require (
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
github.com/gobuffalo/logger v1.0.3 // indirect
github.com/gobuffalo/packd v1.0.0 // indirect
github.com/gobuffalo/packr/v2 v2.8.0 // indirect
github.com/gofrs/uuid/v5 v5.3.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
Expand All @@ -84,15 +80,10 @@ require (
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/karrick/godirwalk v1.15.3 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/markbates/errx v1.1.0 // indirect
github.com/markbates/oncer v1.0.0 // indirect
github.com/markbates/safe v1.0.1 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
Expand All @@ -110,12 +101,10 @@ require (
github.com/rabbitmq/amqp091-go v1.10.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/ztrue/tracerr v0.3.0 // indirect
go.mongodb.org/mongo-driver v1.14.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
Expand All @@ -124,7 +113,6 @@ require (
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/time v0.11.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
Expand Down
120 changes: 0 additions & 120 deletions go.sum

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions internal/client/table_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ func formatValue(v reflect.Value) string {
return "Null"
}
return formatValue(v.Elem())
case reflect.Slice, reflect.Array:
if v.Len() == 0 {
return "[]"
}
// For datacenters slice, show a summary
if v.Len() > 0 {
firstElem := v.Index(0)
if firstElem.Kind() == reflect.Ptr && !firstElem.IsNil() {
firstElem = firstElem.Elem()
}
// Check if this looks like a datacenter slice
if firstElem.Kind() == reflect.Struct {
typeName := firstElem.Type().Name()
if typeName == "AkamaiTotalDNSRequestsDatacentersItems0" {
// Show a summary for datacenters
return fmt.Sprintf("%d datacenter(s)", v.Len())
}
}
}
// For other slices, show count
return fmt.Sprintf("[%d items]", v.Len())
default:
return fmt.Sprintf("%v", v)
}
Expand Down
32 changes: 14 additions & 18 deletions internal/controller/cidr_blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@
package controller

import (
"encoding/json"
"fmt"
"context"
"time"

"github.com/actatum/stormrpc"
"github.com/apex/log"
"github.com/go-openapi/runtime/middleware"

"github.com/sapcc/andromeda/internal/auth"
"github.com/sapcc/andromeda/internal/rpc/agent/akamai"
"github.com/sapcc/andromeda/internal/rpcmodels"
"github.com/sapcc/andromeda/internal/utils"
"github.com/sapcc/andromeda/restapi/operations/administrative"
)

type cidrBlocks []map[string]any

type CidrBlocksController struct {
CommonController
cache map[string]cidrBlocks
cache map[string]*rpcmodels.GetCidrsResponse
agent akamai.RPCAgentAkamaiClient
}

// GetCidrBlocks GET /cidr-blocks
Expand All @@ -35,23 +36,18 @@ func (c CidrBlocksController) GetCidrBlocks(params administrative.GetCidrBlocksP
}

// Check if the CIDR blocks are already cached
var res cidrBlocks
var res *rpcmodels.GetCidrsResponse
var ok bool
if res, ok = c.cache[provider]; !ok {
subject := fmt.Sprintf("andromeda.get_cidrs.%s", provider)
r, err := stormrpc.NewRequest(subject, nil)
if err != nil {
panic(err)
}
ctx, cancel := context.WithTimeout(params.HTTPRequest.Context(), 5*time.Second)
defer cancel()

resp := c.rpc.Do(params.HTTPRequest.Context(), r)
if resp.Err != nil {
panic(resp.Err)
var err error
if res, err = c.agent.GetCidrs(ctx, &rpcmodels.GetCidrsRequest{}); err != nil {
log.WithError(err).Error("failed to get cidr blocks")
return administrative.NewGetCidrBlocksDefault(408).WithPayload(utils.TryAgainLater)
}

if err = json.Unmarshal(resp.Data, &res); err != nil {
panic(err)
}
c.cache[provider] = res
}
return administrative.NewGetCidrBlocksOK().WithPayload(res)
Expand Down
39 changes: 21 additions & 18 deletions internal/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (
"github.com/nats-io/nats.go"

"github.com/sapcc/andromeda/internal/config"
"github.com/sapcc/andromeda/internal/rpc/agent"
"github.com/sapcc/andromeda/internal/rpc/agent/akamai"
"github.com/sapcc/andromeda/internal/rpcmodels"
)

type Controller struct {
Expand All @@ -30,9 +33,10 @@ type Controller struct {
}

type CommonController struct {
db *sqlx.DB
nc *nats.Conn
rpc *stormrpc.Client
db *sqlx.DB
nc *nats.Conn
rpc *stormrpc.Client
agent agent.RPCAgentClient
}

func New(db *sqlx.DB) *Controller {
Expand All @@ -47,9 +51,10 @@ func New(db *sqlx.DB) *Controller {
}

cc := CommonController{
db: db,
nc: nc,
rpc: rpcClient,
db: db,
nc: nc,
rpc: rpcClient,
agent: agent.NewRPCAgentClient(rpcClient),
}
c := Controller{
DomainController{cc},
Expand All @@ -61,24 +66,22 @@ func New(db *sqlx.DB) *Controller {
QuotaController{cc},
SyncController{cc},
GeoMapController{cc},
CidrBlocksController{cc, make(map[string]cidrBlocks)},
CidrBlocksController{
CommonController: cc,
cache: make(map[string]*rpcmodels.GetCidrsResponse),
agent: akamai.NewRPCAgentAkamaiClient(rpcClient),
},
}
return &c
}

func PendingSync(client *stormrpc.Client) error {
if client == nil {
func (cc CommonController) PendingSync() error {
// Skip sync if agent is not initialized (e.g., in tests)
if cc.agent == nil {
return nil
}

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

r, err := stormrpc.NewRequest("andromeda.sync", []string{})
if err != nil {
return err
}

resp := client.Do(ctx, r)
return resp.Err
_, err := cc.agent.Sync(ctx, &rpcmodels.SyncRequest{})
return err
}
6 changes: 3 additions & 3 deletions internal/controller/datacenter.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (c DatacenterController) PostDatacenters(params datacenters.PostDatacenters
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return datacenters.NewPostDatacentersCreated().WithPayload(&datacenters.PostDatacentersCreatedBody{Datacenter: datacenter})
}

Expand Down Expand Up @@ -151,7 +151,7 @@ func (c DatacenterController) PutDatacentersDatacenterID(params datacenters.PutD
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return datacenters.NewPutDatacentersDatacenterIDAccepted().WithPayload(
&datacenters.PutDatacentersDatacenterIDAcceptedBody{Datacenter: &datacenter})
}
Expand Down Expand Up @@ -191,7 +191,7 @@ func (c DatacenterController) DeleteDatacentersDatacenterID(params datacenters.D
return datacenters.NewDeleteDatacentersDatacenterIDNotFound().WithPayload(utils.NotFound)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return datacenters.NewDeleteDatacentersDatacenterIDNoContent()
}

Expand Down
6 changes: 3 additions & 3 deletions internal/controller/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func (c DomainController) PostDomains(params domains.PostDomainsParams) middlewa
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
populateCNAME(domain)
return domains.NewPostDomainsCreated().WithPayload(&domains.PostDomainsCreatedBody{Domain: domain})
}
Expand Down Expand Up @@ -254,7 +254,7 @@ func (c DomainController) PutDomainsDomainID(params domains.PutDomainsDomainIDPa
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
populateCNAME(&domain)
return domains.NewPutDomainsDomainIDAccepted().WithPayload(&domains.PutDomainsDomainIDAcceptedBody{Domain: &domain})
}
Expand All @@ -276,7 +276,7 @@ func (c DomainController) DeleteDomainsDomainID(params domains.DeleteDomainsDoma
return domains.NewDeleteDomainsDomainIDNotFound().WithPayload(utils.NotFound)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return domains.NewDeleteDomainsDomainIDNoContent()
}

Expand Down
4 changes: 2 additions & 2 deletions internal/controller/geomap.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func (c GeoMapController) PostGeomaps(params geographic_maps.PostGeomapsParams)
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return geographic_maps.NewPostGeomapsCreated().WithPayload(&geographic_maps.PostGeomapsCreatedBody{Geomap: geomap})
}

Expand Down Expand Up @@ -227,7 +227,7 @@ func (c GeoMapController) DeleteGeomapsGeoMapID(params geographic_maps.DeleteGeo
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return geographic_maps.NewDeleteGeomapsGeomapIDNoContent()
}

Expand Down
6 changes: 3 additions & 3 deletions internal/controller/member.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func (c MemberController) PostMembers(params members.PostMembersParams) middlewa
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return members.NewPostMembersCreated().
WithPayload(&members.PostMembersCreatedBody{Member: member})
}
Expand Down Expand Up @@ -186,7 +186,7 @@ func (c MemberController) PutMembersMemberID(params members.PutMembersMemberIDPa
panic(err)
}

if err := PendingSync(c.rpc); err != nil {
if err := c.PendingSync(); err != nil {
log.WithError(err).Error("Failed to sync provisioning status")
}
return members.NewPutMembersMemberIDAccepted().
Expand Down Expand Up @@ -218,7 +218,7 @@ func (c MemberController) DeleteMembersMemberID(params members.DeleteMembersMemb
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return members.NewDeleteMembersMemberIDNoContent()
}

Expand Down
6 changes: 3 additions & 3 deletions internal/controller/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func (c MonitorController) PostMonitors(params monitors.PostMonitorsParams) midd
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return monitors.NewPostMonitorsCreated().WithPayload(&monitors.PostMonitorsCreatedBody{Monitor: monitor})
}

Expand Down Expand Up @@ -189,7 +189,7 @@ func (c MonitorController) PutMonitorsMonitorID(params monitors.PutMonitorsMonit
if err := PopulateMonitor(c.db, &monitor, []string{"*"}); err != nil {
panic(err)
}
_ = PendingSync(c.rpc)
_ = c.PendingSync()
return monitors.NewPutMonitorsMonitorIDAccepted().WithPayload(
&monitors.PutMonitorsMonitorIDAcceptedBody{Monitor: &monitor})
}
Expand Down Expand Up @@ -218,7 +218,7 @@ func (c MonitorController) DeleteMonitorsMonitorID(params monitors.DeleteMonitor
}
panic(err)
}
_ = PendingSync(c.rpc)
_ = c.PendingSync()
return monitors.NewDeleteMonitorsMonitorIDNoContent()
}

Expand Down
6 changes: 3 additions & 3 deletions internal/controller/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func (c PoolController) PostPools(params pools.PostPoolsParams) middleware.Respo
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return pools.NewPostPoolsCreated().WithPayload(&pools.PostPoolsCreatedBody{Pool: pool})
}

Expand Down Expand Up @@ -220,7 +220,7 @@ func (c PoolController) PutPoolsPoolID(params pools.PutPoolsPoolIDParams) middle
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return pools.NewPutPoolsPoolIDAccepted().WithPayload(&pools.PutPoolsPoolIDAcceptedBody{Pool: &pool})
}

Expand Down Expand Up @@ -255,7 +255,7 @@ func (c PoolController) DeletePoolsPoolID(params pools.DeletePoolsPoolIDParams)
panic(err)
}

_ = PendingSync(c.rpc)
_ = c.PendingSync()
return pools.NewDeletePoolsPoolIDNoContent()
}

Expand Down
Loading