flynn-cli-tools 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/flynn-cluster +157 -0
- data/bin/flynn-dns +191 -0
- data/bin/flynn-migrate +22 -0
- data/bin/flynn-release +80 -0
- data/dev-bin/console +14 -0
- data/dev-bin/setup +8 -0
- data/lib/flynn/cli/tools.rb +118 -0
- data/lib/flynn/cli/tools/cloudflare.rb +58 -0
- data/lib/flynn/cli/tools/commander_setup.rb +33 -0
- data/lib/flynn/cli/tools/logger.rb +19 -0
- data/lib/flynn/cli/tools/option_parser.rb +42 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4fecf07c24f887cd5c4068ceec7f932e3c9428a7
|
4
|
+
data.tar.gz: 75569666b7f8c9b75cb1be196e353d417208dcb8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1a8944e1e43d3e5f9ec213b5a6fdcc1b0a9d12d4be324633d398689fd7d4b4de718c2e20c81ebc09512ced381faac9248111872df64abd4c619af8e75d7a5c66
|
7
|
+
data.tar.gz: 0a0646c08e87b608f4ef08d1b0c4f0e541102a831fb6a786eae2c9dfe86b32399e5b0515a7575ba45998f7dcb823a9264e210783bac2d115d01cc85b4d51040e
|
data/bin/flynn-cluster
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'table_print'
|
4
|
+
require 'commander'
|
5
|
+
require 'json'
|
6
|
+
require 'httparty'
|
7
|
+
|
8
|
+
# Custom libs
|
9
|
+
$:.unshift File.join(File.dirname(__FILE__), "..")
|
10
|
+
require 'lib/flynn/cli/tools'
|
11
|
+
|
12
|
+
tp.set :max_width, 100
|
13
|
+
|
14
|
+
# Returns whether the object is tagged with something
|
15
|
+
def has_tag? obj, key, value
|
16
|
+
obj["Tags"].each do |tag|
|
17
|
+
return true if tag["Key"] == key && tag["Value"] == value
|
18
|
+
end
|
19
|
+
return false
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the value of a tag or nil
|
23
|
+
def tag_value obj, key
|
24
|
+
obj["Tags"].each do |tag|
|
25
|
+
return tag["Value"] if tag["Key"] == key
|
26
|
+
end
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns a table row for the given auto scaling group
|
31
|
+
def asg_table_row obj
|
32
|
+
return ({
|
33
|
+
cluster: tag_value(obj, "Name"),
|
34
|
+
asg_name: obj["AutoScalingGroupName"],
|
35
|
+
launch_config: obj["LaunchConfigurationName"],
|
36
|
+
num_instances: obj["Instances"].length,
|
37
|
+
zones: obj["AvailabilityZones"].join(", "),
|
38
|
+
created: obj["CreatedTime"]
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns a table row for the given launch configuration
|
43
|
+
def lc_table_row obj
|
44
|
+
return ({
|
45
|
+
launch_config: obj["LaunchConfigurationName"],
|
46
|
+
version: obj["LaunchConfigurationName"].sub('Flynn Platform', '').strip,
|
47
|
+
image: obj["ImageId"],
|
48
|
+
instance_type: obj["InstanceType"],
|
49
|
+
security_groups: obj["SecurityGroups"].join(", "),
|
50
|
+
ssh_key: obj["KeyName"],
|
51
|
+
created: obj["CreatedTime"]
|
52
|
+
})
|
53
|
+
end
|
54
|
+
|
55
|
+
module Flynn::CLI::Tools
|
56
|
+
|
57
|
+
Commander.configure do
|
58
|
+
include Flynn::CLI::Tools::CommanderSetup
|
59
|
+
program :description, "Administrates flynn clusters on AWS"
|
60
|
+
|
61
|
+
global_option "-y", "--yes", "Assume 'yes' to all prompts and run non-interactively." do
|
62
|
+
Flynn::CLI::Tools.options[:yes] = true
|
63
|
+
end
|
64
|
+
|
65
|
+
command :list do |c|
|
66
|
+
|
67
|
+
c.description = "Lists existing flynn clusters"
|
68
|
+
|
69
|
+
c.action do |args, opts|
|
70
|
+
|
71
|
+
# Find all auto scaling groups
|
72
|
+
res = JSON.parse(Flynn::CLI::Tools.capture "aws autoscaling describe-auto-scaling-groups")
|
73
|
+
|
74
|
+
# Find only the ones that are flynn tagged
|
75
|
+
rows = []
|
76
|
+
res["AutoScalingGroups"].each do |row|
|
77
|
+
|
78
|
+
if tag_value(row, "Platform") == "flynn"
|
79
|
+
rows.push asg_table_row(row)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
puts "\nFlynn auto scaling groups...\n\n"
|
85
|
+
tp rows
|
86
|
+
puts ""
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
command :"list-configs" do |c|
|
93
|
+
|
94
|
+
c.description = "Lists existing flynn launch configurations"
|
95
|
+
|
96
|
+
c.action do |args, opts|
|
97
|
+
|
98
|
+
# Find all launch configurations
|
99
|
+
res = JSON.parse(Flynn::CLI::Tools.capture "aws autoscaling describe-launch-configurations")
|
100
|
+
|
101
|
+
# Find only the ones that are flynn related
|
102
|
+
rows = []
|
103
|
+
res["LaunchConfigurations"].each do |row|
|
104
|
+
|
105
|
+
if row["LaunchConfigurationName"].start_with? "Flynn Platform"
|
106
|
+
|
107
|
+
rows.push lc_table_row(row)
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
puts "\nFlynn launch configurations...\n\n"
|
114
|
+
tp rows
|
115
|
+
puts ""
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
command :"list-images" do |c|
|
122
|
+
|
123
|
+
c.description = "Lists the AMIs flynn uses by version"
|
124
|
+
|
125
|
+
c.option "--for-version VERSION", "Lists the AMI used by a specific flynn version"
|
126
|
+
|
127
|
+
c.action do |args, opts|
|
128
|
+
|
129
|
+
# Pull a specific version?
|
130
|
+
if opts.for_version
|
131
|
+
puts "\nFlynn AMI for version #{opts.for_version} in region #{Flynn::CLI::Tools.aws_region}...\n\n"
|
132
|
+
tp Flynn::CLI::Tools.flynn_images opts.for_version
|
133
|
+
puts ""
|
134
|
+
else
|
135
|
+
puts "\nFlynn AMIs for region #{Flynn::CLI::Tools.aws_region}...\n\n"
|
136
|
+
tp Flynn::CLI::Tools.flynn_images
|
137
|
+
puts ""
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
command :"latest-version" do |c|
|
145
|
+
|
146
|
+
c.description = "Shows the latest version released"
|
147
|
+
|
148
|
+
c.action do |args, opts|
|
149
|
+
res = JSON.parse HTTParty.get("https://api.github.com/repos/flynn/flynn/tags").body
|
150
|
+
puts res[0]["name"].strip
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
data/bin/flynn-dns
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'table_print'
|
4
|
+
require 'commander'
|
5
|
+
|
6
|
+
# Custom libs
|
7
|
+
$:.unshift File.join(File.dirname(__FILE__), "..")
|
8
|
+
require 'lib/flynn/cli/tools'
|
9
|
+
require 'lib/flynn/cli/tools/cloudflare'
|
10
|
+
|
11
|
+
tp.set :max_width, 100
|
12
|
+
|
13
|
+
module Flynn::CLI::Tools
|
14
|
+
|
15
|
+
IP_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
16
|
+
TABLE_FIELDS = [:id, :type, :name, :ttl, :content]
|
17
|
+
|
18
|
+
Commander.configure do
|
19
|
+
include CommanderSetup
|
20
|
+
program :description, "Administrates DNS for a flynn cluster"
|
21
|
+
|
22
|
+
global_option "-y", "--yes", "Assume 'yes' to all prompts and run non-interactively." do
|
23
|
+
Flynn::CLI::Tools.options[:yes] = true
|
24
|
+
end
|
25
|
+
|
26
|
+
command :list do |c|
|
27
|
+
|
28
|
+
c.description = "Outputs DNS info for a cluster"
|
29
|
+
|
30
|
+
c.action do |args, opts|
|
31
|
+
|
32
|
+
name = "#{Flynn::CLI::Tools.flynn_cluster}.#{ENV['CLOUDFLARE_ZONE']}"
|
33
|
+
|
34
|
+
puts "\nDNS records for #{name}...\n\n"
|
35
|
+
tp CloudFlare.get("/zones/#{CloudFlare.zone_identifier}/dns_records?name=#{name},*.#{name}"), *TABLE_FIELDS
|
36
|
+
puts ""
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
command :"remove-cluster" do |c|
|
43
|
+
|
44
|
+
c.description = "Removes all DNS entries for the cluster"
|
45
|
+
|
46
|
+
c.action do |args, opts|
|
47
|
+
|
48
|
+
name = "#{Flynn::CLI::Tools.flynn_cluster}.#{ENV['CLOUDFLARE_ZONE']}"
|
49
|
+
|
50
|
+
# List the entries to be removed
|
51
|
+
entries = CloudFlare.get("/zones/#{CloudFlare.zone_identifier}/dns_records?name=#{name},*.#{name}&type=CNAME,A")
|
52
|
+
puts "\nDNS records to be removed for #{name}...\n\n"
|
53
|
+
tp [entries], *TABLE_FIELDS
|
54
|
+
|
55
|
+
# Ask
|
56
|
+
agreed = agree "This will remove the DNS entries listed above. Are you sure? (y/n)" unless Flynn::CLI::Tools.options[:yes]
|
57
|
+
if agreed || Flynn::CLI::Tools.options[:yes]
|
58
|
+
|
59
|
+
# Remove the records
|
60
|
+
puts ""
|
61
|
+
entries.each do |entry|
|
62
|
+
CloudFlare.delete("/zones/#{CloudFlare.zone_identifier}/dns_records/#{entry['id']}")
|
63
|
+
puts "Removed #{entry['type']} record for #{entry['content']}"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
puts ""
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
command :"add-ip" do |c|
|
75
|
+
|
76
|
+
c.description = "Adds an A record for the given IP to the cluster"
|
77
|
+
|
78
|
+
c.action do |args, opts|
|
79
|
+
|
80
|
+
# Verify the IP address
|
81
|
+
ip = args[0]
|
82
|
+
unless ip.match IP_REGEX
|
83
|
+
Flynn::CLI::Tools.logger.error "add-ip: Invalid IP address: #{ip}"
|
84
|
+
puts "Invalid IP address. Given: #{ip}"
|
85
|
+
exit 1
|
86
|
+
end
|
87
|
+
|
88
|
+
name = "#{Flynn::CLI::Tools.flynn_cluster}.#{ENV['CLOUDFLARE_ZONE']}"
|
89
|
+
agreed = agree "Add A record for #{ip} to #{name}? (y/n)" unless Flynn::CLI::Tools.options[:yes]
|
90
|
+
|
91
|
+
# Ensure the CNAME record exists
|
92
|
+
req = {
|
93
|
+
body: {
|
94
|
+
type: "CNAME",
|
95
|
+
name: "*.#{name}",
|
96
|
+
content: name,
|
97
|
+
ttl: 1
|
98
|
+
}.to_json
|
99
|
+
}
|
100
|
+
res = CloudFlare.raw_post("/zones/#{CloudFlare.zone_identifier}/dns_records", req)
|
101
|
+
if res["success"]
|
102
|
+
puts "\nAdded CNAME record for cluster...\n\n"
|
103
|
+
tp [res["result"]], *TABLE_FIELDS
|
104
|
+
end
|
105
|
+
|
106
|
+
# Add the record
|
107
|
+
if agreed || Flynn::CLI::Tools.options[:yes]
|
108
|
+
req = {
|
109
|
+
body: {
|
110
|
+
type: "A",
|
111
|
+
name: name,
|
112
|
+
content: ip,
|
113
|
+
ttl: 1
|
114
|
+
}.to_json
|
115
|
+
}
|
116
|
+
res = CloudFlare.post("/zones/#{CloudFlare.zone_identifier}/dns_records", req)
|
117
|
+
puts "\nAdded DNS record...\n\n"
|
118
|
+
tp [res], *TABLE_FIELDS
|
119
|
+
puts ""
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
command :"remove-ip" do |c|
|
127
|
+
|
128
|
+
c.description = "Removes the A record of the given IP from the cluster"
|
129
|
+
|
130
|
+
c.action do |args, opts|
|
131
|
+
|
132
|
+
# Verify the IP addrss
|
133
|
+
ip = args[0]
|
134
|
+
unless ip.match IP_REGEX
|
135
|
+
Flynn::CLI::Tools.logger.error "remove-ip: Invalid IP address: #{ip}"
|
136
|
+
puts "Invalid IP address. Given: #{ip}"
|
137
|
+
exit 1
|
138
|
+
end
|
139
|
+
|
140
|
+
name = "#{Flynn::CLI::Tools.flynn_cluster}.#{ENV['CLOUDFLARE_ZONE']}"
|
141
|
+
agreed = agree "Delete A record for #{ip} from #{name}? (y/n)" unless Flynn::CLI::Tools.options[:yes]
|
142
|
+
|
143
|
+
# Remove the record
|
144
|
+
if agreed || Flynn::CLI::Tools.options[:yes]
|
145
|
+
|
146
|
+
# Find the record
|
147
|
+
record = nil
|
148
|
+
entries = CloudFlare.get("/zones/#{CloudFlare.zone_identifier}/dns_records?name=#{name}&type=A")
|
149
|
+
entries.each do |entry|
|
150
|
+
record = entry if entry['content'] == ip
|
151
|
+
end
|
152
|
+
unless record
|
153
|
+
Flynn::CLI::Tools.logger.error "remove-ip: IP address not found in cluster #{Flynn::CLI::Tools.flynn_cluster}: #{ip}"
|
154
|
+
exit 1
|
155
|
+
end
|
156
|
+
|
157
|
+
# Remove it
|
158
|
+
CloudFlare.delete("/zones/#{CloudFlare.zone_identifier}/dns_records/#{record['id']}")
|
159
|
+
|
160
|
+
puts "\nRemoved DNS record...\n\n"
|
161
|
+
tp [record], *TABLE_FIELDS
|
162
|
+
|
163
|
+
# Remove the CNAME if the last record was deleted
|
164
|
+
if entries.length == 1
|
165
|
+
|
166
|
+
# Find the CNAME
|
167
|
+
entries = CloudFlare.raw_get("/zones/#{CloudFlare.zone_identifier}/dns_records?name=*.#{name}&type=CNAME")
|
168
|
+
if entries["success"] && entries["result"].length == 1
|
169
|
+
|
170
|
+
# Remove it
|
171
|
+
Flynn::CLI::Tools.logger.info "remove-ip: Removing CNAME for cluster #{Flynn::CLI::Tools.flynn_cluster}"
|
172
|
+
CloudFlare.delete("/zones/#{CloudFlare.zone_identifier}/dns_records/#{entries["result"][0]['id']}")
|
173
|
+
|
174
|
+
puts "\nRemoved CNAME record for cluster...\n\n"
|
175
|
+
tp [entries["result"]], *TABLE_FIELDS
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
puts ""
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
data/bin/flynn-migrate
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# Rename the remote
|
4
|
+
git remote remove flynn
|
5
|
+
|
6
|
+
# Create the app
|
7
|
+
flynn create $(basename $(pwd))
|
8
|
+
|
9
|
+
# Add the environment
|
10
|
+
cat .flynn-env | xargs flynn env set
|
11
|
+
|
12
|
+
# Add the routes
|
13
|
+
bash .flynn-routes
|
14
|
+
|
15
|
+
# Create a release
|
16
|
+
flynn-release
|
17
|
+
|
18
|
+
# Run post-create
|
19
|
+
bash .flynn-post-create
|
20
|
+
|
21
|
+
# Show running processes
|
22
|
+
flynn ps
|
data/bin/flynn-release
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Custom libs
|
4
|
+
$:.unshift File.join(File.dirname(__FILE__), "..")
|
5
|
+
require 'lib/flynn/cli/tools'
|
6
|
+
|
7
|
+
module Flynn::CLI::Tools
|
8
|
+
|
9
|
+
# Default options
|
10
|
+
self.options.merge!({
|
11
|
+
release: true,
|
12
|
+
tag: true,
|
13
|
+
tag_prefix: app_env + "-release-"
|
14
|
+
})
|
15
|
+
|
16
|
+
# Build options parser
|
17
|
+
OptionParser.new do |opts|
|
18
|
+
opts.on "--no-tag", "Skips tagging the release" do |v|
|
19
|
+
options[:tag] = v
|
20
|
+
end
|
21
|
+
opts.on "--no-build", "Skips pushing to flynn repo" do |v|
|
22
|
+
options[:release] = v
|
23
|
+
end
|
24
|
+
opts.on "-r REMOTE", "--remote REMOTE", String, "Set the git remote to release to" do |v|
|
25
|
+
options[:remote] = v
|
26
|
+
end
|
27
|
+
opts.add_general_options!
|
28
|
+
end.parse!
|
29
|
+
|
30
|
+
# Attempt a release if configured
|
31
|
+
if options[:release]
|
32
|
+
|
33
|
+
system "git push #{options[:remote]}"
|
34
|
+
exit_if_failed
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
# Attempt to tag the release
|
39
|
+
if options[:tag]
|
40
|
+
|
41
|
+
# Determine the tag prefix
|
42
|
+
prefix = app_env + "-release-"
|
43
|
+
|
44
|
+
# Find the last release id
|
45
|
+
release = capture "flynn release -q | head -n 1"
|
46
|
+
logger.info "Tagging release #{release}"
|
47
|
+
|
48
|
+
# Find the last release number
|
49
|
+
num = capture "git tag | egrep '^#{prefix}[0-9]+' | wc -l"
|
50
|
+
last_release = num.to_i rescue 0
|
51
|
+
|
52
|
+
# Check the last tag
|
53
|
+
create_release_tag = true
|
54
|
+
if last_release > 0
|
55
|
+
|
56
|
+
last_commit = capture "git rev-list -n 1 #{prefix}#{num}"
|
57
|
+
head_commit = capture "git rev-list -n 1 HEAD"
|
58
|
+
|
59
|
+
if last_commit == head_commit
|
60
|
+
logger.info "Tag #{prefix}#{num} already exists"
|
61
|
+
create_release_tag = false
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
# Create a new release tag if needed
|
67
|
+
if create_release_tag
|
68
|
+
tag = prefix + (num.to_i + 1).to_s
|
69
|
+
system "git tag -a #{tag} -m 'Flynn release #{release} on cluster #{flynn_cluster}'"
|
70
|
+
system "git push origin #{tag}"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Update the current environment tag
|
74
|
+
tag = "#{app_env}-current"
|
75
|
+
system "git tag -f -a #{tag} -m 'Flyyn release #{release} on cluster #{flynn_cluster}'"
|
76
|
+
system "git push origin #{tag} --force"
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/dev-bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "flynn/cli/tools"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/dev-bin/setup
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require_relative 'tools/commander_setup'
|
2
|
+
require_relative 'tools/logger'
|
3
|
+
require_relative 'tools/option_parser'
|
4
|
+
|
5
|
+
# Ensure tools are present
|
6
|
+
if `which aws`.empty?
|
7
|
+
raise RuntimeError, "aws executable could not be found on $PATH. Try running `brew install awscli`."
|
8
|
+
end
|
9
|
+
if `which flynn`.empty?
|
10
|
+
raise RuntimeError, "flynn executable could not be found on $PATH. See https://flynn.io/docs/cli#installation."
|
11
|
+
end
|
12
|
+
|
13
|
+
module Flynn
|
14
|
+
module CLI
|
15
|
+
module Tools
|
16
|
+
|
17
|
+
class << self
|
18
|
+
attr_accessor :options
|
19
|
+
attr_accessor :logger
|
20
|
+
end
|
21
|
+
|
22
|
+
# Intialization
|
23
|
+
self.logger = Logger.new STDERR
|
24
|
+
logger.level = Logger::WARN
|
25
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
26
|
+
date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
|
27
|
+
"[#{date_format}] #{severity}: #{msg}\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Options initialization
|
31
|
+
self.options = {
|
32
|
+
remote: "flynn",
|
33
|
+
quiet: false,
|
34
|
+
dry_run: false
|
35
|
+
}
|
36
|
+
|
37
|
+
def self.flynn_cluster
|
38
|
+
@cluster ||= self.capture "flynn cluster default | tail -n 1 | awk '{print $1}'"
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.flynn_cluster= cluster
|
42
|
+
@cluster = cluster
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.app_env
|
46
|
+
@app_env ||= self.capture "cat .flynn-env | grep RAILS_ENV | cut -f 2 -d ="
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.app_env= app
|
50
|
+
@app_env = app
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.flynn_images version = nil
|
54
|
+
|
55
|
+
# Return the full list of images when not asking for a specific version
|
56
|
+
images = self._flynn_images
|
57
|
+
return images unless version
|
58
|
+
|
59
|
+
# Return the image that matches when a specific version is given
|
60
|
+
images.each do |img|
|
61
|
+
return [img] if img[:flynn_version] <= version
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
def self._flynn_images
|
67
|
+
|
68
|
+
# Short-circuit
|
69
|
+
return @images if @images
|
70
|
+
|
71
|
+
# Load from source
|
72
|
+
require 'json'
|
73
|
+
require 'httparty'
|
74
|
+
res = JSON.parse HTTParty.get("https://dl.flynn.io/ec2/images.json").body
|
75
|
+
|
76
|
+
# Find only the ones that are for the current region
|
77
|
+
@images = []
|
78
|
+
res["versions"].each do |version|
|
79
|
+
image = version["images"].select{|img| img["region"] == self.aws_region}[0]
|
80
|
+
@images.push({
|
81
|
+
flynn_version: version["version"],
|
82
|
+
region: image["region"],
|
83
|
+
image: image["id"],
|
84
|
+
name: image["name"]
|
85
|
+
})
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return it
|
89
|
+
@images
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.aws_region
|
94
|
+
@region ||= self.capture "aws configure get region"
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.system! *args
|
98
|
+
self.system *args, allow_dry: false
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.system *args, allow_dry: true
|
102
|
+
dry = allow_dry && options[:dry_run]
|
103
|
+
logger.debug "#{dry ? 'Dry ' : ''}Running: #{args.join " "}" unless options[:quiet]
|
104
|
+
super *args unless dry
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.capture command
|
108
|
+
logger.debug "Running: #{command}" unless options[:quiet]
|
109
|
+
`#{command}`.strip
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.exit_if_failed
|
113
|
+
exit $?.exitstatus unless $?.success?
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
['CLOUDFLARE_EMAIL', 'CLOUDFLARE_KEY', 'CLOUDFLARE_ZONE'].each do |v|
|
5
|
+
unless ENV[v]
|
6
|
+
puts "Please define the #{v} environment variable"
|
7
|
+
exit 1
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module Flynn
|
12
|
+
module CLI
|
13
|
+
module Tools
|
14
|
+
class CloudFlare
|
15
|
+
include HTTParty
|
16
|
+
base_uri 'https://api.cloudflare.com/client/v4'
|
17
|
+
|
18
|
+
# Default headers
|
19
|
+
headers({
|
20
|
+
"X-Auth-Email": ENV['CLOUDFLARE_EMAIL'],
|
21
|
+
"X-Auth-Key": ENV['CLOUDFLARE_KEY'],
|
22
|
+
"Content-Type": "application/json"
|
23
|
+
})
|
24
|
+
|
25
|
+
# Override common methods
|
26
|
+
class << self
|
27
|
+
[:get, :post, :delete].each do |m|
|
28
|
+
|
29
|
+
alias_method :"_#{m}", m
|
30
|
+
|
31
|
+
# Override the base method
|
32
|
+
define_method m do |*args|
|
33
|
+
resp = self.send :"raw_#{m}", *args
|
34
|
+
unless resp["success"]
|
35
|
+
Flynn::CLI::Tools.logger.error "Request failed: #{resp["errors"]}"
|
36
|
+
exit 2
|
37
|
+
end
|
38
|
+
resp["result"]
|
39
|
+
end
|
40
|
+
|
41
|
+
# Define a raw version
|
42
|
+
define_method :"raw_#{m}" do |*args|
|
43
|
+
Flynn::CLI::Tools.logger.info "#{m.upcase} #{base_uri}#{args[0]}"
|
44
|
+
JSON.parse(self.send(:"_#{m}", *args).body)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Pulls the zone identifier for our domain
|
51
|
+
def self.zone_identifier
|
52
|
+
@zone_identifier ||= self.get("/zones?name=#{ENV['CLOUDFLARE_ZONE']}")[0]["id"]
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Provides defaults for programs that use commander
|
2
|
+
module Flynn
|
3
|
+
module CLI
|
4
|
+
module Tools
|
5
|
+
module CommanderSetup
|
6
|
+
def self.included mod
|
7
|
+
mod.class_exec do
|
8
|
+
program :version, "0.0.0"
|
9
|
+
default_command :help
|
10
|
+
|
11
|
+
global_option "--dry-run", "Prevents this command from making changes" do |v|
|
12
|
+
Flynn::CLI::Tools.options[:dry_run] = v
|
13
|
+
end
|
14
|
+
global_option "--verbose", "Sets log level to INFO" do |v|
|
15
|
+
Flynn::CLI::Tools.logger.level = Logger::INFO
|
16
|
+
end
|
17
|
+
global_option "--debug", "Sets log level to DEBUG" do |v|
|
18
|
+
Flynn::CLI::Tools.logger.level = Logger::DEBUG
|
19
|
+
end
|
20
|
+
if File.basename($0).start_with? "flynn-"
|
21
|
+
global_option "-c CLUSTER", "--cluster CLUSTER", String, "Set the flynn cluster to use" do |v|
|
22
|
+
Flynn::CLI::Tools.flynn_cluster = v
|
23
|
+
end
|
24
|
+
end
|
25
|
+
global_option "-q", "--quiet", "Disables logging" do |v|
|
26
|
+
Flynn::CLI::Tools.options[:quiet] = v
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Flynn
|
4
|
+
module CLI
|
5
|
+
module Tools
|
6
|
+
class Logger < Logger
|
7
|
+
def debug msg
|
8
|
+
super unless Flynn::CLI::Tools.options[:quiet]
|
9
|
+
end
|
10
|
+
def info msg
|
11
|
+
super unless Flynn::CLI::Tools.options[:quiet]
|
12
|
+
end
|
13
|
+
def warn msg
|
14
|
+
super unless Flynn::CLI::Tools.options[:quiet]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Flynn
|
4
|
+
module CLI
|
5
|
+
module Tools
|
6
|
+
class OptionParser < OptionParser
|
7
|
+
@@log_levels = [Logger::INFO, Logger::DEBUG]
|
8
|
+
def parse!
|
9
|
+
begin
|
10
|
+
super
|
11
|
+
rescue ::OptionParser::InvalidOption, ::OptionParser::MissingArgument
|
12
|
+
puts self
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
end
|
16
|
+
def add_general_options!
|
17
|
+
on "--dry-run", "Prevents this command from making changes" do |v|
|
18
|
+
Flynn::CLI::Tools.options[:dry_run] = v
|
19
|
+
end
|
20
|
+
on "--verbose", "Sets log level to INFO" do
|
21
|
+
Flynn::CLI::Tools.logger.level = Logger::INFO
|
22
|
+
end
|
23
|
+
on "--debug", "Sets log level to DEBUG" do
|
24
|
+
Flynn::CLI::Tools.logger.level = Logger::DEBUG
|
25
|
+
end
|
26
|
+
if File.basename($0).start_with? "flynn-"
|
27
|
+
on "-c CLUSTER", "--cluster CLUSTER", String, "Set the flynn cluster to use" do |v|
|
28
|
+
Flynn::CLI::Tools.flynn_cluster = v
|
29
|
+
end
|
30
|
+
end
|
31
|
+
on "-q", "--quiet", "Disables logging" do |v|
|
32
|
+
Flynn::CLI::Tools.options[:quiet] = v
|
33
|
+
end
|
34
|
+
on "-h", "--help", "Prints this help" do
|
35
|
+
puts self
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: flynn-cli-tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kenaniah Cerny
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: table_print
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: commander
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: json
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: httparty
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- kenaniah@gmail.com
|
100
|
+
executables:
|
101
|
+
- flynn-cluster
|
102
|
+
- flynn-dns
|
103
|
+
- flynn-migrate
|
104
|
+
- flynn-release
|
105
|
+
extensions: []
|
106
|
+
extra_rdoc_files: []
|
107
|
+
files:
|
108
|
+
- bin/flynn-cluster
|
109
|
+
- bin/flynn-dns
|
110
|
+
- bin/flynn-migrate
|
111
|
+
- bin/flynn-release
|
112
|
+
- dev-bin/console
|
113
|
+
- dev-bin/setup
|
114
|
+
- lib/flynn/cli/tools.rb
|
115
|
+
- lib/flynn/cli/tools/cloudflare.rb
|
116
|
+
- lib/flynn/cli/tools/commander_setup.rb
|
117
|
+
- lib/flynn/cli/tools/logger.rb
|
118
|
+
- lib/flynn/cli/tools/option_parser.rb
|
119
|
+
homepage: https://github.com/kenaniah/flynn-cli-tools
|
120
|
+
licenses: []
|
121
|
+
metadata: {}
|
122
|
+
post_install_message:
|
123
|
+
rdoc_options: []
|
124
|
+
require_paths:
|
125
|
+
- lib
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
requirements: []
|
137
|
+
rubyforge_project:
|
138
|
+
rubygems_version: 2.6.8
|
139
|
+
signing_key:
|
140
|
+
specification_version: 4
|
141
|
+
summary: A collection of CLI tools for administrating Flynn (flynn.io)
|
142
|
+
test_files: []
|