Merge "Add another parameter to the definition"
[multicloud/k8s.git] / src / k8splugin / internal / rb / profile.go
1 /*
2  * Copyright 2018 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 rb
18
19 import (
20         "bytes"
21         "encoding/base64"
22         "k8splugin/internal/db"
23         "log"
24
25         uuid "github.com/hashicorp/go-uuid"
26         pkgerrors "github.com/pkg/errors"
27 )
28
29 // Profile contains the parameters needed for resource bundle (rb) profiles
30 // It implements the interface for managing the profiles
31 type Profile struct {
32         UUID              string `json:"uuid,omitempty"`
33         RBDID             string `json:"rbdid"`
34         Name              string `json:"name"`
35         Namespace         string `json:"namespace"`
36         KubernetesVersion string `json:"kubernetesversion"`
37 }
38
39 // ProfileManager is an interface exposes the resource bundle profile functionality
40 type ProfileManager interface {
41         Create(def Profile) (Profile, error)
42         List() ([]Profile, error)
43         Get(resID string) (Profile, error)
44         Help() map[string]string
45         Delete(resID string) error
46         Upload(resID string, inp []byte) error
47 }
48
49 // ProfileClient implements the ProfileManager
50 // It will also be used to maintain some localized state
51 type ProfileClient struct {
52         storeName           string
53         tagMeta, tagContent string
54 }
55
56 // NewProfileClient returns an instance of the ProfileClient
57 // which implements the ProfileManager
58 // Uses rb/def prefix
59 func NewProfileClient() *ProfileClient {
60         return &ProfileClient{
61                 storeName:  "rbprofile",
62                 tagMeta:    "metadata",
63                 tagContent: "content",
64         }
65 }
66
67 // Help returns some information on how to create the content
68 // for the profile in the form of html formatted page
69 func (v *ProfileClient) Help() map[string]string {
70         ret := make(map[string]string)
71
72         return ret
73 }
74
75 // Create an entry for the resource bundle profile in the database
76 func (v *ProfileClient) Create(p Profile) (Profile, error) {
77
78         //Check if provided RBID is a valid resource bundle
79         _, err := NewDefinitionClient().Get(p.RBDID)
80         if err != nil {
81                 return Profile{}, pkgerrors.Errorf("Invalid Resource Bundle ID provided: %s", err.Error())
82         }
83
84         // Name is required
85         if p.Name == "" {
86                 return Profile{}, pkgerrors.New("Name is required for Resource Bundle Profile")
87         }
88
89         // If UUID is empty, we will generate one
90         if p.UUID == "" {
91                 p.UUID, _ = uuid.GenerateUUID()
92         }
93         key := p.UUID
94
95         err = db.DBconn.Create(v.storeName, key, v.tagMeta, p)
96         if err != nil {
97                 return Profile{}, pkgerrors.Wrap(err, "Creating Profile DB Entry")
98         }
99
100         return p, nil
101 }
102
103 // List all resource entries in the database
104 func (v *ProfileClient) List() ([]Profile, error) {
105         res, err := db.DBconn.ReadAll(v.storeName, v.tagMeta)
106         if err != nil || len(res) == 0 {
107                 return []Profile{}, pkgerrors.Wrap(err, "Listing Resource Bundle Profiles")
108         }
109
110         var retData []Profile
111
112         for key, value := range res {
113                 //value is a byte array
114                 if len(value) > 0 {
115                         pr := Profile{}
116                         err = db.DBconn.Unmarshal(value, &pr)
117                         if err != nil {
118                                 log.Printf("[Profile] Error Unmarshaling value for: %s", key)
119                                 continue
120                         }
121                         retData = append(retData, pr)
122                 }
123         }
124
125         return retData, nil
126 }
127
128 // Get returns the Resource Bundle Profile for corresponding ID
129 func (v *ProfileClient) Get(id string) (Profile, error) {
130         value, err := db.DBconn.Read(v.storeName, id, v.tagMeta)
131         if err != nil {
132                 return Profile{}, pkgerrors.Wrap(err, "Get Resource Bundle Profile")
133         }
134
135         //value is a byte array
136         if value != nil {
137                 pr := Profile{}
138                 err = db.DBconn.Unmarshal(value, &pr)
139                 if err != nil {
140                         return Profile{}, pkgerrors.Wrap(err, "Unmarshaling Profile Value")
141                 }
142                 return pr, nil
143         }
144
145         return Profile{}, pkgerrors.New("Error getting Resource Bundle Profile")
146 }
147
148 // Delete the Resource Bundle Profile from database
149 func (v *ProfileClient) Delete(id string) error {
150         err := db.DBconn.Delete(v.storeName, id, v.tagMeta)
151         if err != nil {
152                 return pkgerrors.Wrap(err, "Delete Resource Bundle Profile")
153         }
154
155         err = db.DBconn.Delete(v.storeName, id, v.tagContent)
156         if err != nil {
157                 return pkgerrors.Wrap(err, "Delete Resource Bundle Profile Content")
158         }
159
160         return nil
161 }
162
163 // Upload the contents of resource bundle into database
164 func (v *ProfileClient) Upload(id string, inp []byte) error {
165
166         //ignore the returned data here.
167         _, err := v.Get(id)
168         if err != nil {
169                 return pkgerrors.Errorf("Invalid Profile ID provided %s", err.Error())
170         }
171
172         err = isTarGz(bytes.NewBuffer(inp))
173         if err != nil {
174                 return pkgerrors.Errorf("Error in file format %s", err.Error())
175         }
176
177         //Encode given byte stream to text for storage
178         encodedStr := base64.StdEncoding.EncodeToString(inp)
179         err = db.DBconn.Create(v.storeName, id, v.tagContent, encodedStr)
180         if err != nil {
181                 return pkgerrors.Errorf("Error uploading data to db %s", err.Error())
182         }
183
184         return nil
185 }