-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathdb_instance.go
163 lines (142 loc) · 4.49 KB
/
db_instance.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package store
import (
"encoding/json"
"fmt"
"os"
"strconv"
"github.com/bytebase/dbcost/client"
)
// TermPayload is the payload of the term
type TermPayload struct {
// e.g. 3ys 1ms
LeaseContractLength string `json:"leaseContractLength"`
// e.g. All Upfront, Partail Upfront
PurchaseOption string `json:"purchaseOption"`
}
// Term is the pricing term of a given instance
type Term struct {
Code string `json:"code"`
DatabaseEngine client.EngineType `json:"databaseEngine"`
Type client.ChargeType `json:"type"`
Payload *TermPayload `json:"payload"`
HourlyUSD float64 `json:"hourlyUSD"`
CommitmentUSD float64 `json:"commitmentUSD"`
}
// Region is region-price info of a given instance
type Region struct {
Code string `json:"code"`
TermList []*Term `json:"termList"`
}
// DBInstance is the type of DBInstance
type DBInstance struct {
// system fields
ID int `json:"id"`
RowStatus RowStatus `json:"rowStatus"`
CreatorID int `json:"creatorId"`
UpdaterID int `json:"updaterId"`
// Region-Price info
RegionList []*Region `json:"regionList"`
// domain fields
CloudProvider string `json:"cloudProvider"`
Name string `json:"name"`
CPU int `json:"cpu"`
Memory string `json:"memory"`
Processor string `json:"processor"`
}
// Convert convert the offer provided by client to DBInstance
func Convert(offerList []*client.Offer, cloudProvider CloudProvider) ([]*DBInstance, error) {
termMap := make(map[int][]*Term)
for _, offer := range offerList {
// filter the offer does not have a instancePayload (only got price but no goods).
if offer.InstancePayload == nil {
continue
}
var termPayload *TermPayload
// Only reserved type has payload field
if offer.ChargeType == client.ChargeTypeReserved {
termPayload = &TermPayload{
LeaseContractLength: offer.ChargePayload.LeaseContractLength,
PurchaseOption: offer.ChargePayload.PurchaseOption,
}
}
term := &Term{
Code: offer.TermCode,
DatabaseEngine: offer.InstancePayload.DatabaseEngine,
Type: offer.ChargeType,
Payload: termPayload,
HourlyUSD: offer.HourlyUSD,
CommitmentUSD: offer.CommitmentUSD,
}
termMap[offer.ID] = append(termMap[offer.ID], term)
}
incrID := 0
// dbInstanceMap is used to aggregate the instance by their type (e.g. db.m3.large).
dbInstanceMap := make(map[string]*DBInstance)
var dbInstanceList []*DBInstance
// extract dbInstance from the payload field stored in the offer.
for _, offer := range offerList {
// filter the offer does not have a instancePayload (only got price but no goods).
if offer.InstancePayload == nil {
continue
}
instance := offer.InstancePayload
cpuInt, err := strconv.Atoi(instance.CPU)
if err != nil {
return nil, fmt.Errorf("Fail to parse the CPU value from string to int, [val]: %v", instance.CPU)
}
memoryDigit := instance.Memory
// we use the instance type (e.g. db.m3.xlarge) differentiate the specification of each instances,
// and consider they as the same instance.
if _, ok := dbInstanceMap[instance.Type]; !ok {
dbInstance := &DBInstance{
ID: incrID,
RowStatus: RowStatusNormal,
CreatorID: SYSTEM_BOT,
UpdaterID: SYSTEM_BOT,
CloudProvider: cloudProvider.String(),
Name: instance.Type, // e.g. db.t4g.xlarge
CPU: cpuInt,
Memory: memoryDigit,
Processor: instance.PhysicalProcessor,
}
dbInstanceList = append(dbInstanceList, dbInstance)
dbInstanceMap[instance.Type] = dbInstance
incrID++
}
// fill in the term info of the instance
dbInstance := dbInstanceMap[instance.Type]
for _, regionCode := range offer.RegionList {
isRegionExist := false
for _, region := range dbInstance.RegionList {
if region.Code == regionCode {
isRegionExist = true
if _, ok := termMap[offer.ID]; ok {
region.TermList = append(region.TermList, termMap[offer.ID]...)
}
}
}
if !isRegionExist {
dbInstance.RegionList = append(dbInstance.RegionList, &Region{
Code: regionCode,
TermList: termMap[offer.ID],
})
}
}
}
return dbInstanceList, nil
}
// Save save DBInstanceList to local .json file
func Save(dbInstanceList []*DBInstance, filePath string) error {
fd, err := os.Create(filePath)
if err != nil {
return err
}
dataByted, err := json.Marshal(dbInstanceList)
if err != nil {
return err
}
if _, err := fd.Write(dataByted); err != nil {
return err
}
return fd.Close()
}