Implement Terminate operation in DCM
[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 }
28
29 // MetaData contains the parameters needed for metadata
30 type QMetaDataList struct {
31         QuotaName   string `json:"name"`
32         Description string `json:"description"`
33 }
34
35 // Spec contains the parameters needed for spec
36 type QSpec struct {
37         LimitsCPU                   string `json:"limits.cpu"`
38         LimitsMemory                string `json:"limits.memory"`
39         RequestsCPU                 string `json:"requests.cpu"`
40         RequestsMemory              string `json:"requests.memory"`
41         RequestsStorage             string `json:"requests.storage"`
42         LimitsEphemeralStorage      string `json:"limits.ephemeral.storage"`
43         PersistentVolumeClaims      string `json:"persistentvolumeclaims"`
44         Pods                        string `json:"pods"`
45         ConfigMaps                  string `json:"configmaps"`
46         ReplicationControllers      string `json:"replicationcontrollers"`
47         ResourceQuotas              string `json:"resourcequotas"`
48         Services                    string `json:"services"`
49         ServicesLoadBalancers       string `json:"services.loadbalancers"`
50         ServicesNodePorts           string `json:"services.nodeports"`
51         Secrets                     string `json:"secrets"`
52         CountReplicationControllers string `json:"count/replicationcontrollers"`
53         CountDeploymentsApps        string `json:"count/deployments.apps"`
54         CountReplicasetsApps        string `json:"count/replicasets.apps"`
55         CountStatefulSets           string `json:"count/statefulsets.apps"`
56         CountJobsBatch              string `json:"count/jobs.batch"`
57         CountCronJobsBatch          string `json:"count/cronjobs.batch"`
58         CountDeploymentsExtensions  string `json:"count/deployments.extensions"`
59 }
60
61 // QuotaKey is the key structure that is used in the database
62 type QuotaKey struct {
63         Project          string `json:"project"`
64         LogicalCloudName string `json:"logical-cloud-name"`
65         QuotaName        string `json:"qname"`
66 }
67
68 // QuotaManager is an interface that exposes the connection
69 // functionality
70 type QuotaManager interface {
71         CreateQuota(project, logicalCloud string, c Quota) (Quota, error)
72         GetQuota(project, logicalCloud, name string) (Quota, error)
73         GetAllQuotas(project, logicalCloud string) ([]Quota, error)
74         DeleteQuota(project, logicalCloud, name string) error
75         UpdateQuota(project, logicalCloud, name string, c Quota) (Quota, error)
76 }
77
78 // QuotaClient implements the QuotaManager
79 // It will also be used to maintain some localized state
80 type QuotaClient struct {
81         storeName string
82         tagMeta   string
83         util      Utility
84 }
85
86 // QuotaClient returns an instance of the QuotaClient
87 // which implements the QuotaManager
88 func NewQuotaClient() *QuotaClient {
89         service := DBService{}
90         return &QuotaClient{
91                 storeName: "orchestrator",
92                 tagMeta:   "quota",
93                 util:      service,
94         }
95 }
96
97 // Create entry for the quota resource in the database
98 func (v *QuotaClient) CreateQuota(project, logicalCloud string, c Quota) (Quota, error) {
99
100         //Construct key consisting of name
101         key := QuotaKey{
102                 Project:          project,
103                 LogicalCloudName: logicalCloud,
104                 QuotaName:        c.MetaData.QuotaName,
105         }
106
107         //Check if project exists
108         err := v.util.CheckProject(project)
109         if err != nil {
110                 return Quota{}, pkgerrors.New("Unable to find the project")
111         }
112         //check if logical cloud exists
113         err = v.util.CheckLogicalCloud(project, logicalCloud)
114         if err != nil {
115                 return Quota{}, pkgerrors.New("Unable to find the logical cloud")
116         }
117         //Check if this Quota already exists
118         _, err = v.GetQuota(project, logicalCloud, c.MetaData.QuotaName)
119         if err == nil {
120                 return Quota{}, pkgerrors.New("Quota already exists")
121         }
122
123         err = v.util.DBInsert(v.storeName, key, nil, v.tagMeta, c)
124         if err != nil {
125                 return Quota{}, pkgerrors.Wrap(err, "Creating DB Entry")
126         }
127
128         return c, nil
129 }
130
131 // Get returns Quota for corresponding quota name
132 func (v *QuotaClient) GetQuota(project, logicalCloud, quotaName string) (Quota, error) {
133
134         //Construct the composite key to select the entry
135         key := QuotaKey{
136                 Project:          project,
137                 LogicalCloudName: logicalCloud,
138                 QuotaName:        quotaName,
139         }
140         value, err := v.util.DBFind(v.storeName, key, v.tagMeta)
141         if err != nil {
142                 return Quota{}, pkgerrors.Wrap(err, "Quota")
143         }
144
145         //value is a byte array
146         if value != nil {
147                 q := Quota{}
148                 err = v.util.DBUnmarshal(value[0], &q)
149                 if err != nil {
150                         return Quota{}, pkgerrors.Wrap(err, "Unmarshaling value")
151                 }
152                 return q, nil
153         }
154
155         return Quota{}, pkgerrors.New("Cluster Quota does not exist")
156 }
157
158 // GetAll returns all cluster quotas in the logical cloud
159 func (v *QuotaClient) GetAllQuotas(project, logicalCloud string) ([]Quota, error) {
160         //Construct the composite key to select the entry
161         key := QuotaKey{
162                 Project:          project,
163                 LogicalCloudName: logicalCloud,
164                 QuotaName:        "",
165         }
166         var resp []Quota
167         values, err := v.util.DBFind(v.storeName, key, v.tagMeta)
168         if err != nil {
169                 return []Quota{}, pkgerrors.Wrap(err, "Get All Quotas")
170         }
171
172         for _, value := range values {
173                 q := Quota{}
174                 err = v.util.DBUnmarshal(value, &q)
175                 if err != nil {
176                         return []Quota{}, pkgerrors.Wrap(err, "Unmarshaling value")
177                 }
178                 resp = append(resp, q)
179         }
180
181         return resp, nil
182 }
183
184 // Delete the Quota entry from database
185 func (v *QuotaClient) DeleteQuota(project, logicalCloud, quotaName string) error {
186         //Construct the composite key to select the entry
187         key := QuotaKey{
188                 Project:          project,
189                 LogicalCloudName: logicalCloud,
190                 QuotaName:        quotaName,
191         }
192         err := v.util.DBRemove(v.storeName, key)
193         if err != nil {
194                 return pkgerrors.Wrap(err, "Delete Quota")
195         }
196         return nil
197 }
198
199 // Update an entry for the Quota in the database
200 func (v *QuotaClient) UpdateQuota(project, logicalCloud, quotaName string, c Quota) (Quota, error) {
201
202         key := QuotaKey{
203                 Project:          project,
204                 LogicalCloudName: logicalCloud,
205                 QuotaName:        quotaName,
206         }
207         //Check quota URL name against the quota json name
208         if c.MetaData.QuotaName != quotaName {
209                 return Quota{}, pkgerrors.New("Update Error - Quota name mismatch")
210         }
211         //Check if this Quota exists
212         _, err := v.GetQuota(project, logicalCloud, quotaName)
213         if err != nil {
214                 return Quota{}, pkgerrors.New("Cluster Quota does not exist")
215         }
216         err = v.util.DBInsert(v.storeName, key, nil, v.tagMeta, c)
217         if err != nil {
218                 return Quota{}, pkgerrors.Wrap(err, "Updating DB Entry")
219         }
220         return c, nil
221 }