sumomo 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 32e4cbb699706aa8e81613f2e781aeb4d9868daf
4
- data.tar.gz: 7d83d874b32195063ebb437ad9062da01ce72833
3
+ metadata.gz: cb1aedf8b2967520988740daf5e85b6c068302b4
4
+ data.tar.gz: 7fa8031ebf8b52c3ffbe9450d0ed3f7c7672a1c8
5
5
  SHA512:
6
- metadata.gz: b233a9eaae20d275c787adb1dde73ad5ca6e532c7aed417b8c02e662208537d7393cfaefcc4f7bc769ee4003fd1a5dcc8e2be58588f29fe1c7f3ce51edc45de4
7
- data.tar.gz: a2bdea1719464211ec9046a0f30cd8702ae0fdac12eac107c00954b358bd4ec34f18457f9195438f129c84441a8a9bbb4742e66c4a7b804bc4ce4d65b927f1c8
6
+ metadata.gz: 83a0194a2aeb0a63ee35bed97c7521546511ab9fa7677d5e282c1bbeb5caed9f3091a70f63df81ae4dcb574732ee2a10059ede53e99491078a79c42914d0ea3c
7
+ data.tar.gz: 775a27622a8deb089fb94921644566baa1937b1beba30811055ba21f4ebb117fa4b45a9d951b65bc92bd4a3ce50f9ea8414cf0a95b924b462108f4e6b89c5f26
data/README.md CHANGED
@@ -20,7 +20,21 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- TODO: Write usage instructions here
23
+ This gem lets you use all of the syntax in the [momo](https://github.com/davidsiaw/momo) and more!
24
+
25
+ You need to setup your AWS credentials using `aws configure`.
26
+
27
+ ```
28
+ require "sumomo"
29
+
30
+ Sumomo::update_stack(name: "mystack", region: "ap-northeast-1") do
31
+ x = hidden_value "meow"
32
+
33
+ output "Haha", x
34
+ end
35
+
36
+ Sumomo::wait_for_stack(name: "kurosawa", region: "ap-northeast-1")
37
+ ```
24
38
 
25
39
  ## Development
26
40
 
@@ -30,5 +44,5 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
30
44
 
31
45
  ## Contributing
32
46
 
33
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sumomo.
47
+ Bug reports and pull requests are welcome on GitHub at https://github.com/davidsiaw/sumomo.
34
48
 
@@ -0,0 +1,151 @@
1
+ var aws = require("aws-sdk");
2
+
3
+ Cloudformation = {}
4
+ Cloudformation.SUCCESS = "SUCCESS";
5
+ Cloudformation.FAILED = "FAILED";
6
+ Cloudformation.status_sent = false;
7
+ Cloudformation.send = function(request, context, responseStatus, responseData, reason, physicalResourceId) {
8
+
9
+ var responseBody = JSON.stringify({
10
+ Status: responseStatus,
11
+ Reason: reason + " Log Stream: " + context.logStreamName,
12
+ PhysicalResourceId: physicalResourceId || context.logStreamName,
13
+ StackId: request.StackId,
14
+ RequestId: request.RequestId,
15
+ LogicalResourceId: request.LogicalResourceId,
16
+ Data: responseData
17
+ });
18
+
19
+ console.log("Response body:\n", responseBody);
20
+
21
+ var https = require("https");
22
+ var url = require("url");
23
+
24
+ var parsedUrl = url.parse(request.ResponseURL);
25
+ var options = {
26
+ hostname: parsedUrl.hostname,
27
+ port: 443,
28
+ path: parsedUrl.path,
29
+ method: "PUT",
30
+ headers: {
31
+ "content-type": "",
32
+ "content-length": responseBody.length
33
+ }
34
+ };
35
+
36
+ var request = https.request(options, function(response) {
37
+ console.log("Status code: " + response.statusCode);
38
+ console.log("Status message: " + response.statusMessage);
39
+ context.done();
40
+ });
41
+
42
+ request.on("error", function(error) {
43
+ console.log("send(..) failed executing https.request(..): " + error);
44
+ context.done();
45
+ });
46
+
47
+ request.write(responseBody);
48
+ request.end();
49
+ Cloudformation.status_sent = true;
50
+ }
51
+
52
+ function Storage(bucket, prefix, region)
53
+ {
54
+ var s3 = new aws.S3({region: region});
55
+
56
+ this.put = function(key, value, onComplete, onError) {
57
+
58
+ s3.putObject({
59
+ Bucket: bucket,
60
+ Key: "data/" + prefix + "/" + key,
61
+ Body: value
62
+ }, function(err, data) {
63
+ if (err)
64
+ {
65
+ if (onError)
66
+ {
67
+ onError(err);
68
+ }
69
+ else
70
+ {
71
+ throw(err);
72
+ }
73
+ }
74
+ else
75
+ {
76
+ if (onComplete)
77
+ {
78
+ onComplete();
79
+ }
80
+ }
81
+ })
82
+ }
83
+
84
+ this.get = function(key, onComplete, onError) {
85
+
86
+ s3.getObject({
87
+ Bucket: bucket,
88
+ Key: "data/" + prefix + "/" + key
89
+ }, function(err, data) {
90
+ if (err)
91
+ {
92
+ if (onError)
93
+ {
94
+ onError(err);
95
+ }
96
+ else
97
+ {
98
+ throw(err);
99
+ }
100
+ }
101
+ else
102
+ {
103
+ if (onComplete)
104
+ {
105
+ onComplete(data.Body.toString());
106
+ }
107
+ }
108
+ })
109
+ }
110
+
111
+ return this;
112
+ }
113
+
114
+ Global = {}
115
+
116
+ process.on('uncaughtException', function(err) {
117
+ console.log("Sending the following error to cloudformation: ");
118
+ console.log(err);
119
+ Cloudformation.send(Global.request, Global.context, Cloudformation.FAILED, {}, err);
120
+ });
121
+
122
+ process.on('exit', function() {
123
+ if (!Cloudformation.status_sent)
124
+ {
125
+ console.log("No status sent to cloudformation, assuming FAILED");
126
+ Cloudformation.send(Global.request, Global.context, Cloudformation.FAILED, {}, "No status sent to cloudformation");
127
+ }
128
+ });
129
+
130
+ exports.handler = function(request, context)
131
+ {
132
+ console.log("Request:");
133
+ console.log(request);
134
+ console.log("Context:");
135
+ console.log(context);
136
+
137
+ Global.request = request;
138
+ Global.context = context;
139
+ var store = Storage(request.ResourceProperties.Bucket, request.LogicalResourceId, request.ResourceProperties.Region);
140
+
141
+ try
142
+ {
143
+ {{ CODE }}
144
+ }
145
+ catch (err)
146
+ {
147
+ console.log("Sending the following error to cloudformation: ");
148
+ console.log(err);
149
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, err);
150
+ }
151
+ }
@@ -0,0 +1,106 @@
1
+
2
+ var typeToArch = {
3
+ "t1.micro" : "PV64" ,
4
+ "t2.nano" : "HVM64",
5
+ "t2.micro" : "HVM64",
6
+ "t2.small" : "HVM64",
7
+ "t2.medium" : "HVM64",
8
+ "t2.large" : "HVM64",
9
+ "m1.small" : "PV64" ,
10
+ "m1.medium" : "PV64" ,
11
+ "m1.large" : "PV64" ,
12
+ "m1.xlarge" : "PV64" ,
13
+ "m2.xlarge" : "PV64" ,
14
+ "m2.2xlarge" : "PV64" ,
15
+ "m2.4xlarge" : "PV64" ,
16
+ "m3.medium" : "HVM64",
17
+ "m3.large" : "HVM64",
18
+ "m3.xlarge" : "HVM64",
19
+ "m3.2xlarge" : "HVM64",
20
+ "m4.large" : "HVM64",
21
+ "m4.xlarge" : "HVM64",
22
+ "m4.2xlarge" : "HVM64",
23
+ "m4.4xlarge" : "HVM64",
24
+ "m4.10xlarge" : "HVM64",
25
+ "c1.medium" : "PV64" ,
26
+ "c1.xlarge" : "PV64" ,
27
+ "c3.large" : "HVM64",
28
+ "c3.xlarge" : "HVM64",
29
+ "c3.2xlarge" : "HVM64",
30
+ "c3.4xlarge" : "HVM64",
31
+ "c3.8xlarge" : "HVM64",
32
+ "c4.large" : "HVM64",
33
+ "c4.xlarge" : "HVM64",
34
+ "c4.2xlarge" : "HVM64",
35
+ "c4.4xlarge" : "HVM64",
36
+ "c4.8xlarge" : "HVM64",
37
+ "g2.2xlarge" : "HVMG2",
38
+ "g2.8xlarge" : "HVMG2",
39
+ "r3.large" : "HVM64",
40
+ "r3.xlarge" : "HVM64",
41
+ "r3.2xlarge" : "HVM64",
42
+ "r3.4xlarge" : "HVM64",
43
+ "r3.8xlarge" : "HVM64",
44
+ "i2.xlarge" : "HVM64",
45
+ "i2.2xlarge" : "HVM64",
46
+ "i2.4xlarge" : "HVM64",
47
+ "i2.8xlarge" : "HVM64",
48
+ "d2.xlarge" : "HVM64",
49
+ "d2.2xlarge" : "HVM64",
50
+ "d2.4xlarge" : "HVM64",
51
+ "d2.8xlarge" : "HVM64",
52
+ "hi1.4xlarge" : "HVM64",
53
+ "hs1.8xlarge" : "HVM64",
54
+ "cr1.8xlarge" : "HVM64",
55
+ "cc2.8xlarge" : "HVM64"
56
+ }
57
+
58
+ var archToAMINamePattern = {
59
+ "PV64": "amzn-ami-pv*.x86_64-ebs",
60
+ "HVM64": "amzn-ami-hvm*.x86_64-gp2",
61
+ "HVMG2": "amzn-ami-graphics-hvm-*x86_64-ebs*"
62
+ };
63
+
64
+ var ec2 = new aws.EC2({region: request.ResourceProperties.Region});
65
+
66
+ var describeImagesParams = {
67
+ Filters: [{ Name: "name", Values: [archToAMINamePattern[typeToArch[request.ResourceProperties.InstanceType]]]}],
68
+ Owners: [request.ResourceProperties.Architecture == "HVMG2" ? "679593333241" : "amazon"]
69
+ };
70
+
71
+ // Check if the image is a beta or rc image. The Lambda function won't return any of those images.
72
+ function isBeta(imageName) {
73
+ return imageName.toLowerCase().indexOf("beta") > -1 || imageName.toLowerCase().indexOf(".rc") > -1;
74
+ }
75
+
76
+ // Get AMI IDs with the specified name pattern and owner
77
+ ec2.describeImages(describeImagesParams, function(err, describeImagesResult)
78
+ {
79
+ if (err)
80
+ {
81
+ console.log(err, err.stack); // an error occurred
82
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, JSON.stringify(err));
83
+ }
84
+ else
85
+ {
86
+ var response = {}
87
+ var id = "NONE";
88
+ var images = describeImagesResult.Images;
89
+ // Sort images by name in decscending order. The names contain the AMI version, formatted as YYYY.MM.Ver.
90
+ images.sort(function(x, y) { return y.Name.localeCompare(x.Name); });
91
+ for (var j = 0; j < images.length; j++)
92
+ {
93
+ if (isBeta(images[j].Name)) continue;
94
+ id = images[j].ImageId;
95
+ response["Name"] = images[j].Name;
96
+ response["ImageType"] = images[j].ImageType;
97
+ response["CreationDate"] = images[j].CreationDate;
98
+ response["Description"] = images[j].Description;
99
+ response["RootDeviceType"] = images[j].RootDeviceType;
100
+ response["RootDeviceName"] = images[j].RootDeviceName;
101
+ response["VirtualizationType"] = images[j].VirtualizationType;
102
+ break;
103
+ }
104
+ Cloudformation.send(request, context, Cloudformation.SUCCESS, response, "Success", id);
105
+ }
106
+ });
@@ -0,0 +1,89 @@
1
+ // return number of zones
2
+ // Zones = comma separated availability zone names
3
+
4
+ physicalId = "0"
5
+ response = {}
6
+
7
+ function send_success()
8
+ {
9
+ if (request.RequestType == "Create")
10
+ {
11
+ Cloudformation.send(request, context, Cloudformation.SUCCESS, response, "Success", physicalId);
12
+ }
13
+
14
+ if (request.RequestType == "Update")
15
+ {
16
+ Cloudformation.send(request, context, Cloudformation.SUCCESS, response, "Success", physicalId);
17
+ }
18
+
19
+ if (request.RequestType == "Delete")
20
+ {
21
+ Cloudformation.send(request, context, Cloudformation.SUCCESS, {}, "Success");
22
+ }
23
+ }
24
+
25
+ function get_spot_prices(instance, zones, number)
26
+ {
27
+ if (zones.length == 0)
28
+ {
29
+ send_success();
30
+ }
31
+ else
32
+ {
33
+ ec2.describeSpotPriceHistory({
34
+ AvailabilityZone: zones[0],
35
+ InstanceTypes: [instance],
36
+ MaxResults: 10
37
+ }, function(err, data) {
38
+ if (err)
39
+ {
40
+ console.log(err, err.stack); // an error occurred
41
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, JSON.stringify(err));
42
+ }
43
+ else
44
+ {
45
+ console.log("HISTORY")
46
+ console.log(JSON.stringify(data.SpotPriceHistory))
47
+ var price = data.SpotPriceHistory[0].SpotPrice
48
+ if (response["ZoneSpotPrices"])
49
+ {
50
+ response["ZoneSpotPrices"] += ","
51
+ }
52
+ response["ZoneSpotPrices"] += price;
53
+ response["ZoneSpotPrice" + number] = price;
54
+ zones.splice(0,1);
55
+ get_spot_prices(instance, zones, number+1);
56
+ }
57
+ });
58
+ }
59
+ }
60
+
61
+ var ec2 = new aws.EC2({region: request.ResourceProperties.Region});
62
+ ec2.describeAvailabilityZones({}, function(err, data) {
63
+ if (err)
64
+ {
65
+ console.log(err, err.stack); // an error occurred
66
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, JSON.stringify(err));
67
+ }
68
+ else
69
+ {
70
+ var zones = data.AvailabilityZones.map(function(x) {return x.ZoneName;});
71
+
72
+ physicalId = String(zones.length);
73
+ response["Zones"] = zones.join();
74
+ for(var i=0; i<zones.length; i++)
75
+ {
76
+ response["Zone"+i] = zones[i];
77
+ }
78
+
79
+ if (request.ResourceProperties.GetSpotPriceFor)
80
+ {
81
+ response["ZoneSpotPrices"] = ""
82
+ get_spot_prices(request.ResourceProperties.GetSpotPriceFor, zones, 1);
83
+ }
84
+ else
85
+ {
86
+ send_success();
87
+ }
88
+ }
89
+ });
@@ -0,0 +1,231 @@
1
+ // Key: Cloudflare API key
2
+ // Email: Cloudflare API email
3
+ // Domain: Cloudflare domain
4
+ // Entry: DNS entry text
5
+ // CNAME: The CNAME record
6
+ // return Record ID of the CNAME record
7
+
8
+ var querystring = require('querystring');
9
+ var https = require('https');
10
+
11
+ key = request.ResourceProperties.Key
12
+ email = request.ResourceProperties.Email
13
+ domain = request.ResourceProperties.Domain
14
+ entry = request.ResourceProperties.Entry
15
+ cname = request.ResourceProperties.Cname
16
+
17
+ function get(path, query, on_complete)
18
+ {
19
+ var query_string = querystring.stringify(query);
20
+
21
+ var get_options = {
22
+ host: 'api.cloudflare.com',
23
+ port: '443',
24
+ path: '/client/v4' + path + "/?" + query_string,
25
+ method: 'GET',
26
+ headers: {
27
+ 'X-Auth-Key': key,
28
+ 'X-Auth-Email': email
29
+ }
30
+ };
31
+
32
+ var req = https.request(get_options, function(res) {
33
+ //console.log('statusCode: ', res.statusCode);
34
+ //console.log('headers: ', res.headers);
35
+ var body = "";
36
+ res.setEncoding('utf8');
37
+ res.on('data', function(d) {
38
+ body += d;
39
+ });
40
+ res.on('end', function() {
41
+ on_complete(JSON.parse(body));
42
+ });
43
+ req.on('error', function(e) {
44
+ console.error(e);
45
+ });
46
+ });
47
+ req.end();
48
+ }
49
+
50
+ function http_request(method, path, data, on_complete)
51
+ {
52
+ post_data = JSON.stringify(data);
53
+
54
+ var post_options = {
55
+ host: 'api.cloudflare.com',
56
+ port: '443',
57
+ path: '/client/v4' + path,
58
+ method: method,
59
+ headers: {
60
+ 'Content-Type': 'application/json',
61
+ 'Content-Length': Buffer.byteLength(post_data),
62
+ 'X-Auth-Key': key,
63
+ 'X-Auth-Email': email
64
+ }
65
+ };
66
+
67
+ var req = https.request(post_options, function(res) {
68
+ //console.log('statusCode: ', res.statusCode);
69
+ //console.log('headers: ', res.headers);
70
+ var body = "";
71
+ res.setEncoding('utf8');
72
+ res.on('data', function(d) {
73
+ body += d;
74
+ });
75
+ res.on('end', function() {
76
+ on_complete(JSON.parse(body));
77
+ });
78
+ req.on('error', function(e) {
79
+ console.error(e);
80
+ });
81
+ });
82
+ req.write(post_data);
83
+ req.end();
84
+ }
85
+
86
+ function post(path, data, on_complete)
87
+ {
88
+ http_request("POST", path, data, on_complete)
89
+ }
90
+
91
+ function del(path, data, on_complete)
92
+ {
93
+ http_request("DELETE", path, data, on_complete)
94
+ }
95
+
96
+ function get_zone_id(zone_name, on_complete)
97
+ {
98
+ get("/zones", {name: zone_name}, function (data)
99
+ {
100
+ on_complete(data["result"][0]["id"])
101
+ });
102
+ }
103
+
104
+ function get_dns_record_named(zone_id, name, on_complete)
105
+ {
106
+ get("/zones/"+zone_id+"/dns_records", {name: name}, function (data)
107
+ {
108
+ on_complete(data["result"])
109
+ });
110
+ }
111
+
112
+ function create_cname_dns_record(zone_id, type, name, content, on_complete)
113
+ {
114
+ post("/zones/"+zone_id+"/dns_records", {
115
+ type: type,
116
+ name: name,
117
+ content: content
118
+ }, function(data) {
119
+ on_complete(data)
120
+ });
121
+ };
122
+
123
+ function delete_cname_dns_record(zone_id, record_id, on_complete)
124
+ {
125
+ del("/zones/"+zone_id+"/dns_records/"+record_id, {}, function(data) {
126
+ on_complete(data)
127
+ });
128
+ };
129
+
130
+
131
+ console.log('REQUEST RECEIVED:\n', JSON.stringify(request));
132
+
133
+ function send_success(record_id)
134
+ {
135
+ Cloudformation.send(request, context, Cloudformation.SUCCESS, {}, "Success", record_id);
136
+ }
137
+
138
+ function send_failure(reason)
139
+ {
140
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, reason);
141
+ }
142
+
143
+ function save_data(domain_id, record_id, on_complete, on_error)
144
+ {
145
+ store.put("domain_id", domain_id, function() {
146
+ store.put("record_id", record_id, on_complete, on_error);
147
+ }, on_error);
148
+ }
149
+
150
+ function load_data(on_complete, on_error)
151
+ {
152
+ store.get("domain_id", function(domain_id) {
153
+ store.get("record_id", function(record_id) {
154
+ on_complete(domain_id, record_id);
155
+ }, on_error);
156
+ }, on_error);
157
+ }
158
+
159
+ if (request.RequestType == "Create") {
160
+
161
+ get_zone_id(domain, function(id)
162
+ {
163
+ get_dns_record_named(id, entry, function(data)
164
+ {
165
+ if (data.length == 0)
166
+ {
167
+ create_cname_dns_record(id, "CNAME", entry, cname, function(data) {
168
+ console.log("CREATE RECORD: " + JSON.stringify(data));
169
+ if (data.result)
170
+ {
171
+ save_data(id, data.result.id,
172
+ function() {
173
+ send_success(data.result.id)
174
+ },
175
+ function() {
176
+ send_failure("Failed to save data")
177
+ }
178
+ );
179
+ }
180
+ else
181
+ {
182
+ send_failure(JSON.stringify(data));
183
+ }
184
+ });
185
+ }
186
+ else
187
+ {
188
+ send_failure("Entry " + entry + " already exists");
189
+ }
190
+ console.log(data);
191
+ });
192
+ });
193
+
194
+ return;
195
+ }
196
+
197
+ if (request.RequestType == "Update") {
198
+
199
+ load_data(function(domain_id, record_id) {
200
+
201
+ delete_cname_dns_record(domain_id, record_id, function() {
202
+ create_cname_dns_record(domain_id, "CNAME", entry, cname, function(data) {
203
+ console.log(data);
204
+ save_data(domain_id, data.result.id,
205
+ function() {
206
+ send_success(data.result.id)
207
+ },
208
+ function() {
209
+ send_failure("Failed to save data")
210
+ }
211
+ );
212
+ });
213
+ });
214
+
215
+ }, send_failure.bind("Failed to load data"));
216
+
217
+
218
+ return;
219
+ }
220
+
221
+ if (request.RequestType == "Delete") {
222
+
223
+ load_data(function(domain_id, record_id) {
224
+
225
+ delete_cname_dns_record(domain_id, record_id, function() {
226
+ send_success(record_id)
227
+ });
228
+
229
+ }, send_failure.bind("Failed to load data"));
230
+ return;
231
+ }