meroku 2.0.8 → 2.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -5
- data/bin/meroku +1 -1
- data/circle.yml +23 -0
- data/frontend/Gemfile +5 -2
- data/frontend/Gemfile.lock +5 -2
- data/frontend/app/controllers/application_controller.rb +1 -0
- data/frontend/app/controllers/apps_controller.rb +46 -48
- data/frontend/app/controllers/publickeys_controller.rb +45 -46
- data/frontend/app/controllers/users/registrations_controller.rb +0 -15
- data/frontend/app/controllers/users/sessions_controller.rb +12 -3
- data/frontend/app/lib/cmd.rb +11 -0
- data/frontend/app/models/app.rb +18 -11
- data/frontend/app/models/publickey.rb +1 -1
- data/frontend/app/models/user.rb +5 -4
- data/frontend/app/policies/application_policy.rb +53 -0
- data/frontend/app/policies/publickey_policy.rb +7 -0
- data/frontend/app/serializable/serializable_user.rb +2 -1
- data/frontend/app/views/layouts/application.html.erb +1 -1
- data/frontend/config/database.yml +72 -10
- data/frontend/config/routes.rb +6 -14
- data/frontend/db/migrate/20171028150506_add_apisecret_to_users.rb +6 -0
- data/frontend/etc_nginx_sites-enabled_default +1 -1
- data/frontend/public/Meroku.html +140 -0
- data/frontend/public/Meroku/Api.html +129 -0
- data/frontend/public/Meroku/Api/Request.html +221 -0
- data/frontend/public/Meroku/Aws.html +212 -0
- data/frontend/public/Meroku/Aws/Ec2.html +477 -0
- data/frontend/public/Meroku/CLI.html +784 -0
- data/frontend/public/Meroku/CLI/AdminUser.html +192 -0
- data/frontend/public/Meroku/CLI/Help.html +224 -0
- data/frontend/public/Meroku/CLI/Secrets.html +191 -0
- data/frontend/public/Meroku/CLI/Session.html +460 -0
- data/frontend/public/Meroku/CLI/User.html +182 -0
- data/frontend/public/Meroku/Extensions.html +405 -0
- data/frontend/public/Meroku/Infrastructure.html +279 -0
- data/frontend/public/Meroku/Infrastructure/Node.html +785 -0
- data/frontend/public/Meroku/Infrastructure/Server.html +373 -0
- data/frontend/public/Meroku/Node.html +845 -0
- data/frontend/public/Meroku/Tunnel.html +701 -0
- data/frontend/public/Meroku/Tunnelable.html +243 -0
- data/frontend/public/_index.html +273 -0
- data/frontend/public/class_list.html +51 -0
- data/frontend/public/css/common.css +1 -0
- data/frontend/public/css/full_list.css +58 -0
- data/frontend/public/css/style.css +492 -0
- data/frontend/public/file.README.html +181 -0
- data/frontend/public/file_list.html +56 -0
- data/frontend/public/frames.html +17 -0
- data/frontend/public/index.html +181 -0
- data/frontend/public/js/app.js +248 -0
- data/frontend/public/js/full_list.js +216 -0
- data/frontend/public/js/jquery.js +4 -0
- data/frontend/public/method_list.html +395 -0
- data/frontend/public/robots.txt +2 -1
- data/frontend/public/top-level-namespace.html +110 -0
- data/frontend/test/policies/publickey_policy_test.rb +19 -0
- data/lib/meroku.rb +9 -7
- data/lib/meroku/api.rb +8 -0
- data/lib/meroku/api/request.rb +17 -0
- data/lib/meroku/aws.rb +14 -0
- data/lib/meroku/aws/ec2.rb +59 -0
- data/lib/meroku/cli.rb +80 -81
- data/lib/meroku/cli/help.rb +27 -0
- data/lib/meroku/cli/secrets.rb +13 -0
- data/lib/meroku/cli/session.rb +32 -51
- data/lib/meroku/extensions.rb +32 -0
- data/lib/meroku/infrastructure.rb +14 -17
- data/lib/meroku/infrastructure/server.rb +20 -0
- data/lib/meroku/node.rb +113 -0
- data/lib/meroku/tunnelable.rb +31 -0
- data/lib/meroku/version.rb +1 -1
- data/modified-cedar-14.sh +0 -4
- metadata +50 -9
- data/frontend/app/controllers/pages_controller.rb +0 -4
- data/frontend/app/views/pages/landing.html.erb +0 -2
- data/frontend/db/migrate/20171025193627_add_token_to_users.rb +0 -5
- data/lib/meroku/cli/admin_user.rb +0 -20
- data/lib/meroku/cli/user.rb +0 -14
- data/lib/meroku/infrastructure/node.rb +0 -102
- data/lib/meroku/tunnel.rb +0 -56
data/frontend/public/robots.txt
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
User-agent: *
|
2
|
+
Disallow: /
|
@@ -0,0 +1,110 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.9.9
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
pathId = "";
|
19
|
+
relpath = '';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
|
23
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
24
|
+
|
25
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
26
|
+
|
27
|
+
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="class_list.html?1"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
38
|
+
|
39
|
+
<a href="_index.html">Index</a> »
|
40
|
+
|
41
|
+
|
42
|
+
<span class="title">Top Level Namespace</span>
|
43
|
+
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div id="search">
|
47
|
+
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
49
|
+
href="class_list.html">
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
56
|
+
</a>
|
57
|
+
|
58
|
+
</div>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div id="content"><h1>Top Level Namespace
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
</h1>
|
67
|
+
<div class="box_info">
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
</div>
|
80
|
+
|
81
|
+
<h2>Defined Under Namespace</h2>
|
82
|
+
<p class="children">
|
83
|
+
|
84
|
+
|
85
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="Meroku.html" title="Meroku (module)">Meroku</a></span>
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
</p>
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
</div>
|
101
|
+
|
102
|
+
<div id="footer">
|
103
|
+
Generated on Tue Oct 31 19:39:54 2017 by
|
104
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
105
|
+
0.9.9 (ruby-2.4.2).
|
106
|
+
</div>
|
107
|
+
|
108
|
+
</div>
|
109
|
+
</body>
|
110
|
+
</html>
|
data/lib/meroku.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
+
require "fileutils"
|
1
2
|
require "active_support/core_ext/object/try"
|
2
3
|
require "net/ssh"
|
3
|
-
require
|
4
|
+
require "net/http"
|
4
5
|
require "escape"
|
5
6
|
require "aws-sdk-ec2"
|
6
7
|
require "dotenv"
|
7
8
|
require "byebug"
|
8
|
-
require
|
9
|
+
require "rest-client"
|
10
|
+
require "meroku/extensions"
|
11
|
+
require "meroku/aws"
|
9
12
|
require "meroku/version"
|
10
|
-
require "meroku/
|
11
|
-
require "meroku/
|
12
|
-
require "meroku/cli/admin_user"
|
13
|
+
require "meroku/tunnelable"
|
14
|
+
require "meroku/node"
|
13
15
|
require "meroku/infrastructure"
|
16
|
+
require "meroku/api"
|
14
17
|
require "meroku/cli"
|
15
18
|
|
16
|
-
|
19
|
+
# My Heroku (Meroku)
|
17
20
|
module Meroku
|
18
|
-
|
19
21
|
end
|
data/lib/meroku/api.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Meroku
|
2
|
+
module Api
|
3
|
+
# Wrapper around RestClient.post
|
4
|
+
module Request
|
5
|
+
def self.post(url, data)
|
6
|
+
response = RestClient.post(url, data.to_json,
|
7
|
+
timeout: 1,
|
8
|
+
content_type: :json,
|
9
|
+
accept: :json)
|
10
|
+
r = JSON.parse(response)
|
11
|
+
yield(r["data"]) if r.key?("data")
|
12
|
+
return unless r.key?("errors") && r["errors"].size.positive?
|
13
|
+
puts "error: #{r['errors'].map { |x| x['detail'] }.join('. ')}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/meroku/aws.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'meroku/aws/ec2'
|
2
|
+
|
3
|
+
module Meroku
|
4
|
+
# Stuff related to Amazon Web Services
|
5
|
+
module Aws
|
6
|
+
IP = '34.239.241.218'
|
7
|
+
|
8
|
+
KEY_NAME = '~/crypto/meroku/meroku.id_rsa'
|
9
|
+
|
10
|
+
def self.bucket_url
|
11
|
+
"http://www.sam-we.com/dropbox/meroku-#{ENV['SECRET']}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
module Meroku
|
3
|
+
module Aws
|
4
|
+
# Logic related to the ec2 instances we use as servers
|
5
|
+
module Ec2
|
6
|
+
def tag
|
7
|
+
{
|
8
|
+
resource_type: 'instance',
|
9
|
+
tags: [
|
10
|
+
{
|
11
|
+
key: 'Name',
|
12
|
+
value: 'node'
|
13
|
+
}
|
14
|
+
]
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def make_instance
|
19
|
+
ec2_client.run_instances(
|
20
|
+
image_id: 'ami-841f46ff',
|
21
|
+
min_count: 1,
|
22
|
+
max_count: 1,
|
23
|
+
key_name: 'meroku.id_rsa',
|
24
|
+
instance_type: 't2.micro',
|
25
|
+
tag_specifications: [tag]
|
26
|
+
).instances.first
|
27
|
+
end
|
28
|
+
|
29
|
+
def ec2_client
|
30
|
+
::Aws::EC2::Client.new(
|
31
|
+
region: 'us-east-1',
|
32
|
+
credentials: ::Aws::Credentials.new(
|
33
|
+
ENV['AWS_ACCESS_KEY'],
|
34
|
+
ENV['AWS_SECRET']
|
35
|
+
)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.ec2_client
|
40
|
+
::Aws::EC2::Client.new(
|
41
|
+
region: 'us-east-1',
|
42
|
+
credentials: ::Aws::Credentials.new(
|
43
|
+
ENV['AWS_ACCESS_KEY'],
|
44
|
+
ENV['AWS_SECRET']
|
45
|
+
)
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.associate_address(eipalloc, id)
|
50
|
+
retries ||= 0
|
51
|
+
ec2_client.associate_address(allocation_id: eipalloc, instance_id: id)
|
52
|
+
rescue ::Aws::EC2::Errors::InvalidInstanceID
|
53
|
+
sleep 1
|
54
|
+
puts 'retrying associate_address()'
|
55
|
+
retry if (retries += 1) < 15
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/meroku/cli.rb
CHANGED
@@ -1,105 +1,104 @@
|
|
1
|
-
require
|
1
|
+
require 'meroku/cli/help'
|
2
|
+
require 'meroku/cli/secrets'
|
3
|
+
require 'meroku/cli/session'
|
2
4
|
|
3
5
|
module Meroku
|
6
|
+
# The CLI is used by end users and also maintainers
|
4
7
|
module CLI
|
5
|
-
|
6
|
-
def help
|
7
|
-
<<~HEREDOC
|
8
|
-
Usage: meroku command subcommand
|
9
|
-
|
10
|
-
Examples
|
11
|
-
|
12
|
-
meroku signup # if you havent done already
|
13
|
-
|
14
|
-
meroku create
|
15
|
-
|
16
|
-
meroku keys:add
|
17
|
-
|
18
|
-
meroku infrastrucuture spawn # Spawns server
|
19
|
-
|
20
|
-
HEREDOC
|
21
|
-
end
|
8
|
+
include Meroku::Aws::Ec2
|
22
9
|
|
23
10
|
def signup
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
puts "error: #{JSON.parse(response_json)["errors"].map{|x| x["detail"]}.join(".")}"
|
33
|
-
else
|
34
|
-
email = JSON.parse(response_json)["data"]["attributes"]["email"]
|
35
|
-
token = JSON.parse(response_json)["data"]["attributes"]["token"]
|
36
|
-
puts "Signed up #{email}"
|
37
|
-
dirname = File.dirname("#{Dir.home}/.meroku")
|
38
|
-
FileUtils.mkdir(dirname) if !File.directory?(dirname)
|
39
|
-
File.open("#{Dir.home}/.meroku/.token", 'w') { |file| file.write(token) }
|
11
|
+
email, pw = Meroku::Extensions.mgets(%i[email password])
|
12
|
+
Meroku::Api::Request.post(
|
13
|
+
'https://www.meroku.com/users.json',
|
14
|
+
user: { email: email, password: pw, password_confirmation: pw }
|
15
|
+
) do |response|
|
16
|
+
puts "Signed up #{response['attributes']['email']}"
|
17
|
+
save_setting('apiusername', response['attributes']['apiusername'])
|
18
|
+
save_setting('apisecret', response['attributes']['apisecret'])
|
40
19
|
end
|
20
|
+
true
|
41
21
|
end
|
42
22
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
url = "https://www.meroku.com/publickeys.json"
|
53
|
-
response_json = RestClient.post url, {:publickey=>{:name => name, :data=>data}, :token=>session.token}.to_json, timeout: 1, :content_type => :json, :accept => :json
|
54
|
-
|
55
|
-
if JSON.parse(response_json)["errors"] && JSON.parse(response_json)["errors"].size > 0
|
56
|
-
puts "error: #{JSON.parse(response_json)["errors"].map{|x| x["detail"]}.join(".")}"
|
57
|
-
else
|
58
|
-
name = JSON.parse(response_json)["data"]["attributes"]["name"]
|
59
|
-
puts "Added #{name}"
|
23
|
+
def login
|
24
|
+
email, password = Meroku::Extensions.mgets(%i[email password])
|
25
|
+
Meroku::Api::Request.post(
|
26
|
+
'https://www.meroku.com/users/sign_in.json',
|
27
|
+
user: { email: email, password: password }
|
28
|
+
) do |response|
|
29
|
+
puts "Signed in as #{response['attributes']['email']}"
|
30
|
+
save_setting('apiusername', response['attributes']['apiusername'])
|
31
|
+
save_setting('apisecret', response['attributes']['apisecret'])
|
60
32
|
end
|
33
|
+
true
|
61
34
|
end
|
62
35
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
puts JSON.parse(response_json)["errors"].map{|x| x["detail"]}.join(".")
|
70
|
-
else
|
71
|
-
name = JSON.parse(response_json)["data"]["attributes"]["name"]
|
72
|
-
puts "Created #{name}, adding git remote"
|
73
|
-
puts "git remote remove meroku"
|
74
|
-
`git remote remove meroku 2>/dev/null`
|
75
|
-
puts "git remote add meroku #{token}@www.meroku.com:#{name}.git"
|
76
|
-
`git remote add meroku #{token}@www.meroku.com:#{name}.git`
|
36
|
+
def logout
|
37
|
+
[
|
38
|
+
"#{Dir.home}/.meroku/.apiusername",
|
39
|
+
"#{Dir.home}/.meroku/.apisecret"
|
40
|
+
].each do |f|
|
41
|
+
File.delete(f) if File.exist?(f)
|
77
42
|
end
|
43
|
+
true
|
78
44
|
end
|
79
45
|
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
|
46
|
+
def create
|
47
|
+
Meroku::Api::Request.post(
|
48
|
+
'https://www.meroku.com/apps.json',
|
49
|
+
app: { name: 'unnamed' }, apisecret: `cat ~/.meroku/.apisecret`.chomp
|
50
|
+
) do |response|
|
51
|
+
puts "Created #{response['attributes']['name']}, adding git remote"
|
52
|
+
add_git_remote(
|
53
|
+
'meroku',
|
54
|
+
"#{apiusername}@www.meroku.com:#{response['attributes']['name']}.git"
|
55
|
+
)
|
84
56
|
end
|
85
57
|
true
|
86
58
|
end
|
87
59
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
60
|
+
def apiusername
|
61
|
+
`cat ~/.meroku/.apiusername.chomp`
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_git_remote(name, uri)
|
65
|
+
puts "git remote remove #{name}"
|
66
|
+
`git remote remove #{name} 2>/dev/null`
|
67
|
+
puts "git remote add #{name} #{uri}"
|
68
|
+
`git remote add #{name} #{uri}`
|
69
|
+
end
|
70
|
+
|
71
|
+
def keys_add
|
72
|
+
file = "#{Dir.home}/.ssh/id_rsa.pub"
|
73
|
+
apisecret = `cat ~/.meroku/.apisecret`.chomp
|
74
|
+
abort "error: #{file} not found" unless File.exist?(file)
|
75
|
+
Meroku::Api::Request.post(
|
76
|
+
'https://www.meroku.com/publickeys.json',
|
77
|
+
publickey: { name: 'id_rsa.pub', data: `cat ~/.ssh/id_rsa.pub`.chomp },
|
78
|
+
apisecret: apisecret
|
79
|
+
) do |response|
|
80
|
+
puts "Added #{response['attributes']['name']}"
|
98
81
|
end
|
99
|
-
|
82
|
+
true
|
100
83
|
end
|
101
84
|
|
102
|
-
|
85
|
+
def spawn
|
86
|
+
Meroku::CLI::Secrets.load(admin: true)
|
87
|
+
node = Meroku::Node.new
|
88
|
+
node.associate_address.configure_keys.add_sources.ubuntu_updates
|
89
|
+
node.install_packages.database_inits.git_clone.nginx_configs.start_rails
|
90
|
+
true
|
91
|
+
end
|
103
92
|
|
93
|
+
def despawn
|
94
|
+
Meroku::CLI::Secrets.load(admin: true)
|
95
|
+
Meroku::Infrastructure.each_server(&:shutdown)
|
96
|
+
true
|
97
|
+
end
|
104
98
|
|
99
|
+
def save_setting(name, value)
|
100
|
+
FileUtils.mkdir_p "#{Dir.home}/.meroku"
|
101
|
+
IO.write("#{Dir.home}/.meroku/.#{name}", value)
|
102
|
+
end
|
103
|
+
end
|
105
104
|
end
|