some clean up
added Makefile
This commit is contained in:
parent
8f1463b2ef
commit
5d5c779b43
8 changed files with 98 additions and 43 deletions
44
Makefile
Normal file
44
Makefile
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
SHELL := /bin/bash
|
||||||
|
|
||||||
|
TARGET := hetzner-sb-notifier
|
||||||
|
.DEFAULT_GOAL: $(TARGET)
|
||||||
|
|
||||||
|
# These will be provided to the target
|
||||||
|
VERSION := 1.0.0
|
||||||
|
BUILD := `git rev-parse HEAD`
|
||||||
|
|
||||||
|
.PHONY: all build clean uninstall fmt simplify check run
|
||||||
|
|
||||||
|
all: check build
|
||||||
|
|
||||||
|
$(TARGET):
|
||||||
|
@go build -o $(TARGET)
|
||||||
|
|
||||||
|
build: $(TARGET)
|
||||||
|
@true
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo "Performing clean"
|
||||||
|
@rm -f $(TARGET)
|
||||||
|
|
||||||
|
uninstall: clean
|
||||||
|
@echo "Performing uninstall"
|
||||||
|
@rm -f $$(which ${TARGET})
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
@echo "Performing fmt"
|
||||||
|
@gofmt -l -w .
|
||||||
|
|
||||||
|
simplify:
|
||||||
|
@echo "Performing simplify"
|
||||||
|
@gofmt -s -l -w .
|
||||||
|
|
||||||
|
check:
|
||||||
|
@echo "Performing check"
|
||||||
|
@test -z $(shell gofmt -l main.go | tee /dev/stderr) || echo "[WARN] Fix formatting issues with 'make fmt'"
|
||||||
|
@for d in $$(go list ./...); do golint $${d}; done
|
||||||
|
@go tool vet .
|
||||||
|
|
||||||
|
run: install
|
||||||
|
@echo "Performing run"
|
||||||
|
@$(TARGET)
|
28
Readme.md
28
Readme.md
|
@ -1,6 +1,10 @@
|
||||||
|
The aim of my-bloody-hetzner-sb-notifier is a simple CLI to fetch the current Hetzner Serverbörse deals and filter them according to CLI parameters sorted by score.
|
||||||
|
|
||||||
|
The score is calculated from the amount of HDD space as well as RAM and CPU-Benchnmark for better comparability.
|
||||||
|
|
||||||
|
The CLI interface looks like this:
|
||||||
````
|
````
|
||||||
Usage of my-bloody-hetzner-sb-notifier:
|
Usage of hetzner-sb-notifier:
|
||||||
-alert-on-score int
|
-alert-on-score int
|
||||||
set alert on score
|
set alert on score
|
||||||
-max-benchmark int
|
-max-benchmark int
|
||||||
|
@ -23,11 +27,19 @@ Usage of my-bloody-hetzner-sb-notifier:
|
||||||
set min price
|
set min price
|
||||||
-min-ram int
|
-min-ram int
|
||||||
set min ram
|
set min ram
|
||||||
-notifier-password string
|
|
||||||
set notifier password
|
|
||||||
-notifier-recipient string
|
|
||||||
set notifier recipient
|
|
||||||
-notifier-sender string
|
|
||||||
set notifier sender
|
|
||||||
|
|
||||||
````
|
````
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
./hetzner-sb-notifier --max-price 77 --min-ram 128 --min-hdd-count 2 --min-hdd-size 4096
|
||||||
|
````
|
||||||
|
Got 545 offers. Filtered offers: 3
|
||||||
|
ID| Ram| HDD| CPU| Price| Score| Reduce time|Specials
|
||||||
|
SB64-935022| 128 GB| 2x 2 TB (4096)| Intel Xeon E5-1650V2 (12518)| 64.00 €| 91.84| 47h 48m|ECC, Ent. HDD, iNIC
|
||||||
|
SB72-927788| 128 GB| 2x 2 TB (4096)| Intel Xeon E5-1650V3 (13335)| 72.00 €| 86.17| 21h 08m|ECC, Ent. HDD, iNIC
|
||||||
|
SB73-910394| 128 GB| 3x 2 TB (6144)| Intel Xeon E5-1650V2 (12518)| 73.00 €| 86.13| 03h 04m|ECC, Ent. HDD, iNIC
|
||||||
|
````
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
The Go project uses Go Modules
|
|
@ -12,7 +12,7 @@ type Client struct {
|
||||||
|
|
||||||
func NewClient() *Client {
|
func NewClient() *Client {
|
||||||
crawler := &Client{
|
crawler := &Client{
|
||||||
&http.Client{Timeout: 10 * time.Second} ,
|
&http.Client{Timeout: 10 * time.Second},
|
||||||
}
|
}
|
||||||
|
|
||||||
return crawler
|
return crawler
|
||||||
|
|
|
@ -67,16 +67,15 @@ func (c *Crawler) Print(servers []hetzner.Server) {
|
||||||
c.tabWriter.Flush()
|
c.tabWriter.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (c *Crawler) isFiltered(server hetzner.Server) bool {
|
func (c *Crawler) isFiltered(server hetzner.Server) bool {
|
||||||
filtered := true
|
filtered := true
|
||||||
|
|
||||||
priceParsed := server.ParsePrice()
|
priceParsed := server.ParsePrice()
|
||||||
if server.Cpu_benchmark >= c.minBenchmark && server.Cpu_benchmark <= c.maxBenchmark &&
|
if server.CpuBenchmark >= c.minBenchmark && server.CpuBenchmark <= c.maxBenchmark &&
|
||||||
priceParsed >= c.minPrice && priceParsed <= c.maxPrice &&
|
priceParsed >= c.minPrice && priceParsed <= c.maxPrice &&
|
||||||
server.Ram >= c.minRam && server.Ram <= c.maxRam &&
|
server.Ram >= c.minRam && server.Ram <= c.maxRam &&
|
||||||
server.TotalHdd() >= c.minHddSize && server.TotalHdd() <= c.maxHddSize &&
|
server.TotalHdd() >= c.minHddSize && server.TotalHdd() <= c.maxHddSize &&
|
||||||
server.Hdd_count >= c.minHddCount && server.Hdd_count <= c.maxHddCount {
|
server.HddCount >= c.minHddCount && server.HddCount <= c.maxHddCount {
|
||||||
filtered = false
|
filtered = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,6 @@ import (
|
||||||
|
|
||||||
const hetznerlivedataurl = "https://www.hetzner.de/a_hz_serverboerse/live_data.json"
|
const hetznerlivedataurl = "https://www.hetzner.de/a_hz_serverboerse/live_data.json"
|
||||||
|
|
||||||
func MakeUrl() string {
|
func MakeURL() string {
|
||||||
return fmt.Sprintf("%s?m=%v", hetznerlivedataurl, time.Now().UnixNano())
|
return fmt.Sprintf("%s?m=%v", hetznerlivedataurl, time.Now().UnixNano())
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,45 +19,45 @@ type Server struct {
|
||||||
Datacenter []string `json:"datacenter"`
|
Datacenter []string `json:"datacenter"`
|
||||||
Specials []string `json:"specials"`
|
Specials []string `json:"specials"`
|
||||||
Traffic string `json:"traffic"`
|
Traffic string `json:"traffic"`
|
||||||
Bandwith int `json:"bandwith"`
|
Bandwidth int `json:"bandwith"`
|
||||||
|
|
||||||
Price string `json:"price"`
|
Price string `json:"price"`
|
||||||
Price_v string `json:"price_v"`
|
PriceV string `json:"price_v"`
|
||||||
Setup_price string `json:"setup_price"`
|
SetupPrice string `json:"setup_price"`
|
||||||
|
|
||||||
Cpu string `json:"cpu"`
|
Cpu string `json:"cpu"`
|
||||||
Cpu_benchmark int `json:"cpu_benchmark"`
|
CpuBenchmark int `json:"cpu_benchmark"`
|
||||||
Cpu_count int `json:"cpu_count"`
|
CpuCount int `json:"cpu_count"`
|
||||||
Ram int `json:"ram"`
|
Ram int `json:"ram"`
|
||||||
Ram_hr string `json:"ram_hr"`
|
RamHr string `json:"ram_hr"`
|
||||||
Hdd_size int `json:"hdd_size"`
|
HddSize int `json:"hdd_size"`
|
||||||
Hdd_hr string `json:"hdd_hr"`
|
HddHr string `json:"hdd_hr"`
|
||||||
Hdd_count int `json:"hdd_count"`
|
HddCount int `json:"hdd_count"`
|
||||||
SpecialHdd string `json:"specialHdd"`
|
SpecialHdd string `json:"specialHdd"`
|
||||||
|
|
||||||
Next_reduce int `json:"next_reduce"`
|
NextReduce int `json:"next_reduce"`
|
||||||
Next_reduce_hr string `json:"next_reduce_hr"`
|
NextReduceHr string `json:"next_reduce_hr"`
|
||||||
|
|
||||||
Fixed_price bool `json:"fixed_price"`
|
FixedPrice bool `json:"fixed_price"`
|
||||||
Is_highio bool `json:"is_highio"`
|
IsHighio bool `json:"is_highio"`
|
||||||
Is_ecc bool `json:"is_ecc"`
|
IsEcc bool `json:"is_ecc"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) TotalHdd() int {
|
func (s *Server) TotalHdd() int {
|
||||||
return s.Hdd_count*s.Hdd_size
|
return s.HddCount * s.HddSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Score() float64 {
|
func (s *Server) Score() float64 {
|
||||||
return (float64(s.TotalHdd())*0.2 + float64(s.Ram)*0.4 + float64(s.Cpu_benchmark)*0.4)/s.ParsePrice()
|
return (float64(s.TotalHdd())*0.2 + float64(s.Ram)*0.4 + float64(s.CpuBenchmark)*0.4) / s.ParsePrice()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ParsePrice() float64 {
|
func (s *Server) ParsePrice() float64 {
|
||||||
priceParsed, err := strconv.ParseFloat(s.Price, 32)
|
priceParsed, err := strconv.ParseFloat(s.Price, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Could not parse price %s for server %s: %s", s.Price, s.Key, err)
|
fmt.Printf("Could not parse price %s for server %d: %s", s.Price, s.Key, err)
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return priceParsed*1.19
|
return priceParsed * 1.19
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Header() string {
|
func (s *Server) Header() string {
|
||||||
|
@ -66,9 +66,9 @@ func (s *Server) Header() string {
|
||||||
|
|
||||||
func (s *Server) ToString() string {
|
func (s *Server) ToString() string {
|
||||||
fixedPriceSymbol := "*"
|
fixedPriceSymbol := "*"
|
||||||
if !s.Fixed_price {
|
if !s.FixedPrice {
|
||||||
fixedPriceSymbol = ""
|
fixedPriceSymbol = ""
|
||||||
}
|
}
|
||||||
specials := strings.Join(s.Specials, ", ")
|
specials := strings.Join(s.Specials, ", ")
|
||||||
return fmt.Sprintf("%s-%d\t%s\t%s (%d)\t%s (%d)\t%.2f €%s\t%.2f\t%s\t%s", s.Name, s.Key, s.Ram_hr, s.Hdd_hr, s.TotalHdd(), s.Cpu, s.Cpu_benchmark, s.ParsePrice(), fixedPriceSymbol, s.Score(), s.Next_reduce_hr, specials)
|
return fmt.Sprintf("%s-%d\t%s\t%s (%d)\t%s (%d)\t%.2f €%s\t%.2f\t%s\t%s", s.Name, s.Key, s.RamHr, s.HddHr, s.TotalHdd(), s.Cpu, s.CpuBenchmark, s.ParsePrice(), fixedPriceSymbol, s.Score(), s.NextReduceHr, specials)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package instrumentation
|
package instrumentation
|
||||||
|
|
||||||
type Instrumenter struct{
|
type Instrumenter struct {
|
||||||
projectId string
|
projectID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInstrumenter(projectId string) *Instrumenter {
|
func NewInstrumenter(projectID string) *Instrumenter {
|
||||||
return &Instrumenter{
|
return &Instrumenter{
|
||||||
projectId: projectId,
|
projectID: projectID,
|
||||||
}
|
}
|
||||||
}
|
}
|
2
main.go
2
main.go
|
@ -75,7 +75,7 @@ func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
offers := &hetzner.Offers{}
|
offers := &hetzner.Offers{}
|
||||||
err := client.NewClient().DoRequest(hetzner.MakeUrl(), offers)
|
err := client.NewClient().DoRequest(hetzner.MakeURL(), offers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("failed to get hetzner live data: %s", err))
|
panic(fmt.Errorf("failed to get hetzner live data: %s", err))
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue