forked from kubernetes-retired/kube-aws
-
Notifications
You must be signed in to change notification settings - Fork 0
/
assets.go
149 lines (123 loc) · 3.28 KB
/
assets.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
package cfnstack
import (
"fmt"
"github.com/kubernetes-incubator/kube-aws/fingerprint"
"github.com/kubernetes-incubator/kube-aws/model"
"path/filepath"
"strings"
)
type Assets interface {
Merge(Assets) Assets
AsMap() map[model.AssetID]model.Asset
FindAssetByStackAndFileName(string, string) (model.Asset, error)
}
type assetsImpl struct {
underlying map[model.AssetID]model.Asset
}
func (a assetsImpl) Merge(other Assets) Assets {
merged := map[model.AssetID]model.Asset{}
for k, v := range a.underlying {
merged[k] = v
}
for k, v := range other.AsMap() {
merged[k] = v
}
return assetsImpl{
underlying: merged,
}
}
func (a assetsImpl) AsMap() map[model.AssetID]model.Asset {
return a.underlying
}
func (a assetsImpl) findAssetByID(id model.AssetID) (model.Asset, error) {
asset, ok := a.underlying[id]
if !ok {
return asset, fmt.Errorf("[bug] failed to get the asset for the id \"%s\"", id)
}
return asset, nil
}
func (a assetsImpl) FindAssetByStackAndFileName(stack string, file string) (model.Asset, error) {
return a.findAssetByID(model.NewAssetID(stack, file))
}
type AssetsBuilder interface {
Add(filename string, content string) (model.Asset, error)
AddUserDataPart(userdata model.UserData, part string, assetName string) error
Build() Assets
}
type assetsBuilderImpl struct {
locProvider AssetLocationProvider
assets map[model.AssetID]model.Asset
}
func (b *assetsBuilderImpl) Add(filename string, content string) (model.Asset, error) {
loc, err := b.locProvider.locationFor(filename)
if err != nil {
return model.Asset{}, err
}
asset := model.Asset{
AssetLocation: *loc,
Content: content,
}
b.assets[loc.ID] = asset
return asset, nil
}
func (b *assetsBuilderImpl) AddUserDataPart(userdata model.UserData, part string, assetName string) error {
if p, ok := userdata.Parts[part]; ok {
content, err := p.Template()
if err != nil {
return err
}
filename := fmt.Sprintf("%s-%s", assetName, fingerprint.SHA256(content))
asset, err := b.Add(filename, content)
if err != nil {
return err
}
p.Asset = asset
}
return nil // it is not an error if part is not found
}
func (b *assetsBuilderImpl) Build() Assets {
return assetsImpl{
underlying: b.assets,
}
}
func NewAssetsBuilder(stackName string, s3URI string, region model.Region) AssetsBuilder {
return &assetsBuilderImpl{
locProvider: AssetLocationProvider{
s3URI: s3URI,
region: region,
stackName: stackName,
},
assets: map[model.AssetID]model.Asset{},
}
}
type AssetLocationProvider struct {
s3URI string
region model.Region
stackName string
}
func (p AssetLocationProvider) locationFor(filename string) (*model.AssetLocation, error) {
if filename == "" {
return nil, fmt.Errorf("Can't produce S3 location for empty filename")
}
s3URI := p.s3URI
uri, err := S3URIFromString(s3URI)
if err != nil {
return nil, fmt.Errorf("failed to determine location for %s: %v", filename, err)
}
relativePathComponents := []string{
p.stackName,
filename,
}
key := strings.Join(
append(uri.PathComponents(), relativePathComponents...),
"/",
)
id := model.NewAssetID(p.stackName, filename)
return &model.AssetLocation{
ID: id,
Key: key,
Bucket: uri.Bucket(),
Path: filepath.Join(relativePathComponents...),
Region: p.region,
}, nil
}