Skip to content

Commit ece0447

Browse files
committed
feat: translate bytes into dollar amounts
1 parent c0f0bd9 commit ece0447

File tree

10 files changed

+58
-22
lines changed

10 files changed

+58
-22
lines changed

.github/workflows/deploy.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ jobs:
3434
workspace: warm-staging
3535
network: warm
3636
did: did:web:staging.etracker.warm.storacha.network
37+
egress-dollars-per-tib: ${{ vars.WARM_STAGING_EGRESS_DOLLARS_PER_TIB }}
3738
apply: ${{ github.event_name != 'pull_request' }}
3839
secrets:
3940
aws-account-id: ${{ secrets.WARM_STAGING_AWS_ACCOUNT_ID }}
@@ -54,6 +55,7 @@ jobs:
5455
workspace: forge-prod
5556
network: forge
5657
did: did:web:etracker.forge.storacha.network
58+
egress-dollars-per-tib: ${{ vars.FORGE_PROD_EGRESS_DOLLARS_PER_TIB }}
5759
apply: ${{ (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'forge-production') }}
5860
secrets:
5961
aws-account-id: ${{ secrets.FORGE_PROD_AWS_ACCOUNT_ID }}

.github/workflows/terraform.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ on:
1616
did:
1717
required: true
1818
type: string
19+
egress-dollars-per-tib:
20+
required: true
21+
type: number
1922
apply:
2023
required: true
2124
type: boolean
@@ -58,6 +61,7 @@ env:
5861
TF_VAR_metrics_auth_token: ${{ secrets.metrics-auth-token }}
5962
TF_VAR_admin_dashboard_user: ${{ secrets.admin-dashboard-user }}
6063
TF_VAR_admin_dashboard_password: ${{ secrets.admin-dashboard-password }}
64+
TF_VAR_egress_dollars_per_tib: ${{ inputs.egress-dollars-per-tib }}
6165
TF_VAR_cloudflare_zone_id: ${{ secrets.cloudflare-zone-id }}
6266
CLOUDFLARE_API_TOKEN: ${{ secrets.cloudflare-api-token }}
6367
DEPLOY_ENV: ci

cmd/etracker/start.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ func init() {
6767
cobra.CheckErr(viper.BindEnv("metrics_auth_token"))
6868
cobra.CheckErr(viper.BindEnv("admin_dashboard_user"))
6969
cobra.CheckErr(viper.BindEnv("admin_dashboard_password"))
70+
cobra.CheckErr(viper.BindEnv("egress_dollars_per_tib"))
7071

7172
startCmd.Flags().String(
7273
"egress-table-name",
@@ -242,6 +243,7 @@ func startService(cmd *cobra.Command, args []string) error {
242243
cons,
243244
server.WithMetricsEndpoint(cfg.MetricsAuthToken),
244245
server.WithAdminCreds(cfg.AdminDashboardUser, cfg.AdminDashboardPassword),
246+
server.WithPricing(cfg.EgressDollarsPerTiB),
245247
server.WithPrincipalResolver(presolver),
246248
)
247249
if err != nil {

cmd/preview-admin/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ func main() {
165165
})
166166

167167
// Wrap admin handler with authentication
168-
adminHandler := web.BasicAuthMiddleware(web.AdminHandler(mockSvc), username, password)
168+
// Use a default pricing value for preview ($10 per TiB)
169+
adminHandler := web.BasicAuthMiddleware(web.AdminHandler(mockSvc, 10.0), username, password)
169170
mux.HandleFunc("/admin", adminHandler)
170171
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
171172
http.Redirect(w, r, "/admin", http.StatusFound)

deploy/app/main.tf

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@ module "app" {
5353
# if there are any env vars you want available only to your container
5454
# in the vpc as opposed to set in the dockerfile, enter them here
5555
# NOTE: do not put sensitive data in env-vars. use secrets
56-
deployment_env_vars = []
56+
deployment_env_vars = [
57+
{
58+
name = "ETRACKER_EGRESS_DOLLARS_PER_TIB"
59+
value = var.egress_dollars_per_tib
60+
}
61+
]
5762
image_tag = var.image_tag
5863
create_db = false
5964
# enter secret values your app will use here -- these will be available

deploy/app/variables.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,8 @@ variable "admin_dashboard_password" {
6565
description = "value for admin_dashboard_password secret"
6666
type = string
6767
}
68+
69+
variable "egress_dollars_per_tib" {
70+
description = "Cost in dollars per TiB of egress"
71+
type = string
72+
}

internal/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type Config struct {
1717
MetricsAuthToken string `mapstructure:"metrics_auth_token"`
1818
AdminDashboardUser string `mapstructure:"admin_dashboard_user"`
1919
AdminDashboardPassword string `mapstructure:"admin_dashboard_password"`
20+
EgressDollarsPerTiB float64 `mapstructure:"egress_dollars_per_tib"`
2021
AWSConfig aws.Config `mapstructure:"aws_config"`
2122
EgressTableName string `mapstructure:"egress_table_name" validate:"required"`
2223
EgressUnprocessedIndexName string `mapstructure:"egress_unprocessed_index_name" validate:"required"`

internal/server/server.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type config struct {
2121
metricsEndpointToken string
2222
adminUser string
2323
adminPassword string
24+
egressDollarsPerTiB float64
2425
principalResolver validator.PrincipalResolver
2526
}
2627

@@ -39,6 +40,12 @@ func WithAdminCreds(user, password string) Option {
3940
}
4041
}
4142

43+
func WithPricing(egressDollarsPerTiB float64) Option {
44+
return func(c *config) {
45+
c.egressDollarsPerTiB = egressDollarsPerTiB
46+
}
47+
}
48+
4249
func WithPrincipalResolver(resolver validator.PrincipalResolver) Option {
4350
return func(c *config) {
4451
c.principalResolver = resolver
@@ -80,7 +87,7 @@ func (s *Server) ListenAndServe(addr string) error {
8087
mux.HandleFunc("GET /receipts/{cid}", s.getReceiptsHandler())
8188

8289
// Set up admin endpoint with authentication (handles both GET and POST)
83-
adminHandler := web.BasicAuthMiddleware(web.AdminHandler(s.svc), s.cfg.adminUser, s.cfg.adminPassword)
90+
adminHandler := web.BasicAuthMiddleware(web.AdminHandler(s.svc, s.cfg.egressDollarsPerTiB), s.cfg.adminUser, s.cfg.adminPassword)
8491
mux.HandleFunc("GET /admin", adminHandler)
8592
mux.HandleFunc("POST /admin", adminHandler)
8693

web/admin.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,14 @@ var loginTemplateHTML string
8282
var loginCSS string
8383

8484
type adminDashboardData struct {
85-
ActiveTab string
86-
Providers []service.ProviderWithStats
87-
Accounts []service.AccountStats
88-
NextToken *string
89-
PrevToken *string
90-
Error string
91-
CSS template.CSS
85+
ActiveTab string
86+
Providers []service.ProviderWithStats
87+
Accounts []service.AccountStats
88+
NextToken *string
89+
PrevToken *string
90+
Error string
91+
CSS template.CSS
92+
EgressDollarsPerTiB float64
9293
}
9394

9495
type loginData struct {
@@ -118,6 +119,12 @@ func formatDate(t interface{}) string {
118119
return fmt.Sprintf("%v", t)
119120
}
120121

122+
func formatDollars(bytes uint64, dollarsPerTiB float64) string {
123+
const bytesPerTiB = 1024 * 1024 * 1024 * 1024
124+
dollars := (float64(bytes) / bytesPerTiB) * dollarsPerTiB
125+
return fmt.Sprintf("$%.2f", dollars)
126+
}
127+
121128
// showLoginForm renders the login form
122129
func showLoginForm(w http.ResponseWriter, r *http.Request, errorMsg string) {
123130
tmpl := template.Must(template.New("login").Parse(loginTemplateHTML))
@@ -221,17 +228,19 @@ func BasicAuthMiddleware(handler http.HandlerFunc, username, password string) ht
221228
}
222229

223230
// AdminHandler returns an HTTP handler for the admin dashboard
224-
func AdminHandler(svc StatsService) http.HandlerFunc {
231+
func AdminHandler(svc StatsService, egressDollarsPerTiB float64) http.HandlerFunc {
225232
tmpl := template.Must(template.New("admin").Funcs(template.FuncMap{
226-
"formatBytes": formatBytes,
227-
"formatDate": formatDate,
233+
"formatBytes": formatBytes,
234+
"formatDate": formatDate,
235+
"formatDollars": formatDollars,
228236
}).Parse(adminTemplateHTML))
229237

230238
const defaultLimit = 20
231239

232240
return func(w http.ResponseWriter, r *http.Request) {
233241
data := adminDashboardData{
234-
CSS: template.CSS(adminCSS),
242+
CSS: template.CSS(adminCSS),
243+
EgressDollarsPerTiB: egressDollarsPerTiB,
235244
}
236245

237246
// Get active tab from query parameter (default to "providers")

web/templates/admin.html.tmpl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@
7373
{{if .StatsError}}
7474
<td colspan="4" class="stats-error">Error: {{.StatsError.Error}}</td>
7575
{{else if .Stats}}
76-
<td class="stat-value">{{.Stats.CurrentDay.Egress | formatBytes}}</td>
77-
<td class="stat-value">{{.Stats.CurrentWeek.Egress | formatBytes}}</td>
78-
<td class="stat-value">{{.Stats.CurrentMonth.Egress | formatBytes}}</td>
79-
<td class="stat-value">{{.Stats.PreviousMonth.Egress | formatBytes}}</td>
76+
<td class="stat-value" title="{{.Stats.CurrentDay.Egress | formatBytes}}">{{formatDollars .Stats.CurrentDay.Egress $.EgressDollarsPerTiB}}</td>
77+
<td class="stat-value" title="{{.Stats.CurrentWeek.Egress | formatBytes}}">{{formatDollars .Stats.CurrentWeek.Egress $.EgressDollarsPerTiB}}</td>
78+
<td class="stat-value" title="{{.Stats.CurrentMonth.Egress | formatBytes}}">{{formatDollars .Stats.CurrentMonth.Egress $.EgressDollarsPerTiB}}</td>
79+
<td class="stat-value" title="{{.Stats.PreviousMonth.Egress | formatBytes}}">{{formatDollars .Stats.PreviousMonth.Egress $.EgressDollarsPerTiB}}</td>
8080
{{else}}
8181
<td colspan="4" class="no-stats">No stats available</td>
8282
{{end}}
@@ -142,10 +142,10 @@
142142
{{if .StatsError}}
143143
<td colspan="4" class="stats-error">Error: {{.StatsError.Error}}</td>
144144
{{else if .Stats}}
145-
<td class="stat-value">{{.Stats.CurrentDay.Egress | formatBytes}}</td>
146-
<td class="stat-value">{{.Stats.CurrentWeek.Egress | formatBytes}}</td>
147-
<td class="stat-value">{{.Stats.CurrentMonth.Egress | formatBytes}}</td>
148-
<td class="stat-value">{{.Stats.PreviousMonth.Egress | formatBytes}}</td>
145+
<td class="stat-value" title="{{.Stats.CurrentDay.Egress | formatBytes}}">{{formatDollars .Stats.CurrentDay.Egress $.EgressDollarsPerTiB}}</td>
146+
<td class="stat-value" title="{{.Stats.CurrentWeek.Egress | formatBytes}}">{{formatDollars .Stats.CurrentWeek.Egress $.EgressDollarsPerTiB}}</td>
147+
<td class="stat-value" title="{{.Stats.CurrentMonth.Egress | formatBytes}}">{{formatDollars .Stats.CurrentMonth.Egress $.EgressDollarsPerTiB}}</td>
148+
<td class="stat-value" title="{{.Stats.PreviousMonth.Egress | formatBytes}}">{{formatDollars .Stats.PreviousMonth.Egress $.EgressDollarsPerTiB}}</td>
149149
{{else}}
150150
<td colspan="4" class="no-stats">No stats available</td>
151151
{{end}}

0 commit comments

Comments
 (0)