meroku 2.0.8 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|