CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.2.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/utils.go

229lines · modecode

1package main
2
3import (
4 "flag"
5 "fmt"
6 "io/ioutil"
7 "os"
8 "path/filepath"
9 "regexp"
10 "strings"
11
12 "github.com/imdario/mergo"
13 "github.com/mitchellh/go-homedir"
14 "github.com/zackbloom/go-ini"
15 "github.com/zackbloom/goamz/aws"
16 "github.com/zackbloom/goamz/cloudfront"
17 "github.com/zackbloom/goamz/iam"
18 "github.com/zackbloom/goamz/route53"
19 "github.com/zackbloom/goamz/s3"
20 "gopkg.in/yaml.v1"
21)
22
23const (
24 LIMITED = 60
25 FOREVER = 31556926
26)
27
28var s3Session *s3.S3
29var iamSession *iam.IAM
30var r53Session *route53.Route53
31var cfSession *cloudfront.CloudFront
32
33func getRegion(region string) aws.Region {
34 regionS, ok := aws.Regions[region]
35 if !ok {
36 panic("Region not found")
37 }
38 return regionS
39}
40
41func openS3(key, secret, region string) *s3.S3 {
42 regionS := getRegion(region)
43
44 auth := aws.Auth{
45 AccessKey: key,
46 SecretKey: secret,
47 }
48 return s3.New(auth, regionS)
49}
50
51func openIAM(key, secret, region string) *iam.IAM {
52 regionS := getRegion(region)
53
54 auth := aws.Auth{
55 AccessKey: key,
56 SecretKey: secret,
57 }
58 return iam.New(auth, regionS)
59}
60
61func openCloudFront(key, secret string) *cloudfront.CloudFront {
62 auth := aws.Auth{
63 AccessKey: key,
64 SecretKey: secret,
65 }
66 return cloudfront.NewCloudFront(auth)
67}
68
69func openRoute53(key, secret string) *route53.Route53 {
70 auth := aws.Auth{
71 AccessKey: key,
72 SecretKey: secret,
73 }
74
75 r53, _ := route53.NewRoute53(auth)
76 return r53
77}
78
79func panicIf(err error) {
80 if err != nil {
81 panic(err)
82 }
83}
84func must(val interface{}, err error) interface{} {
85 if err != nil {
86 panic(err)
87 }
88
89 return val
90}
91func mustString(val string, err error) string {
92 panicIf(err)
93 return val
94}
95func mustInt(val int, err error) int {
96 panicIf(err)
97 return val
98}
99
100type Options struct {
101 Files string `yaml:"files"`
102 Root string `yaml:"root"`
103 Dest string `yaml:"dest"`
104 ConfigFile string `yaml:"-"`
105 Env string `yaml:"-"`
106 Bucket string `yaml:"bucket"`
107 AWSKey string `yaml:"key"`
108 AWSSecret string `yaml:"secret"`
109 AWSRegion string `yaml:"region"`
110 NoUser bool `yaml:"-"`
111}
112
113func parseOptions() (o Options, set *flag.FlagSet) {
114 set = flag.NewFlagSet(os.Args[1], flag.ExitOnError)
115 //TODO: Set set.Usage
116
117 set.StringVar(&o.Files, "files", "*", "Comma-seperated glob patterns of files to deploy (within root)")
118 set.StringVar(&o.Root, "root", "./", "The local directory to deploy")
119 set.StringVar(&o.Dest, "dest", "./", "The destination directory to write files to in the S3 bucket")
120 set.StringVar(&o.ConfigFile, "config", "", "A yaml file to read configuration from")
121 set.StringVar(&o.Env, "env", "", "The env to read from the config file")
122 set.StringVar(&o.Bucket, "bucket", "", "The bucket to deploy to")
123 set.StringVar(&o.AWSKey, "key", "", "The AWS key to use")
124 set.StringVar(&o.AWSSecret, "secret", "", "The AWS secret of the provided key")
125 set.StringVar(&o.AWSRegion, "region", "us-east-1", "The AWS region the S3 bucket is in")
126 set.BoolVar(&o.NoUser, "no-user", false, "When creating, should we make a user account?")
127
128 set.Parse(os.Args[2:])
129
130 return
131}
132
133type ConfigFile map[string]Options
134
135func loadConfigFile(o *Options) {
136 isDefault := false
137 configPath := o.ConfigFile
138 if o.ConfigFile == "" {
139 isDefault = true
140 configPath = "./deploy.yaml"
141 }
142
143 data, err := ioutil.ReadFile(configPath)
144 if err != nil {
145 if os.IsNotExist(err) && isDefault {
146 return
147 }
148
149 panic(err)
150 }
151
152 var file ConfigFile
153 err = yaml.Unmarshal(data, &file)
154 panicIf(err)
155
156 var envCfg Options
157 if o.Env != "" {
158 var ok bool
159 envCfg, ok = file[o.Env]
160 if !ok {
161 panic("Config for specified env not found")
162 }
163 }
164
165 defCfg, _ := file["default"]
166
167 panicIf(mergo.Merge(o, defCfg))
168 panicIf(mergo.Merge(o, envCfg))
169}
170
171func addAWSConfig(o *Options) {
172 if o.AWSKey == "" && o.AWSSecret == "" {
173 o.AWSKey, o.AWSSecret = loadAWSConfig()
174 }
175}
176
177type AWSConfig struct {
178 Default struct {
179 AccessKey string `ini:"aws_access_key_id"`
180 SecretKey string `ini:"aws_secret_access_key"`
181 } `ini:"[default]"`
182}
183
184func loadAWSConfig() (access string, secret string) {
185 cfg := AWSConfig{}
186
187 path, err := homedir.Expand("~/.aws/config")
188 if err != nil {
189 return
190 }
191
192 content, err := ioutil.ReadFile(path)
193 if err != nil {
194 return
195 }
196
197 ini.Unmarshal(content, &cfg)
198
199 return cfg.Default.AccessKey, cfg.Default.SecretKey
200}
201
202func copyFile(bucket *s3.Bucket, from string, to string, contentType string, maxAge int) {
203 copyOpts := s3.CopyOptions{
204 MetadataDirective: "REPLACE",
205 ContentType: contentType,
206 Options: s3.Options{
207 CacheControl: fmt.Sprintf("public, max-age=%d", maxAge),
208 ContentEncoding: "gzip",
209 },
210 }
211
212 _, err := bucket.PutCopy(to, s3.PublicRead, copyOpts, joinPath(bucket.Name, from))
213 if err != nil {
214 panic(err)
215 }
216}
217
218var pathRe = regexp.MustCompile("/{2,}")
219
220func joinPath(parts ...string) string {
221 // Like filepath.Join, but always uses '/'
222 out := filepath.Join(parts...)
223
224 if os.PathSeparator != '/' {
225 out = strings.Replace(out, string(os.PathSeparator), "/", -1)
226 }
227
228 return out
229}