Skip to content

Commit

Permalink
feat: new APIs for traffic pricings (#496)
Browse files Browse the repository at this point in the history
The API has been updated to provide a better insight and more
flexibility for displaying the pricing of traffic for servers and load
balancers.

In addition to the new fields, the old fields are deprecated and will be
set to `null` in the API on 2024-08-05.

As far as we could tell they are not widely used in Open Source code,
please check if you are using them in any private code. Some linters
automatically check for deprecated fields, if you use `golangci-lint`
this is provided by the `staticcheck` linter.

You can learn more about this change in [our
changelog](https://docs.hetzner.cloud/changelog#2024-07-25-cloud-api-returns-traffic-information-in-different-format).

### Upgrading

#### Server Type Included Traffic

If you were using the field `hcloud.ServerType.IncludedTraffic`, you can
now get the information through `hcloud.ServerType.Pricings`:

```go
func main() {
    // previous
    includedTraffic := serverType.IncludedTraffic

    // now
    locationOfInterest := "fsn1"
    var includedTraffic uint64
    for _, price := range serverType.Pricings {
        if price.Location.Name == locationOfInterest {
            includedTraffic = price.IncludedTraffic
            break
        }
    }
}
```

#### Traffic Prices

If you were using the field `hcloud.Pricing.Traffic`, you can now get
the information through `hcloud.Pricing.ServerTypes` or
`hcloud.Pricing.LoadBalancerTypes`:

```go
func main() {
    // previous
    trafficPrice := pricing.Traffic

    // now
    serverTypeOfInterest := "cx22"
    locationOfInterest := "fsn1"

    var trafficPrice hcloud.Price
    for _, serverTypePricings := range pricing.ServerTypes {
        if serverTypePricings.ServerType.Name == serverTypeOfInterest {
            for _, price := range serverTypePricings {
               if price.Location.Name == locationOfInterest {
                   trafficPrice = price.PerTBTraffic
                   break
               }
            }
        }
    }
}
```
  • Loading branch information
apricote authored Jul 25, 2024
1 parent db7e12d commit 90c3110
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 23 deletions.
18 changes: 14 additions & 4 deletions hcloud/pricing.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import (

// Pricing specifies pricing information for various resources.
type Pricing struct {
Image ImagePricing
FloatingIP FloatingIPPricing
FloatingIPs []FloatingIPTypePricing
PrimaryIPs []PrimaryIPPricing
Image ImagePricing
FloatingIP FloatingIPPricing
FloatingIPs []FloatingIPTypePricing
PrimaryIPs []PrimaryIPPricing
// Deprecated: [Pricing.Traffic] is deprecated and will report 0 after 2024-08-05.
// Use traffic pricing from [Pricing.ServerTypes] or [Pricing.LoadBalancerTypes] instead.
Traffic TrafficPricing
ServerBackup ServerBackupPricing
ServerTypes []ServerTypePricing
Expand Down Expand Up @@ -102,6 +104,10 @@ type ServerTypeLocationPricing struct {
Location *Location
Hourly Price
Monthly Price

// IncludedTraffic is the free traffic per month in bytes
IncludedTraffic uint64
PerTBTraffic Price
}

// LoadBalancerTypePricing provides pricing information for a Load Balancer type.
Expand All @@ -116,6 +122,10 @@ type LoadBalancerTypeLocationPricing struct {
Location *Location
Hourly Price
Monthly Price

// IncludedTraffic is the free traffic per month in bytes
IncludedTraffic uint64
PerTBTraffic Price
}

// PricingClient is a client for the pricing API.
Expand Down
30 changes: 27 additions & 3 deletions hcloud/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func ServerTypeFromSchema(s schema.ServerType) *ServerType {
StorageType: StorageType(s.StorageType),
CPUType: CPUType(s.CPUType),
Architecture: Architecture(s.Architecture),
IncludedTraffic: s.IncludedTraffic,
IncludedTraffic: s.IncludedTraffic, // nolint:staticcheck // Field is deprecated, but we still need to map it as long as it is available
DeprecatableResource: DeprecatableResource{
DeprecationFromSchema(s.Deprecation),
},
Expand All @@ -306,6 +306,11 @@ func ServerTypeFromSchema(s schema.ServerType) *ServerType {
Net: price.PriceMonthly.Net,
Gross: price.PriceMonthly.Gross,
},
IncludedTraffic: price.IncludedTraffic,
PerTBTraffic: Price{
Net: price.PricePerTBTraffic.Net,
Gross: price.PricePerTBTraffic.Gross,
},
})
}

Expand Down Expand Up @@ -472,6 +477,11 @@ func LoadBalancerTypeFromSchema(s schema.LoadBalancerType) *LoadBalancerType {
Net: price.PriceMonthly.Net,
Gross: price.PriceMonthly.Gross,
},
IncludedTraffic: price.IncludedTraffic,
PerTBTraffic: Price{
Net: price.PricePerTBTraffic.Net,
Gross: price.PricePerTBTraffic.Gross,
},
})
}
return lt
Expand Down Expand Up @@ -701,8 +711,8 @@ func PricingFromSchema(s schema.Pricing) Pricing {
PerTB: Price{
Currency: s.Currency,
VATRate: s.VATRate,
Net: s.Traffic.PricePerTB.Net,
Gross: s.Traffic.PricePerTB.Gross,
Net: s.Traffic.PricePerTB.Net, // nolint:staticcheck // Field is deprecated, but we still need to map it as long as it is available
Gross: s.Traffic.PricePerTB.Gross, // nolint:staticcheck // Field is deprecated, but we still need to map it as long as it is available
},
},
ServerBackup: ServerBackupPricing{
Expand Down Expand Up @@ -768,6 +778,13 @@ func PricingFromSchema(s schema.Pricing) Pricing {
Net: price.PriceMonthly.Net,
Gross: price.PriceMonthly.Gross,
},
IncludedTraffic: price.IncludedTraffic,
PerTBTraffic: Price{
Currency: s.Currency,
VATRate: s.VATRate,
Net: price.PricePerTBTraffic.Net,
Gross: price.PricePerTBTraffic.Gross,
},
})
}
p.ServerTypes = append(p.ServerTypes, ServerTypePricing{
Expand Down Expand Up @@ -795,6 +812,13 @@ func PricingFromSchema(s schema.Pricing) Pricing {
Net: price.PriceMonthly.Net,
Gross: price.PriceMonthly.Gross,
},
IncludedTraffic: price.IncludedTraffic,
PerTBTraffic: Price{
Currency: s.Currency,
VATRate: s.VATRate,
Net: price.PricePerTBTraffic.Net,
Gross: price.PricePerTBTraffic.Gross,
},
})
}
p.LoadBalancerTypes = append(p.LoadBalancerTypes, LoadBalancerTypePricing{
Expand Down
20 changes: 14 additions & 6 deletions hcloud/schema/pricing.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package schema

// Pricing defines the schema for pricing information.
type Pricing struct {
Currency string `json:"currency"`
VATRate string `json:"vat_rate"`
Image PricingImage `json:"image"`
FloatingIP PricingFloatingIP `json:"floating_ip"`
FloatingIPs []PricingFloatingIPType `json:"floating_ips"`
PrimaryIPs []PricingPrimaryIP `json:"primary_ips"`
Currency string `json:"currency"`
VATRate string `json:"vat_rate"`
Image PricingImage `json:"image"`
FloatingIP PricingFloatingIP `json:"floating_ip"`
FloatingIPs []PricingFloatingIPType `json:"floating_ips"`
PrimaryIPs []PricingPrimaryIP `json:"primary_ips"`
// Deprecated: [Pricing.Traffic] is deprecated and will report 0 after 2024-08-05.
// Use traffic pricing from [Pricing.ServerTypes] or [Pricing.LoadBalancerTypes] instead.
Traffic PricingTraffic `json:"traffic"`
ServerBackup PricingServerBackup `json:"server_backup"`
ServerTypes []PricingServerType `json:"server_types"`
Expand Down Expand Up @@ -72,6 +74,9 @@ type PricingServerTypePrice struct {
Location string `json:"location"`
PriceHourly Price `json:"price_hourly"`
PriceMonthly Price `json:"price_monthly"`

IncludedTraffic uint64 `json:"included_traffic"`
PricePerTBTraffic Price `json:"price_per_tb_traffic"`
}

// PricingLoadBalancerType defines the schema of pricing information for a Load Balancer type.
Expand All @@ -87,6 +92,9 @@ type PricingLoadBalancerTypePrice struct {
Location string `json:"location"`
PriceHourly Price `json:"price_hourly"`
PriceMonthly Price `json:"price_monthly"`

IncludedTraffic uint64 `json:"included_traffic"`
PricePerTBTraffic Price `json:"price_per_tb_traffic"`
}

// PricingGetResponse defines the schema of the response when retrieving pricing information.
Expand Down
21 changes: 12 additions & 9 deletions hcloud/schema/server_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ package schema

// ServerType defines the schema of a server type.
type ServerType struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Cores int `json:"cores"`
Memory float32 `json:"memory"`
Disk int `json:"disk"`
StorageType string `json:"storage_type"`
CPUType string `json:"cpu_type"`
Architecture string `json:"architecture"`
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Cores int `json:"cores"`
Memory float32 `json:"memory"`
Disk int `json:"disk"`
StorageType string `json:"storage_type"`
CPUType string `json:"cpu_type"`
Architecture string `json:"architecture"`

// Deprecated: [ServerType.IncludedTraffic] is deprecated and will always report 0 after 2024-08-05.
// Use [ServerType.Prices] instead to get the included traffic for each location.
IncludedTraffic int64 `json:"included_traffic"`
Prices []PricingServerTypePrice `json:"prices"`
DeprecatableResource
Expand Down
74 changes: 74 additions & 0 deletions hcloud/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,11 @@ func TestServerTypeFromSchema(t *testing.T) {
"price_monthly": {
"net": "1",
"gross": "1.19"
},
"included_traffic": 654321,
"price_per_tb_traffic": {
"net": "1",
"gross": "1.19"
}
}
]
Expand Down Expand Up @@ -991,6 +996,17 @@ func TestServerTypeFromSchema(t *testing.T) {
if serverType.Pricings[0].Monthly.Gross != "1.19" {
t.Errorf("unexpected monthly gross price: %v", serverType.Pricings[0].Monthly.Gross)
}

if serverType.Pricings[0].IncludedTraffic != 654321 {
t.Errorf("unexpected included traffic: %v", serverType.Pricings[0].IncludedTraffic)
}

if serverType.Pricings[0].PerTBTraffic.Net != "1" {
t.Errorf("unexpected per tb traffic net price: %v", serverType.Pricings[0].PerTBTraffic.Net)
}
if serverType.Pricings[0].PerTBTraffic.Gross != "1.19" {
t.Errorf("unexpected per tb traffic gross price: %v", serverType.Pricings[0].PerTBTraffic.Gross)
}
}
}

Expand Down Expand Up @@ -1460,6 +1476,11 @@ func TestLoadBalancerTypeFromSchema(t *testing.T) {
"price_monthly": {
"net": "1",
"gross": "1.19"
},
"included_traffic": 654321,
"price_per_tb_traffic": {
"net": "1",
"gross": "1.19"
}
}
]
Expand Down Expand Up @@ -1508,6 +1529,17 @@ func TestLoadBalancerTypeFromSchema(t *testing.T) {
if loadBalancerType.Pricings[0].Monthly.Gross != "1.19" {
t.Errorf("unexpected monthly gross price: %v", loadBalancerType.Pricings[0].Monthly.Gross)
}

if loadBalancerType.Pricings[0].IncludedTraffic != 654321 {
t.Errorf("unexpected included traffic: %v", loadBalancerType.Pricings[0].IncludedTraffic)
}

if loadBalancerType.Pricings[0].PerTBTraffic.Net != "1" {
t.Errorf("unexpected per tb traffic net price: %v", loadBalancerType.Pricings[0].PerTBTraffic.Net)
}
if loadBalancerType.Pricings[0].PerTBTraffic.Gross != "1.19" {
t.Errorf("unexpected per tb traffic gross price: %v", loadBalancerType.Pricings[0].PerTBTraffic.Gross)
}
}
}

Expand Down Expand Up @@ -2103,6 +2135,11 @@ func TestPricingFromSchema(t *testing.T) {
"price_monthly": {
"net": "1",
"gross": "1.19"
},
"included_traffic": 654321,
"price_per_tb_traffic": {
"net": "1",
"gross": "1.19"
}
}
]
Expand All @@ -2122,6 +2159,11 @@ func TestPricingFromSchema(t *testing.T) {
"price_monthly": {
"net": "1",
"gross": "1.19"
},
"included_traffic": 654321,
"price_per_tb_traffic": {
"net": "1",
"gross": "1.19"
}
}
]
Expand Down Expand Up @@ -2299,6 +2341,22 @@ func TestPricingFromSchema(t *testing.T) {
if p.Pricings[0].Monthly.Gross != "1.19" {
t.Errorf("unexpected Monthly.Gross: %v", p.Pricings[0].Monthly.Gross)
}

if p.Pricings[0].IncludedTraffic != 654321 {
t.Errorf("unexpected IncludedTraffic: %v", p.Pricings[0].IncludedTraffic)
}
if p.Pricings[0].PerTBTraffic.Currency != "EUR" {
t.Errorf("unexpected PerTBTraffic.Currency: %v", p.Pricings[0].PerTBTraffic.Currency)
}
if p.Pricings[0].PerTBTraffic.VATRate != "19.00" {
t.Errorf("unexpected PerTBTraffic.VATRate: %v", p.Pricings[0].PerTBTraffic.VATRate)
}
if p.Pricings[0].PerTBTraffic.Net != "1" {
t.Errorf("unexpected PerTBTraffic.Net: %v", p.Pricings[0].PerTBTraffic.Net)
}
if p.Pricings[0].PerTBTraffic.Gross != "1.19" {
t.Errorf("unexpected PerTBTraffic.Gross: %v", p.Pricings[0].PerTBTraffic.Gross)
}
}
}

Expand Down Expand Up @@ -2346,6 +2404,22 @@ func TestPricingFromSchema(t *testing.T) {
if p.Pricings[0].Monthly.Gross != "1.19" {
t.Errorf("unexpected Monthly.Gross: %v", p.Pricings[0].Monthly.Gross)
}

if p.Pricings[0].IncludedTraffic != 654321 {
t.Errorf("unexpected IncludedTraffic: %v", p.Pricings[0].IncludedTraffic)
}
if p.Pricings[0].PerTBTraffic.Currency != "EUR" {
t.Errorf("unexpected PerTBTraffic.Currency: %v", p.Pricings[0].PerTBTraffic.Currency)
}
if p.Pricings[0].PerTBTraffic.VATRate != "19.00" {
t.Errorf("unexpected PerTBTraffic.VATRate: %v", p.Pricings[0].PerTBTraffic.VATRate)
}
if p.Pricings[0].PerTBTraffic.Net != "1" {
t.Errorf("unexpected PerTBTraffic.Net: %v", p.Pricings[0].PerTBTraffic.Net)
}
if p.Pricings[0].PerTBTraffic.Gross != "1.19" {
t.Errorf("unexpected PerTBTraffic.Gross: %v", p.Pricings[0].PerTBTraffic.Gross)
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion hcloud/server_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ type ServerType struct {
StorageType StorageType
CPUType CPUType
Architecture Architecture
// IncludedTraffic is the free traffic per month in bytes

// Deprecated: [ServerType.IncludedTraffic] is deprecated and will always report 0 after 2024-08-05.
// Use [ServerType.Pricings] instead to get the included traffic for each location.
IncludedTraffic int64
Pricings []ServerTypeLocationPricing
DeprecatableResource
Expand Down

0 comments on commit 90c3110

Please sign in to comment.