-
Notifications
You must be signed in to change notification settings - Fork 3
/
manifest.go
186 lines (160 loc) · 5.23 KB
/
manifest.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package main
import (
"fmt"
"io"
"io/ioutil"
"strings"
"gopkg.in/yaml.v2"
)
type URL struct {
Host string
Domain string
}
func ParseURL(s, domain string) URL {
p := strings.SplitN(s, ".", 2)
if len(p) == 1 {
p = append(p, domain)
}
return URL{
Host: p[0],
Domain: p[1],
}
}
func (u URL) String() string {
if u.Domain == "" {
return u.Host
}
return fmt.Sprintf("%s.%s", u.Host, u.Domain)
}
type User struct {
Name string `yaml:"username"`
Password string `yaml:"password"`
}
type Organization struct {
Users map[string][]string `yaml:"users"`
Domains []string `yaml:"domains"`
Environment map[string]string `yaml:"env"`
Spaces map[string]*Space `yaml:"spaces"`
Quota string `yaml:"quota"`
Quotas map[string]*Quota `yaml:"quotas"`
SecurityGroupSets *SecurityGroupSet `yaml:"security_group_sets"`
}
type Space struct {
SSH string `yaml:"ssh"`
Domain string `yaml:"domain"`
Users map[string][]string `yaml:"users"`
Environment map[string]string `yaml:"env"`
SharedServices map[string]string `yaml:"services"`
Quota string `yaml:"quota"`
Applications []*Application `yaml:"apps"`
UserProvidedServices []*UserProvidedService `yaml:"user-provided-services"`
SecurityGroupSets *SecurityGroupSet `yaml:"security_group_sets"`
}
type Application struct {
Name string `yaml:"name"`
Hostname string `yaml:"hostname"`
Domain string `yaml:"domain"`
URLs []string `yaml:"urls"`
Repository string `yaml:"repo"`
Path string `yaml:"path"`
Image string `yaml:"image"`
Buildpack string `yaml:"buildpack"`
Memory string `yaml:"memory"`
Disk string `yaml:"disk"`
Instances int `yaml:"instances"`
Environment map[string]string `yaml:"env"`
BoundServices map[string]string `yaml:"bind"`
SharedServices []string `yaml:"shared"`
}
type Quota struct {
Memory map[string]string `yaml:"memory"`
TotalAppInstances string `yaml:"app-instances"`
ServiceInstances string `yaml:"service-instances"`
Routes string `yaml:"routes"`
PaidPlans bool `yaml:"allow-paid-plans"`
NumRoutesWithResPorts string `yaml:"reserve-route-ports"`
}
type Manifest struct {
Domains []string `yaml:"domains"`
Users []User `yaml:"users"`
Quotas map[string]*Quota `yaml:"quotas"`
Organizations map[string]*Organization `yaml:"organizations"`
SecurityGroups map[string]*SecurityGroup `yaml:"security_groups"`
SecurityGroupSets *SecurityGroupSet `yaml:"security_group_sets"`
}
type UserProvidedService struct {
Name string `yaml:"name"`
Credentials interface{} `yaml:"credentials"`
RouteServiceUrl string `yaml:"route_service_url"`
SyslogDrainUrl string `yaml:"syslog_drain_url"`
}
type SecurityGroup struct {
Rules []interface{} `yaml:"rules"`
SecurityGroupFile string `yaml:"security_group_file"`
}
type SecurityGroupSet struct {
Running []string `yaml:"running"`
Staging []string `yaml:"staging"`
}
func ParseManifest(src io.Reader) (Manifest, error) {
var m Manifest
b, err := ioutil.ReadAll(src)
if err != nil {
return m, err
}
err = yaml.Unmarshal(b, &m)
if err != nil {
return m, err
}
/* resolve out the defaults */
for o, org := range m.Organizations {
for s, space := range org.Spaces {
shared := map[string]string{}
for svc, details := range space.SharedServices {
shared[fmt.Sprintf("%s-%s", "shared", svc)] = details
}
space.SharedServices = shared
for a, app := range space.Applications {
/* default to 1 instance of each application */
if app.Instances < 1 {
m.Organizations[o].Spaces[s].Applications[a].Instances = 1
}
/* if we have a hostname or domain, *and* URLs,
we need to throw an error. */
if (app.Domain != "" || app.Hostname != "") && len(app.URLs) > 0 {
return m, fmt.Errorf("Both hostname/domain and list of urls specified -- this is not allowed")
}
/* use the default domain for the space, if present */
if space.Domain != "" && app.Domain == "" {
m.Organizations[o].Spaces[s].Applications[a].Domain = space.Domain
}
services := map[string]string{}
for svc, details := range app.BoundServices {
services[fmt.Sprintf("%s-%s", app.Name, svc)] = details
}
for _, sv_ := range app.SharedServices {
svc := fmt.Sprintf("shared-%s", sv_)
bind, ok := space.SharedServices[svc]
if !ok {
return m, fmt.Errorf("reference to shared service '%s' in %s/%s application %s could not be found",
svc, o, s, app.Name)
}
services[svc] = bind
}
app.BoundServices = services
env := map[string]string{}
for k, v := range org.Environment {
env[k] = v
}
for k, v := range space.Environment {
env[k] = v
}
for k, v := range app.Environment {
env[k] = v
}
app.Environment = env
}
}
}
return m, nil
}