-
Notifications
You must be signed in to change notification settings - Fork 7
/
meta.go
170 lines (139 loc) · 4.88 KB
/
meta.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
164
165
166
167
168
169
170
package main
import (
"fmt"
ecsService "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/fatih/color"
"sort"
"strings"
"time"
)
const (
TimeLayout = "2006-01-02T15:04:05Z"
)
type MetaStore struct {
*ecsService.Client
InstanceFamilyCache map[string]ecsService.InstanceType
}
// Initialize the instance type
func (ms *MetaStore) Initialize(region string) {
req := ecsService.CreateDescribeInstanceTypesRequest()
req.RegionId = region
resp, err := ms.DescribeInstanceTypes(req)
if err != nil {
panic(fmt.Sprintf("Failed to DescribeInstanceTypes,because of %v", err))
}
instanceTypes := resp.InstanceTypes.InstanceType
for _, instanceType := range instanceTypes {
ms.InstanceFamilyCache[instanceType.InstanceTypeId] = instanceType
}
d_req := ecsService.CreateDescribeAvailableResourceRequest()
d_req.RegionId = region
d_req.DestinationResource = "InstanceType"
d_req.InstanceChargeType = "PostPaid"
d_req.SpotStrategy = "SpotWithPriceLimit"
d_resp, err := ms.DescribeAvailableResource(d_req)
if err != nil {
panic(fmt.Sprintf("Failed to get available resource,because of %v", err))
}
zoneStocks := d_resp.AvailableZones.AvailableZone
for instanceTypeId := range ms.InstanceFamilyCache {
found := 0
for _, zoneStock := range zoneStocks {
for _, resource := range zoneStock.AvailableResources.AvailableResource[0].SupportedResources.SupportedResource {
if resource.Value == instanceTypeId {
found = 1
break
}
}
if found == 1 {
break
}
}
if found == 0 {
delete(ms.InstanceFamilyCache, instanceTypeId)
}
}
fmt.Printf("Initialize cache ready with %d kinds of instanceTypes\n", len(instanceTypes))
}
// Get the instanceType with in the range.
func (ms *MetaStore) FilterInstances(cpu, memory, maxCpu, maxMemory int, family string) (instanceTypes []string) {
instanceTypes = make([]string, 0)
instancesFamily := strings.Split(family, ",")
for key, instanceType := range ms.InstanceFamilyCache {
if instanceType.CpuCoreCount >= cpu && instanceType.CpuCoreCount <= maxCpu &&
instanceType.MemorySize >= float64(memory) && instanceType.MemorySize <= float64(maxMemory) {
for _, instanceFamily := range instancesFamily {
if strings.Contains(key, instanceFamily) {
instanceTypes = append(instanceTypes, key)
break
}
}
}
}
fmt.Printf("Filter %d of %d kinds of instanceTypes.\n", len(instanceTypes), len(ms.InstanceFamilyCache))
return instanceTypes
}
// Fetch spot price history
func (ms *MetaStore) FetchSpotPrices(instanceTypes []string, resolution int) (historyPrices map[string][]ecsService.SpotPriceType) {
historyPrices = make(map[string][]ecsService.SpotPriceType)
for _, instanceType := range instanceTypes {
req := ecsService.CreateDescribeSpotPriceHistoryRequest()
req.NetworkType = "vpc"
req.InstanceType = instanceType
req.IoOptimized = "optimized"
resp, err := ms.DescribeSpotPriceHistory(req)
resolutionDuration := time.Duration(resolution * -1*24) * time.Hour
req.StartTime = time.Now().Add(resolutionDuration).Format(TimeLayout)
if err != nil {
continue
}
historyPrices[instanceType] = resp.SpotPrices.SpotPriceType
}
fmt.Printf("Fetch %d kinds of InstanceTypes prices successfully.\n", len(instanceTypes))
return historyPrices
}
// Print spot history sort and rank
func (ms *MetaStore) SpotPricesAnalysis(historyPrices map[string][]ecsService.SpotPriceType) SortedInstancePrices {
sp := make(SortedInstancePrices, 0)
for instanceTypeId, prices := range historyPrices {
var meta ecsService.InstanceType
if m, ok := ms.InstanceFamilyCache[instanceTypeId]; !ok {
continue
} else {
meta = m
}
priceAZMap := make(map[string][]ecsService.SpotPriceType)
for _, price := range prices {
if priceAZMap[price.ZoneId] == nil {
priceAZMap[price.ZoneId] = make([]ecsService.SpotPriceType, 0)
}
priceAZMap[price.ZoneId] = append(priceAZMap[price.ZoneId], price)
}
for zoneId, price := range priceAZMap {
ip := CreateInstancePrice(meta, zoneId, price)
sp = append(sp, ip)
}
}
fmt.Printf("Successfully compare %d kinds of instanceTypes\n", len(sp))
return sp
}
func (ms *MetaStore) PrintPriceRank(prices SortedInstancePrices, cutoff int, limit int) {
sort.Sort(prices)
color.Green("%30s %20s %15s %15s %15s\n", "InstanceTypeId", "ZoneId", "Price(Core)", "Discount", "ratio")
for index, price := range prices {
if index >= limit {
break
}
if price.Discount <= float64(cutoff) {
color.Green("%30s %20s %15.4f %15.1f %15.1f\n", price.InstanceTypeId, price.ZoneId, price.PricePerCore, price.Discount, price.Possibility)
} else {
color.Blue("%30s %20s %15.4f %15.1f %15.1f\n", price.InstanceTypeId, price.ZoneId, price.PricePerCore, price.Discount, price.Possibility)
}
}
}
func NewMetaStore(client *ecsService.Client) *MetaStore {
return &MetaStore{
Client: client,
InstanceFamilyCache: make(map[string]ecsService.InstanceType),
}
}