github.com/kubernetes-incubator/kube-aws@v0.16.4/cfnstack/assets.go (about) 1 package cfnstack 2 3 import ( 4 "fmt" 5 "github.com/kubernetes-incubator/kube-aws/fingerprint" 6 "github.com/kubernetes-incubator/kube-aws/logger" 7 "github.com/kubernetes-incubator/kube-aws/pkg/api" 8 "path/filepath" 9 "strings" 10 ) 11 12 type Assets interface { 13 Merge(Assets) Assets 14 AsMap() map[api.AssetID]api.Asset 15 FindAssetByStackAndFileName(string, string) (api.Asset, error) 16 S3Prefix() string 17 } 18 19 func EmptyAssets() assetsImpl { 20 return assetsImpl{ 21 underlying: map[api.AssetID]api.Asset{}, 22 } 23 } 24 25 type assetsImpl struct { 26 s3Prefix string 27 underlying map[api.AssetID]api.Asset 28 } 29 30 func (a assetsImpl) Merge(other Assets) Assets { 31 merged := map[api.AssetID]api.Asset{} 32 33 for k, v := range a.underlying { 34 merged[k] = v 35 } 36 for k, v := range other.AsMap() { 37 merged[k] = v 38 } 39 40 return assetsImpl{ 41 s3Prefix: other.S3Prefix(), 42 underlying: merged, 43 } 44 } 45 46 func (a assetsImpl) S3Prefix() string { 47 return a.s3Prefix 48 } 49 50 func (a assetsImpl) AsMap() map[api.AssetID]api.Asset { 51 return a.underlying 52 } 53 54 func (a assetsImpl) findAssetByID(id api.AssetID) (api.Asset, error) { 55 asset, ok := a.underlying[id] 56 if !ok { 57 ks := []string{} 58 for id, _ := range a.underlying { 59 k := fmt.Sprintf("%s/%s", id.StackName, id.Filename) 60 ks = append(ks, k) 61 } 62 logger.Debugf("dumping stored asset keys: %s", strings.Join(ks, ", ")) 63 return asset, fmt.Errorf("[bug] failed to get the asset for the id \"%s\"", id) 64 } 65 return asset, nil 66 } 67 68 func (a assetsImpl) FindAssetByStackAndFileName(stack string, file string) (api.Asset, error) { 69 return a.findAssetByID(api.NewAssetID(stack, file)) 70 } 71 72 type AssetsBuilder interface { 73 Add(filename string, content string) (api.Asset, error) 74 AddUserDataPart(userdata api.UserData, part string, assetName string) error 75 Build() Assets 76 } 77 78 type AssetsBuilderImpl struct { 79 AssetLocationProvider 80 assets map[api.AssetID]api.Asset 81 } 82 83 func (b *AssetsBuilderImpl) Add(filename string, content string) (api.Asset, error) { 84 loc, err := b.Locate(filename) 85 if err != nil { 86 return api.Asset{}, err 87 } 88 89 asset := api.Asset{ 90 AssetLocation: *loc, 91 Content: content, 92 } 93 94 b.assets[loc.ID] = asset 95 return asset, nil 96 } 97 98 func (b *AssetsBuilderImpl) AddUserDataPart(userdata api.UserData, part string, assetName string) error { 99 if p, ok := userdata.Parts[part]; ok { 100 content, err := p.Template() 101 if err != nil { 102 return err 103 } 104 105 filename := fmt.Sprintf("%s-%s", assetName, fingerprint.SHA256(content)) 106 asset, err := b.Add(filename, content) 107 if err != nil { 108 return err 109 } 110 p.Asset = asset 111 } 112 return nil // it is not an error if part is not found 113 } 114 115 func (b *AssetsBuilderImpl) Build() Assets { 116 return assetsImpl{ 117 s3Prefix: b.S3Prefix(), 118 underlying: b.assets, 119 } 120 } 121 122 func NewAssetsBuilder(stackName string, s3URI string, region api.Region) (*AssetsBuilderImpl, error) { 123 uri, err := S3URIFromString(s3URI) 124 125 if err != nil { 126 return nil, fmt.Errorf("failed creating s3 assets locator for stack %s: %v", stackName, err) 127 } 128 129 return &AssetsBuilderImpl{ 130 AssetLocationProvider: AssetLocationProvider{ 131 s3URI: uri, 132 region: region, 133 stackName: stackName, 134 }, 135 assets: map[api.AssetID]api.Asset{}, 136 }, nil 137 } 138 139 type AssetLocationProvider struct { 140 s3URI S3URI 141 region api.Region 142 stackName string 143 } 144 145 func (p AssetLocationProvider) S3DirURI() string { 146 return fmt.Sprintf("%s/%s", p.s3URI.String(), p.stackName) 147 } 148 149 func (p AssetLocationProvider) Locate(filename string) (*api.AssetLocation, error) { 150 if filename == "" { 151 return nil, fmt.Errorf("Can't produce S3 location for empty filename") 152 } 153 154 relativePathComponents := []string{ 155 p.stackName, 156 filename, 157 } 158 159 // key = s3uri's path component + stack name + filename 160 key := strings.Join( 161 append(p.s3URI.KeyComponents(), relativePathComponents...), 162 "/", 163 ) 164 165 id := api.NewAssetID(p.stackName, filename) 166 167 return &api.AssetLocation{ 168 ID: id, 169 Key: key, 170 Bucket: p.s3URI.Bucket(), 171 Path: filepath.Join(relativePathComponents...), 172 Region: p.region, 173 }, nil 174 } 175 176 // S3Prefix returns BUCKET + / + S3 OBJECT KEY PREFIX whereas the prefix is that of all the assets locatable by this provider 177 // For example, in case this provider is configured to locate assets for stack MYSTACK in S3 bucket MYBUCKET 178 // due to that you've passed an S3 URI of `s3://MYBUCKET/MY/PREFIX` and the stack name of MYSTACK, 179 // this func returns "MYBUCKET/MY/PREFIX/MYSTACK". 180 func (p AssetLocationProvider) S3Prefix() string { 181 return fmt.Sprintf("%s/%s", p.s3URI.BucketAndKey(), p.stackName) 182 }