add python compatibility module
[multicloud/k8s.git] / src / dcm / pkg / module / quota.go
1 /*
2 * Copyright 2020 Intel Corporation, Inc
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15  */
16
17 package module
18
19 import (
20         pkgerrors "github.com/pkg/errors"
21 )
22
23 // Quota contains the parameters needed for a Quota
24 type Quota struct {
25         MetaData QMetaDataList `json:"metadata"`
26         // Specification QSpec         `json:"spec"`
27         Specification map[string]string `json:"spec"`
28 }
29
30 // MetaData contains the parameters needed for metadata
31 type QMetaDataList struct {
32         QuotaName   string `json:"name"`
33         Description string `json:"description"`
34 }
35
36 // TODO: use QSpec fields to validate quota keys
37 // Spec contains the parameters needed for spec
38 type QSpec struct {
39         LimitsCPU                   string `json:"limits.cpu"`
40         LimitsMemory                string `json:"limits.memory"`
41         RequestsCPU                 string `json:"requests.cpu"`
42         RequestsMemory              string `json:"requests.memory"`
43         RequestsStorage             string `json:"requests.storage"`
44         LimitsEphemeralStorage      string `json:"limits.ephemeral.storage"`
45         PersistentVolumeClaims      string `json:"persistentvolumeclaims"`
46         Pods                        string `json:"pods"`
47         ConfigMaps                  string `json:"configmaps"`
48         ReplicationControllers      string `json:"replicationcontrollers"`
49         ResourceQuotas              string `json:"resourcequotas"`
50         Services                    string `json:"services"`
51         ServicesLoadBalancers       string `json:"services.loadbalancers"`
52         ServicesNodePorts           string `json:"services.nodeports"`
53         Secrets                     string `json:"secrets"`
54         CountReplicationControllers string `json:"count/replicationcontrollers"`
55         CountDeploymentsApps        string `json:"count/deployments.apps"`
56         CountReplicasetsApps        string `json:"count/replicasets.apps"`
57         CountStatefulSets           string `json:"count/statefulsets.apps"`
58         CountJobsBatch              string `json:"count/jobs.batch"`
59         CountCronJobsBatch          string `json:"count/cronjobs.batch"`
60         CountDeploymentsExtensions  string `json:"count/deployments.extensions"`
61 }
62
63 // QuotaKey is the key structure that is used in the database
64 type QuotaKey struct {
65         Project          string `json:"project"`
66         LogicalCloudName string `json:"logical-cloud-name"`
67         QuotaName        string `json:"qname"`
68 }
69
70 // QuotaManager is an interface that exposes the connection
71 // functionality
72 type QuotaManager interface {
73         CreateQuota(project, logicalCloud string, c Quota) (Quota, error)
74         GetQuota(project, logicalCloud, name string) (Quota, error)
75         GetAllQuotas(project, logicalCloud string) ([]Quota, error)
76         DeleteQuota(project, logicalCloud, name string) error
77         UpdateQuota(project, logicalCloud, name string, c Quota) (Quota, error)
78 }
79
80 // QuotaClient implements the QuotaManager
81 // It will also be used to maintain some localized state
82 type QuotaClient struct {
83         storeName string
84         tagMeta   string
85         util      Utility
86 }
87
88 // QuotaClient returns an instance of the QuotaClient
89 // which implements the QuotaManager
90 func NewQuotaClient() *QuotaClient {
91         service := DBService{}
92         return &QuotaClient{
93                 storeName: "orchestrator",
94                 tagMeta:   "quota",
95                 util:      service,
96         }
97 }
98
99 // Create entry for the quota resource in the database
100 func (v *QuotaClient) CreateQuota(project, logicalCloud string, c Quota) (Quota, error) {
101
102         //Construct key consisting of name
103         key := QuotaKey{
104                 Project:          project,
105                 LogicalCloudName: logicalCloud,
106                 QuotaName:        c.MetaData.QuotaName,
107         }
108
109         //Check if project exists
110         err := v.util.CheckProject(project)
111         if err != nil {
112                 return Quota{}, pkgerrors.New("Unable to find the project")
113         }
114         //check if logical cloud exists
115         err = v.util.CheckLogicalCloud(project, logicalCloud)
116         if err != nil {
117                 return Quota{}, pkgerrors.New("Unable to find the logical cloud")
118         }
119         //Check if this Quota already exists
120         _, err = v.GetQuota(project, logicalCloud, c.MetaData.QuotaName)
121         if err == nil {
122                 return Quota{}, pkgerrors.New("Quota already exists")
123         }
124
125         err = v.util.DBInsert(v.storeName, key, nil, v.tagMeta, c)
126         if err != nil {
127                 return Quota{}, pkgerrors.Wrap(err, "Creating DB Entry")
128         }
129
130         return c, nil
131 }
132
133 // Get returns Quota for corresponding quota name
134 func (v *QuotaClient) GetQuota(project, logicalCloud, quotaName string) (Quota, error) {
135
136         //Construct the composite key to select the entry
137         key := QuotaKey{
138                 Project:          project,
139                 LogicalCloudName: logicalCloud,
140                 QuotaName:        quotaName,
141         }
142         value, err := v.util.DBFind(v.storeName, key, v.tagMeta)
143         if err != nil {
144                 return Quota{}, pkgerrors.Wrap(err, "Quota")
145         }
146
147         //value is a byte array
148         if value != nil {
149                 q := Quota{}
150                 err = v.util.DBUnmarshal(value[0], &q)
151                 if err != nil {
152                         return Quota{}, pkgerrors.Wrap(err, "Unmarshaling value")
153                 }
154                 return q, nil
155         }
156
157         return Quota{}, pkgerrors.New("Cluster Quota does not exist")
158 }
159
160 // GetAll returns all cluster quotas in the logical cloud
161 func (v *QuotaClient) GetAllQuotas(project, logicalCloud string) ([]Quota, error) {
162         //Construct the composite key to select the entry
163         key := QuotaKey{
164                 Project:          project,
165                 LogicalCloudName: logicalCloud,
166                 QuotaName:        "",
167         }
168         var resp []Quota
169         values, err := v.util.DBFind(v.storeName, key, v.tagMeta)
170         if err != nil {
171                 return []Quota{}, pkgerrors.Wrap(err, "Get All Quotas")
172         }
173
174         for _, value := range values {
175                 q := Quota{}
176                 err = v.util.DBUnmarshal(value, &q)
177                 if err != nil {
178                         return []Quota{}, pkgerrors.Wrap(err, "Unmarshaling value")
179                 }
180                 resp = append(resp, q)
181         }
182
183         return resp, nil
184 }
185
186 // Delete the Quota entry from database
187 func (v *QuotaClient) DeleteQuota(project, logicalCloud, quotaName string) error {
188         //Construct the composite key to select the entry
189         key := QuotaKey{
190                 Project:          project,
191                 LogicalCloudName: logicalCloud,
192                 QuotaName:        quotaName,
193         }
194         err := v.util.DBRemove(v.storeName, key)
195         if err != nil {
196                 return pkgerrors.Wrap(err, "Delete Quota")
197         }
198         return nil
199 }
200
201 // Update an entry for the Quota in the database
202 func (v *QuotaClient) UpdateQuota(project, logicalCloud, quotaName string, c Quota) (Quota, error) {
203
204         key := QuotaKey{
205                 Project:          project,
206                 LogicalCloudName: logicalCloud,
207                 QuotaName:        quotaName,
208         }
209         //Check quota URL name against the quota json name
210         if c.MetaData.QuotaName != quotaName {
211                 return Quota{}, pkgerrors.New("Update Error - Quota name mismatch")
212         }
213         //Check if this Quota exists
214         _, err := v.GetQuota(project, logicalCloud, quotaName)
215         if err != nil {
216                 return Quota{}, pkgerrors.New("Cluster Quota does not exist")
217         }
218         err = v.util.DBInsert(v.storeName, key, nil, v.tagMeta, c)
219         if err != nil {
220                 return Quota{}, pkgerrors.Wrap(err, "Updating DB Entry")
221         }
222         return c, nil
223 }