Upload secrets even when domain already exists
[aaf/sms.git] / sms-service / src / preload / preload.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 main
18
19 import (
20         "bytes"
21         "crypto/tls"
22         "crypto/x509"
23         "encoding/json"
24         "flag"
25         "fmt"
26         "io/ioutil"
27         "log"
28         "net/http"
29         "net/url"
30         "path/filepath"
31         "strings"
32         "time"
33
34         pkgerrors "github.com/pkg/errors"
35 )
36
37 //DataJSON stores a list of domains from JSON file
38 type DataJSON struct {
39         //Support single domain: {} structure in JSON
40         Domain SecretDomainJSON `json:"domain,omitempty"`
41         //Support plural domains: [{}] structure in JSON
42         Domains []SecretDomainJSON `json:"domains,omitempty"`
43 }
44
45 //SecretDomainJSON stores a name for the Domain and a list of Secrets
46 type SecretDomainJSON struct {
47         Name    string       `json:"name"`
48         Secrets []SecretJSON `json:"secrets"`
49 }
50
51 //SecretJSON stores a name for the Secret and a list of Values
52 type SecretJSON struct {
53         Name   string                 `json:"name"`
54         Values map[string]interface{} `json:"values"`
55 }
56
57 //Processes the JSON file and returns a DataJSON struct
58 func processJSONFile(name string) (DataJSON, error) {
59
60         data, err := ioutil.ReadFile(name)
61         if err != nil {
62                 return DataJSON{}, pkgerrors.Cause(err)
63         }
64
65         d := DataJSON{}
66         err = json.Unmarshal(data, &d)
67         if err != nil {
68                 return DataJSON{}, pkgerrors.Cause(err)
69         }
70
71         return d, nil
72 }
73
74 type smsClient struct {
75         BaseURL *url.URL
76         //In seconds
77         Timeout    int
78         CaCertPath string
79
80         httpClient *http.Client
81 }
82
83 func (c *smsClient) init() error {
84
85         skipVerify := false
86         caCert, err := ioutil.ReadFile(c.CaCertPath)
87         if err != nil {
88                 fmt.Println(pkgerrors.Cause(err))
89                 fmt.Println("Using Insecure Server Verification")
90                 skipVerify = true
91         }
92
93         tlsConfig := &tls.Config{
94                 MinVersion: tls.VersionTLS12,
95         }
96
97         tlsConfig.InsecureSkipVerify = skipVerify
98
99         // Add cert information when skipVerify is false
100         if skipVerify == false {
101                 caCertPool := x509.NewCertPool()
102                 caCertPool.AppendCertsFromPEM(caCert)
103                 tlsConfig.RootCAs = caCertPool
104         }
105
106         tr := &http.Transport{
107                 TLSClientConfig: tlsConfig,
108         }
109
110         c.httpClient = &http.Client{
111                 Transport: tr,
112                 Timeout:   time.Duration(c.Timeout) * time.Second,
113         }
114
115         return nil
116 }
117
118 func (c *smsClient) resolveURL(relURL string) (*url.URL, error) {
119
120         rel, err := url.Parse(relURL)
121         if err != nil {
122                 return nil, pkgerrors.Cause(err)
123         }
124
125         return c.BaseURL.ResolveReference(rel), nil
126
127 }
128
129 func (c *smsClient) sendGetRequest(relURL string) (map[string]interface{}, error) {
130
131         u, err := c.resolveURL(relURL)
132         if err != nil {
133                 return nil, pkgerrors.Cause(err)
134         }
135
136         resp, err := c.httpClient.Get(u.String())
137         if err != nil {
138                 return nil, pkgerrors.Cause(err)
139         }
140
141         if resp.StatusCode >= 400 && resp.StatusCode < 600 {
142                 // Request Failed
143                 errText, _ := ioutil.ReadAll(resp.Body)
144                 return nil, pkgerrors.Errorf("Request Failed with: %s and Error: %s",
145                         resp.Status, string(errText))
146         }
147
148         var result map[string]interface{}
149         err = json.NewDecoder(resp.Body).Decode(&result)
150         if err != nil {
151                 return nil, pkgerrors.Cause(err)
152         }
153
154         return result, nil
155 }
156
157 func (c *smsClient) sendPostRequest(relURL string, message map[string]interface{}) error {
158
159         u, err := c.resolveURL(relURL)
160         if err != nil {
161                 return pkgerrors.Cause(err)
162         }
163
164         body, err := json.Marshal(message)
165         if err != nil {
166                 return pkgerrors.Cause(err)
167         }
168
169         resp, err := c.httpClient.Post(u.String(), "application/json", bytes.NewBuffer(body))
170         if err != nil {
171                 return pkgerrors.Cause(err)
172         }
173
174         if resp.StatusCode >= 400 && resp.StatusCode < 600 {
175                 // Request Failed
176                 errText, _ := ioutil.ReadAll(resp.Body)
177                 return pkgerrors.Errorf("Request Failed with: %s and Error: %s",
178                         resp.Status, string(errText))
179         }
180
181         return nil
182 }
183
184 func (c *smsClient) createDomain(domain string) error {
185
186         message := map[string]interface{}{
187                 "name": domain,
188         }
189         url := "/v1/sms/domain"
190         err := c.sendPostRequest(url, message)
191         if err != nil {
192                 if strings.Contains(err.Error(), "existing domain") {
193                         fmt.Println("Domain ", domain, " already exists...")
194                         return nil
195                 }
196                 return pkgerrors.Cause(err)
197         }
198         return nil
199 }
200
201 func (c *smsClient) createSecret(domain string, secret string,
202         values map[string]interface{}) error {
203
204         message := map[string]interface{}{
205                 "name":   secret,
206                 "values": values,
207         }
208
209         url := "/v1/sms/domain/" + strings.TrimSpace(domain) + "/secret"
210         err := c.sendPostRequest(url, message)
211         if err != nil {
212                 return pkgerrors.Cause(err)
213         }
214
215         return nil
216 }
217
218 func (c *smsClient) isReady() bool {
219
220         url := "v1/sms/quorum/status"
221         res, err := c.sendGetRequest(url)
222         if err != nil {
223                 fmt.Println(pkgerrors.Cause(err))
224                 return false
225         }
226
227         if res["sealstatus"] == true {
228                 return false
229         }
230
231         return true
232 }
233
234 //uploadToSMS reads through the domain or domains and uploads
235 //their corresponding secrets to SMS service
236 func (c *smsClient) uploadToSMS(data DataJSON) error {
237
238         var ldata []SecretDomainJSON
239
240         //Check if Domain is empty
241         if strings.TrimSpace(data.Domain.Name) != "" {
242                 ldata = append(ldata, data.Domain)
243         } else if len(data.Domains) != 0 {
244                 //Check if plural Domains are empty
245                 ldata = append(ldata, data.Domains...)
246         } else {
247                 return pkgerrors.New("Invalid JSON Data. No domain or domains found")
248         }
249
250         isReady := make(chan bool)
251         go func() {
252                 for c.isReady() == false {
253                         time.Sleep(5 * time.Second)
254                         fmt.Println("Waiting for SMS to accept requests...")
255                 }
256                 isReady <- true
257         }()
258         <-isReady
259
260         fmt.Println("Uploading data...")
261
262         for _, d := range ldata {
263                 err := c.createDomain(d.Name)
264                 if err != nil {
265                         return pkgerrors.Cause(err)
266                 }
267
268                 for _, s := range d.Secrets {
269                         err = c.createSecret(d.Name, s.Name, s.Values)
270                         if err != nil {
271                                 return pkgerrors.Cause(err)
272                         }
273                 }
274         }
275
276         return nil
277 }
278
279 func main() {
280
281         cacert := flag.String("cacert", "/sms/certs/aaf_root_ca.cer",
282                 "Path to the CA Certificate file")
283         serviceurl := flag.String("serviceurl", "https://aaf-sms.onap",
284                 "Url for the SMS Service")
285         serviceport := flag.String("serviceport", "10443",
286                 "Service port if its different than the default")
287         jsondir := flag.String("jsondir", ".",
288                 "Folder containing json files to upload")
289
290         flag.Parse()
291
292         //Clear all trailing/leading spaces from incoming strings
293         *cacert = strings.TrimSpace(*cacert)
294         *serviceurl = strings.TrimSpace(*serviceurl)
295         *serviceport = strings.TrimSpace(*serviceport)
296         *jsondir = strings.TrimSpace(*jsondir)
297
298         files, err := ioutil.ReadDir(*jsondir)
299         if err != nil {
300                 log.Fatal(pkgerrors.Cause(err))
301         }
302
303         //URL validity is checked here
304         serviceURL, err := url.Parse(*serviceurl + ":" + *serviceport)
305         if err != nil {
306                 log.Fatal(pkgerrors.Cause(err))
307         }
308
309         client := &smsClient{
310                 Timeout:    30,
311                 BaseURL:    serviceURL,
312                 CaCertPath: *cacert,
313         }
314         client.init()
315
316         for _, file := range files {
317                 if filepath.Ext(file.Name()) == ".json" {
318                         fmt.Println("Processing   ", filepath.Join(*jsondir, file.Name()))
319                         d, err := processJSONFile(filepath.Join(*jsondir, file.Name()))
320                         if err != nil {
321                                 log.Printf("Error Reading %s : %s", file.Name(), pkgerrors.Cause(err))
322                                 continue
323                         }
324
325                         err = client.uploadToSMS(d)
326                         if err != nil {
327                                 log.Printf("Error Uploading %s : %s", file.Name(), pkgerrors.Cause(err))
328                                 continue
329                         }
330                 }
331         }
332 }