-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
stack.go
161 lines (140 loc) · 4.2 KB
/
stack.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
package kubernetes
import (
"io/ioutil"
"path/filepath"
"sort"
latest "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
"github.com/docker/compose-on-kubernetes/api/labels"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
)
// Stack is the main type used by stack commands so they remain independent from kubernetes compose component version.
type Stack struct {
Name string
Namespace string
ComposeFile string
Spec *latest.StackSpec
}
type childResource interface {
setOwner(metav1.OwnerReference) error
delete() // does not report error, as if a deletion failed, we want to continue deleting other child resources
}
func deleteChildResources(childResources []childResource) {
for _, cr := range childResources {
cr.delete()
}
}
func setChildResourcesOwner(childResources []childResource, owner metav1.OwnerReference) error {
for _, cr := range childResources {
if err := cr.setOwner(owner); err != nil {
return err
}
}
return nil
}
// getServices returns all the stack service names, sorted lexicographically
func (s *Stack) getServices() []string {
services := make([]string, len(s.Spec.Services))
for i, service := range s.Spec.Services {
services[i] = service.Name
}
sort.Strings(services)
return services
}
// createFileBasedConfigMaps creates a Kubernetes ConfigMap for each Compose global file-based config.
func (s *Stack) createFileBasedConfigMaps(configMaps corev1.ConfigMapInterface) ([]childResource, error) {
var resources []childResource
for name, config := range s.Spec.Configs {
if config.File == "" {
continue
}
fileName := filepath.Base(config.File)
content, err := ioutil.ReadFile(config.File)
if err != nil {
return resources, err
}
configMap, err := configMaps.Create(toConfigMap(s.Name, name, fileName, content))
if err != nil {
return resources, err
}
resources = append(resources, &configMapChildResource{client: configMaps, configMap: configMap})
}
return resources, nil
}
type configMapChildResource struct {
client corev1.ConfigMapInterface
configMap *apiv1.ConfigMap
}
func (r *configMapChildResource) setOwner(ref metav1.OwnerReference) error {
r.configMap.OwnerReferences = append(r.configMap.OwnerReferences, ref)
_, err := r.client.Update(r.configMap)
return err
}
func (r *configMapChildResource) delete() {
r.client.Delete(r.configMap.Name, nil)
}
// toConfigMap converts a Compose Config to a Kube ConfigMap.
func toConfigMap(stackName, name, key string, content []byte) *apiv1.ConfigMap {
return &apiv1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: map[string]string{
labels.ForStackName: stackName,
},
},
Data: map[string]string{
key: string(content),
},
}
}
// createFileBasedSecrets creates a Kubernetes Secret for each Compose global file-based secret.
func (s *Stack) createFileBasedSecrets(secrets corev1.SecretInterface) ([]childResource, error) {
var resources []childResource
for name, secret := range s.Spec.Secrets {
if secret.File == "" {
continue
}
fileName := filepath.Base(secret.File)
content, err := ioutil.ReadFile(secret.File)
if err != nil {
return resources, err
}
secret, err := secrets.Create(toSecret(s.Name, name, fileName, content))
if err != nil {
return resources, err
}
resources = append(resources, &secretChildResource{client: secrets, secret: secret})
}
return resources, nil
}
type secretChildResource struct {
client corev1.SecretInterface
secret *apiv1.Secret
}
func (r *secretChildResource) setOwner(ref metav1.OwnerReference) error {
r.secret.OwnerReferences = append(r.secret.OwnerReferences, ref)
_, err := r.client.Update(r.secret)
return err
}
func (r *secretChildResource) delete() {
r.client.Delete(r.secret.Name, nil)
}
// toSecret converts a Compose Secret to a Kube Secret.
func toSecret(stackName, name, key string, content []byte) *apiv1.Secret {
return &apiv1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: map[string]string{
labels.ForStackName: stackName,
},
},
Data: map[string][]byte{
key: content,
},
}
}