forked from openshift/osde2e
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathquota.go
More file actions
139 lines (119 loc) · 4.13 KB
/
quota.go
File metadata and controls
139 lines (119 loc) · 4.13 KB
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
package osd
import (
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"path"
accounts "github.com/openshift-online/ocm-sdk-go/accountsmgmt/v1"
osderrors "github.com/openshift-online/ocm-sdk-go/errors"
"github.com/openshift/osde2e/pkg/config"
)
const (
// ResourceAWSCluster is the quota resource type for a cluster on AWS.
ResourceAWSCluster = "cluster.aws"
)
// CheckQuota determines if enough quota is available to launch with cfg.
func (u *OSD) CheckQuota() (bool, error) {
// get flavour being deployed
flavourID := u.Flavour()
flavourReq, err := u.conn.ClustersMgmt().V1().Flavours().Flavour(flavourID).Get().Send()
if err == nil && flavourReq != nil {
err = errResp(flavourReq.Error())
if err != nil {
return false, err
}
} else if flavourReq == nil || flavourReq.Body().Empty() {
return false, errors.New("returned flavour can't be empty")
}
flavour := flavourReq.Body()
// get quota
quotaList, err := u.CurrentAccountQuota()
if err != nil {
return false, fmt.Errorf("could not get quota: %v", err)
}
// TODO: use compute_machine_type when available in OCM SDK
_ = flavour.Nodes()
machineType := ""
quotaFound := false
quotaList.Each(func(q *accounts.ResourceQuota) bool {
if quotaFound = HasQuotaFor(q, ResourceAWSCluster, machineType); quotaFound {
log.Printf("Quota for test config (%s/%s/multiAZ=%t) found: total=%d, remaining: %d",
ResourceAWSCluster, machineType, config.Instance.Cluster.MultiAZ, q.Allowed(), q.Allowed()-q.Reserved())
}
return !quotaFound
})
return quotaFound, nil
}
// CurrentAccountQuota returns quota available for the current account's organization in the environment.
func (u *OSD) CurrentAccountQuota() (*accounts.ResourceQuotaList, error) {
acc, err := u.CurrentAccount()
if err != nil || acc == nil {
return nil, fmt.Errorf("couldn't get current account: %v", err)
} else if acc.Organization() == nil || acc.Organization().ID() == "" {
return nil, fmt.Errorf("organization for account '%s' must be set to get quota", acc.ID())
}
orgID := acc.Organization().ID()
quotaList, err := u.getQuotaSummary(orgID)
if err == nil && quotaList != nil {
err = errResp(quotaList.Error())
} else if quotaList == nil {
return nil, errors.New("QuotaList can't be nil")
}
return quotaList.Items(), err
}
// HasQuotaFor the desired configuration. If machineT is empty a default will try to be selected.
func HasQuotaFor(q *accounts.ResourceQuota, resourceType, machineType string) bool {
azType := "single"
if config.Instance.Cluster.MultiAZ {
azType = "multi"
}
if q.ResourceType() == resourceType && q.ResourceName() == machineType || machineType == "" {
if q.AvailabilityZoneType() == azType {
if q.Reserved() < q.Allowed() {
return true
}
}
}
return false
}
// TODO: use ocm-sdk-go resource_summary method once available
func (u *OSD) getQuotaSummary(orgID string) (*resourceSummaryListResponse, error) {
resp := new(resourceSummaryListResponse)
summaryPath := path.Join("/api/accounts_mgmt", APIVersion, "organizations", orgID, "quota_summary")
rawResp, err := u.conn.Get().Path(summaryPath).Send()
if err == nil && rawResp.Status() != http.StatusOK {
resp.err, err = osderrors.UnmarshalError(rawResp.Bytes())
} else if rawResp != nil {
err = json.Unmarshal(rawResp.Bytes(), resp)
}
if err != nil {
return resp, err
}
// allow reading QuotaSummary as ResourceQuota
for i := range resp.List {
resp.List[i]["kind"] = "ResourceQuota"
}
// convert formats by writing to bytes and unmarshalling typed
var listData []byte
if listData, err = json.Marshal(resp.List); err == nil {
resp.list, err = accounts.UnmarshalResourceQuotaList(listData)
}
return resp, err
}
type resourceSummaryListResponse struct {
Kind string `json:"kind"`
Page int `json:"page"`
Size int `json:"size"`
Total int `json:"total"`
List []map[string]interface{} `json:"items"`
list *accounts.ResourceQuotaList
err *osderrors.Error
}
func (r *resourceSummaryListResponse) Items() *accounts.ResourceQuotaList {
return r.list
}
func (r *resourceSummaryListResponse) Error() *osderrors.Error {
return r.err
}