This repository has been archived by the owner on Jul 7, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 59
/
vcap.go
137 lines (118 loc) · 4.81 KB
/
vcap.go
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
// Copyright 2019 the Service Broker Project Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package db_service
import (
"encoding/json"
"fmt"
"net/url"
"os"
"github.com/spf13/viper"
)
type VcapService struct {
BindingName string `json:"binding_name"` // The name assigned to the service binding by the user.
InstanceName string `json:"instance_name"` // The name assigned to the service instance by the user.
Name string `json:"name"` // The binding_name if it exists; otherwise the instance_name.
Label string `json:"label"` // The name of the service offering.
Tags []string `json:"tags"` // An array of strings an app can use to identify a service instance.
Plan string `json:"plan"` // The service plan selected when the service instance was created.
Credentials map[string]interface{} `json:"credentials"` // The service-specific credentials needed to access the service instance.
}
func UseVcapServices() error {
vcapData, vcapExists := os.LookupEnv("VCAP_SERVICES")
// CloudFoundry provides an empty VCAP_SERVICES hash by default
if !vcapExists || vcapData == "{}" {
return nil
}
vcapService, err := ParseVcapServices(vcapData)
if err != nil {
return fmt.Errorf("Error parsing VCAP_SERVICES: %s", err)
}
return SetDatabaseCredentials(vcapService)
}
func SetDatabaseCredentials(vcapService VcapService) error {
u, err := url.Parse(coalesce(vcapService.Credentials["uri"]))
if err != nil {
return fmt.Errorf("Error parsing credentials uri field: %s", err)
}
// Set up database credentials using environment variables
viper.Set(dbTypeProp, DbTypeMysql)
viper.Set(dbHostProp, coalesce(vcapService.Credentials["host"], vcapService.Credentials["hostname"]))
viper.Set(dbUserProp, coalesce(u.User.Username(), vcapService.Credentials["Username"], vcapService.Credentials["username"]))
if pw, _ := u.User.Password(); pw != "" {
viper.Set(dbPassProp, coalesce(pw, vcapService.Credentials["Password"], vcapService.Credentials["password"]))
} else {
viper.Set(dbPassProp, coalesce(vcapService.Credentials["Password"], vcapService.Credentials["password"]))
}
viper.Set(dbNameProp, coalesce(vcapService.Credentials["database_name"], vcapService.Credentials["name"]))
// If database is provided by gcp service broker, retrieve the client_cert, ca_cert and client_key fields
if contains(vcapService.Tags, "gcp") {
viper.Set(caCertProp, vcapService.Credentials["CaCert"])
viper.Set(clientCertProp, vcapService.Credentials["ClientCert"])
viper.Set(clientKeyProp, vcapService.Credentials["ClientKey"])
}
return nil
}
// Return first non-null string in list of arguments
func coalesce(credentials ...interface{}) string {
for _, credential := range credentials {
if credential != nil {
switch credential.(type) {
case int:
return fmt.Sprintf("%d", credential)
default:
return fmt.Sprintf("%v", credential)
}
}
}
return ""
}
func ParseVcapServices(vcapServicesData string) (VcapService, error) {
var vcapMap map[string][]VcapService
err := json.Unmarshal([]byte(vcapServicesData), &vcapMap)
if err != nil {
return VcapService{}, fmt.Errorf("Error unmarshalling VCAP_SERVICES: %s", err)
}
for _, vcapArray := range vcapMap {
vcapService, err := findMySqlTag(vcapArray, "mysql")
if err != nil {
return VcapService{}, fmt.Errorf("Error finding MySQL tag: %s", err)
}
return vcapService, nil
}
return VcapService{}, fmt.Errorf("Error parsing VCAP_SERVICES")
}
// whether a given string array arr contains string key
func contains(arr []string, key string) bool {
for _, n := range arr {
if key == n {
return true
}
}
return false
}
// return the index of the VcapService with a tag of "mysql" in the list of VcapServices, fail if we find more or fewer than 1
func findMySqlTag(vcapServices []VcapService, key string) (VcapService, error) {
index := -1
count := 0
for i, vcapService := range vcapServices {
if contains(vcapService.Tags, key) {
count += 1
index = i
}
}
if count != 1 {
return VcapService{}, fmt.Errorf("The variable VCAP_SERVICES must have one VCAP service with a tag of %s. There are currently %d VCAP services with the tag %s.", "'mysql'", count, "'mysql'")
}
return vcapServices[index], nil
}