Skip to content

Commit

Permalink
new billing api
Browse files Browse the repository at this point in the history
  • Loading branch information
mxssl committed Sep 9, 2023
1 parent 7da5131 commit 6d193ef
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 209 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ jobs:
- uses: actions/checkout@v4
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.48.0

docker-release:
runs-on: ubuntu-latest
Expand All @@ -33,11 +31,11 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: 1.19
go-version: "1.20"
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v4
with:
version: latest
args: release --rm-dist
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Prometheus exporter для получения информации по билл

Экспортер раз в час ходит по url `https://api.selectel.ru/v3/balances` с токеном в запросе, получает в json формате инфу по балансу средств на счете и отдает ее по url `/metrics` в формате prometheus.

Для работы экспортера нужно получить API [токен](https://my.selectel.ru/profile/apikeys):
Для работы экспортера нужно получить API [токен](https://my.selectel.ru/profile/apikeys)

## Как запустить

Expand All @@ -19,7 +19,7 @@ version: '3'

services:
selectel_exporter:
image: mxssl/selectel-billing-exporter:1.0.0
image: mxssl/selectel-billing-exporter:1.1.0
ports:
- "6789:80"
restart: always
Expand Down Expand Up @@ -47,6 +47,7 @@ docker-compose logs
### helm

[Установка helm чарта](https://github.com/mxssl/helm-charts/tree/main/charts/selectel-billing-exporter)

### Создание манифестов вручную

```yaml
Expand All @@ -65,10 +66,9 @@ spec:
labels:
component: selectel-billing
spec:
terminationGracePeriodSeconds: 10
containers:
- name: exporter
image: mxssl/selectel-billing-exporter:1.0.2
image: mxssl/selectel-billing-exporter:1.1.0
command: ["./app"]
ports:
- containerPort: 80
Expand Down Expand Up @@ -110,12 +110,12 @@ kubectl apply -n exporters -f your-file.yaml
```yaml
- alert: selectel_billing
expr: selectel_billing_vpc_main{job="selectel_billing"} / 100 < 30000
expr: selectel_billing_final_sum{job="selectel_billing"} < 30000
for: 180s
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }}: В облаке Selectel на счете VPC меньше 30 тыс рублей"
summary: "{{ $labels.instance }}: В облаке Selectel на счете меньше 30 тыс рублей"
description: "Необходимо пополнить счет облака Selectel"
```
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)

go 1.19
go 1.20
101 changes: 17 additions & 84 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,11 @@ import (
var TOKEN string

type selectelBillingResponse struct {
Status string `json:"status"`
Data struct {
Currency string `json:"currency"`
IsPostpay bool `json:"is_postpay"`
Discount int `json:"discount"`
Primary struct {
Main int `json:"main"`
Bonus int `json:"bonus"`
VkRub int `json:"vk_rub"`
Ref int `json:"ref"`
Hold struct {
Main int `json:"main"`
Bonus int `json:"bonus"`
VkRub int `json:"vk_rub"`
} `json:"hold"`
} `json:"primary"`
Storage struct {
Main int `json:"main"`
Bonus int `json:"bonus"`
VkRub int `json:"vk_rub"`
Prediction interface{} `json:"prediction"`
Debt int `json:"debt"`
Sum int `json:"sum"`
} `json:"storage"`
Vpc struct {
Main int `json:"main"`
Bonus int `json:"bonus"`
VkRub int `json:"vk_rub"`
Prediction interface{} `json:"prediction"`
Debt int `json:"debt"`
Sum int `json:"sum"`
} `json:"vpc"`
Vmware struct {
Main int `json:"main"`
Bonus int `json:"bonus"`
VkRub int `json:"vk_rub"`
Prediction interface{} `json:"prediction"`
Debt int `json:"debt"`
Sum int `json:"sum"`
} `json:"vmware"`
Data struct {
Billings []struct {
FinalSum int `json:"final_sum"`
DebtSum int `json:"debt_sum"`
} `json:"billings"`
} `json:"data"`
}

Expand Down Expand Up @@ -110,23 +75,17 @@ func main() {
}

func initGauges() map[string]prometheus.Gauge {
selectelNames := make(map[string][]string)
selectelStructFields := []string{"main", "bonus", "vk_rub", "debt", "sum"}
selectelNames["primary"] = []string{"main", "bonus", "vk_rub", "ref", "hold_main", "hold_bonus", "hold_vk_rub"}
selectelNames["storage"] = selectelStructFields
selectelNames["vmware"] = selectelStructFields
selectelNames["vpc"] = selectelStructFields

promGauges := make(map[string]prometheus.Gauge)

for name, fields := range selectelNames {
for _, field := range fields {
promGauges["selectel_billing_"+name+"_"+field] = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "selectel_billing_" + name + "_" + field,
Help: "selectel billing " + name + " " + field,
})
}
}
promGauges["selectel_billing_final_sum"] = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "selectel_billing_final_sum",
Help: "selectel billing final sum",
})

promGauges["selectel_billing_debt_sum"] = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "selectel_billing_debt_sum",
Help: "selectel billing debt sum",
})

for _, v := range promGauges {
prometheus.MustRegister(v)
Expand All @@ -145,35 +104,9 @@ func recordMetrics() {
continue
}

// primary
gauge["selectel_billing_primary_main"].Set(float64(s.Data.Primary.Main))
gauge["selectel_billing_primary_bonus"].Set(float64(s.Data.Primary.Bonus))
gauge["selectel_billing_primary_vk_rub"].Set(float64(s.Data.Primary.VkRub))
gauge["selectel_billing_primary_ref"].Set(float64(s.Data.Primary.Ref))
gauge["selectel_billing_primary_hold_main"].Set(float64(s.Data.Primary.Hold.Main))
gauge["selectel_billing_primary_hold_bonus"].Set(float64(s.Data.Primary.Hold.Bonus))
gauge["selectel_billing_primary_hold_vk_rub"].Set(float64(s.Data.Primary.Hold.VkRub))

// storage
gauge["selectel_billing_storage_main"].Set(float64(s.Data.Storage.Main))
gauge["selectel_billing_storage_bonus"].Set(float64(s.Data.Storage.Bonus))
gauge["selectel_billing_storage_vk_rub"].Set(float64(s.Data.Storage.VkRub))
gauge["selectel_billing_storage_debt"].Set(float64(s.Data.Storage.Debt))
gauge["selectel_billing_storage_sum"].Set(float64(s.Data.Storage.Sum))

// vpc
gauge["selectel_billing_vpc_main"].Set(float64(s.Data.Vpc.Main))
gauge["selectel_billing_vpc_bonus"].Set(float64(s.Data.Vpc.Bonus))
gauge["selectel_billing_vpc_vk_rub"].Set(float64(s.Data.Vpc.VkRub))
gauge["selectel_billing_vpc_debt"].Set(float64(s.Data.Vpc.Debt))
gauge["selectel_billing_vpc_sum"].Set(float64(s.Data.Vpc.Sum))

// vmware
gauge["selectel_billing_vmware_main"].Set(float64(s.Data.Vmware.Main))
gauge["selectel_billing_vmware_bonus"].Set(float64(s.Data.Vmware.Bonus))
gauge["selectel_billing_vmware_vk_rub"].Set(float64(s.Data.Vmware.VkRub))
gauge["selectel_billing_vmware_debt"].Set(float64(s.Data.Vmware.Debt))
gauge["selectel_billing_vmware_sum"].Set(float64(s.Data.Vmware.Sum))
// записываем метрики
gauge["selectel_billing_final_sum"].Set(float64(s.Data.Billings[0].FinalSum))
gauge["selectel_billing_debt_sum"].Set(float64(s.Data.Billings[0].DebtSum))

time.Sleep(time.Hour * 1)
}
Expand Down
93 changes: 18 additions & 75 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,81 +20,24 @@ func TestSelectelBillingRequest(t *testing.T) {
httpmock.RegisterResponder("GET", "https://api.selectel.ru/v3/balances",
httpmock.NewStringResponder(200, string(testdata)))

expected := selectelBillingResponse{Status: "success", Data: struct {
Currency string "json:\"currency\""
IsPostpay bool "json:\"is_postpay\""
Discount int "json:\"discount\""
Primary struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
Ref int "json:\"ref\""
Hold struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
} "json:\"hold\""
} "json:\"primary\""
Storage struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
Prediction interface{} "json:\"prediction\""
Debt int "json:\"debt\""
Sum int "json:\"sum\""
} "json:\"storage\""
Vpc struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
Prediction interface{} "json:\"prediction\""
Debt int "json:\"debt\""
Sum int "json:\"sum\""
} "json:\"vpc\""
Vmware struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
Prediction interface{} "json:\"prediction\""
Debt int "json:\"debt\""
Sum int "json:\"sum\""
} "json:\"vmware\""
}{Currency: "rub", IsPostpay: false, Discount: 0, Primary: struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
Ref int "json:\"ref\""
Hold struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
} "json:\"hold\""
}{Main: 10000, Bonus: 10000, VkRub: 0, Ref: 0, Hold: struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
}{Main: 0, Bonus: 0, VkRub: 0}}, Storage: struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
Prediction interface{} "json:\"prediction\""
Debt int "json:\"debt\""
Sum int "json:\"sum\""
}{Main: 203005, Bonus: 0, VkRub: 0, Prediction: interface{}(nil), Debt: 0, Sum: 203005}, Vpc: struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
Prediction interface{} "json:\"prediction\""
Debt int "json:\"debt\""
Sum int "json:\"sum\""
}{Main: 11250838, Bonus: 12345, VkRub: 0, Prediction: interface{}(nil), Debt: 0, Sum: 11150838}, Vmware: struct {
Main int "json:\"main\""
Bonus int "json:\"bonus\""
VkRub int "json:\"vk_rub\""
Prediction interface{} "json:\"prediction\""
Debt int "json:\"debt\""
Sum int "json:\"sum\""
}{Main: 10000, Bonus: 10000, VkRub: 0, Prediction: interface{}(nil), Debt: 0, Sum: 20000}}}
expected := selectelBillingResponse{
Data: struct {
Billings []struct {
FinalSum int `json:"final_sum"`
DebtSum int `json:"debt_sum"`
} `json:"billings"`
}{
Billings: []struct {
FinalSum int `json:"final_sum"`
DebtSum int `json:"debt_sum"`
}{
{
FinalSum: 33218108,
DebtSum: 0,
},
},
},
}

actual := selectelBillingResponse{}

Expand Down
45 changes: 6 additions & 39 deletions testdata/SelectelBillingRespExample.json
Original file line number Diff line number Diff line change
@@ -1,43 +1,10 @@
{
"status": "success",
"data": {
"currency": "rub",
"is_postpay": false,
"discount": 0,
"primary": {
"main": 10000,
"bonus": 10000,
"vk_rub": 0,
"ref": 0,
"hold": {
"main": 0,
"bonus": 0,
"vk_rub": 0
"billings": [
{
"final_sum": 33218108,
"debt_sum": 0
}
},
"storage": {
"main": 203005,
"bonus": 0,
"vk_rub": 0,
"prediction": null,
"debt": 0,
"sum": 203005
},
"vpc": {
"main": 11250838,
"bonus": 12345,
"vk_rub": 0,
"prediction": null,
"debt": 0,
"sum": 11150838
},
"vmware": {
"main": 10000,
"bonus": 10000,
"vk_rub": 0,
"prediction": null,
"debt": 0,
"sum": 20000
}
]
}
}
}

2 comments on commit 6d193ef

@lspresent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert selectelBillingResponse struct

@mxssl
Copy link
Owner Author

@mxssl mxssl commented on 6d193ef Sep 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lspresent

It seems that there is a new response structure:

{
  "status": "success",
  "data": {
    "settings": {
      "mode": "prepay",
      "avaliable_billings": [
        "primary"
      ],
      "avaliable_balances": [
        "vk_rub",
        "bonus",
        "main"
      ],
      "currency": "rub",
      "full_user": true
    },
    "billings": [
      {
        "billing_type": "primary",
        "balances_values_sum": 31214604,
        "debt": [
          {
            "service_id": 300500,
            "service_type": "vpc",
            "debt_value": 0
          },
          {
            "service_id": 800500,
            "service_type": "dbaas",
            "debt_value": 0
          },
          {
            "service_id": 1000500,
            "service_type": "craas",
            "debt_value": 0
          },
          {
            "service_id": 900500,
            "service_type": "serverless",
            "debt_value": 0
          },
          {
            "service_id": 700500,
            "service_type": "mks",
            "debt_value": 0
          },
          {
            "service_id": 500500,
            "service_type": "vmware",
            "debt_value": 0
          },
          {
            "service_id": 600500,
            "service_type": "cdn",
            "debt_value": 0
          },
          {
            "service_id": 200500,
            "service_type": "storage",
            "debt_value": 0
          }
        ],
        "final_sum": 31214604,
        "debt_sum": 0,
        "balances": [
          {
            "balance_id": 322836,
            "balance_type": "vk_rub",
            "value": 0
          },
          {
            "balance_id": 322834,
            "balance_type": "main",
            "value": 31214604
          },
          {
            "balance_id": 322835,
            "balance_type": "bonus",
            "value": 0
          }
        ]
      }
    ],
    "debt_status": "Success"
  }
}

Code tested over this new structure

Please sign in to comment.