google-cloud-gemserver 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.yardopts +7 -0
- data/CONTRIBUTING.md +49 -0
- data/LICENSE +202 -0
- data/README.md +179 -0
- data/bin/console +7 -0
- data/bin/google-cloud-gemserver +5 -0
- data/bin/setup +6 -0
- data/lib/google/cloud/gemserver.rb +33 -0
- data/lib/google/cloud/gemserver/authentication.rb +254 -0
- data/lib/google/cloud/gemserver/backend.rb +33 -0
- data/lib/google/cloud/gemserver/backend/gemstash_server.rb +60 -0
- data/lib/google/cloud/gemserver/backend/key.rb +152 -0
- data/lib/google/cloud/gemserver/backend/stats.rb +149 -0
- data/lib/google/cloud/gemserver/backend/storage_sync.rb +186 -0
- data/lib/google/cloud/gemserver/cli.rb +174 -0
- data/lib/google/cloud/gemserver/cli/cloud_sql.rb +196 -0
- data/lib/google/cloud/gemserver/cli/project.rb +143 -0
- data/lib/google/cloud/gemserver/cli/request.rb +130 -0
- data/lib/google/cloud/gemserver/cli/server.rb +337 -0
- data/lib/google/cloud/gemserver/configuration.rb +505 -0
- data/lib/google/cloud/gemserver/gcs.rb +171 -0
- data/lib/google/cloud/gemserver/version.rb +23 -0
- data/lib/patched/configuration.rb +29 -0
- data/lib/patched/dependencies.rb +33 -0
- data/lib/patched/env.rb +42 -0
- data/lib/patched/gem_pusher.rb +28 -0
- data/lib/patched/gem_yanker.rb +28 -0
- data/lib/patched/storage.rb +37 -0
- data/lib/patched/web.rb +64 -0
- metadata +271 -0
@@ -0,0 +1,196 @@
|
|
1
|
+
# Copyright 2017 Google Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "google/cloud/gemserver"
|
16
|
+
require "securerandom"
|
17
|
+
require "google/apis/sqladmin_v1beta4"
|
18
|
+
require "googleauth"
|
19
|
+
require "yaml"
|
20
|
+
|
21
|
+
module Google
|
22
|
+
module Cloud
|
23
|
+
module Gemserver
|
24
|
+
class CLI
|
25
|
+
##
|
26
|
+
# # CloudSQL
|
27
|
+
#
|
28
|
+
# CloudSQL manages the creation of a Cloud SQL instance as well as
|
29
|
+
# the necessary database and user creation.
|
30
|
+
#
|
31
|
+
class CloudSQL
|
32
|
+
##
|
33
|
+
# Permits SQL admin operations with the Cloud SQL API.
|
34
|
+
SCOPES = ["https://www.googleapis.com/auth/sqlservice.admin"]
|
35
|
+
.freeze
|
36
|
+
|
37
|
+
##
|
38
|
+
# An alias for the SqladminV1beta4 module.
|
39
|
+
SQL = Google::Apis::SqladminV1beta4
|
40
|
+
|
41
|
+
##
|
42
|
+
# The name of the database used to store gemserver data.
|
43
|
+
# @return [String]
|
44
|
+
attr_reader :db
|
45
|
+
|
46
|
+
##
|
47
|
+
# The name of the default user created to access the database.
|
48
|
+
# @return [String]
|
49
|
+
attr_reader :user
|
50
|
+
|
51
|
+
##
|
52
|
+
# The password of the default user created to access the database.
|
53
|
+
# @return [String]
|
54
|
+
attr_reader :pwd
|
55
|
+
|
56
|
+
##
|
57
|
+
# The project ID of the project the gemserver will be deployed to.
|
58
|
+
# @return [String]
|
59
|
+
attr_reader :proj_id
|
60
|
+
|
61
|
+
##
|
62
|
+
# The name of the Cloud SQL instance.
|
63
|
+
# @return [String]
|
64
|
+
attr_reader :inst
|
65
|
+
|
66
|
+
##
|
67
|
+
# The Cloud SQL API used to manage Cloud SQL instances.
|
68
|
+
# @return [Google::Apis::SqladminV1beta4::SQLAdminService]
|
69
|
+
attr_reader :service
|
70
|
+
|
71
|
+
##
|
72
|
+
# Creates a CloudSQL object and loads the necessary configuration
|
73
|
+
# settings.
|
74
|
+
#
|
75
|
+
# @param inst [String] Name of the instance to be used. Optional.
|
76
|
+
def initialize inst = nil
|
77
|
+
auth = Google::Auth.get_application_default SCOPES
|
78
|
+
Google::Apis::RequestOptions.default.authorization = auth
|
79
|
+
@config = Configuration.new
|
80
|
+
@service = SQL::SQLAdminService.new
|
81
|
+
@inst = inst || "instance-#{SecureRandom.uuid}".freeze
|
82
|
+
@custom = inst ? true : false
|
83
|
+
load_config
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Prepares a Cloud SQL instance with a database and user. Also saves
|
88
|
+
# the database settings in the appropriate configuration file.
|
89
|
+
def run
|
90
|
+
create_instance do |instance_op|
|
91
|
+
run_sql_task instance_op if instance_op.class == SQL::Operation
|
92
|
+
update_root_user
|
93
|
+
create_db do |db_op|
|
94
|
+
run_sql_task db_op
|
95
|
+
create_user
|
96
|
+
end
|
97
|
+
end
|
98
|
+
update_config
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
##
|
104
|
+
# @private Creates a Cloud SQL instance.
|
105
|
+
def create_instance &block
|
106
|
+
if @custom
|
107
|
+
puts "Using existing Cloud SQL instance: #{@inst}"
|
108
|
+
yield
|
109
|
+
return instance
|
110
|
+
end
|
111
|
+
puts "Creating Cloud SQL instance #{@inst} (this takes a few "\
|
112
|
+
"minutes to complete)"
|
113
|
+
settings = SQL::Settings.new(tier: "db-f1-micro")
|
114
|
+
payload = SQL::DatabaseInstance.new(
|
115
|
+
name: @inst,
|
116
|
+
project: @proj_id,
|
117
|
+
settings: settings
|
118
|
+
)
|
119
|
+
@service.insert_instance(@proj_id, payload, &block)
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# @private Creates a database for a Cloud SQL instance.
|
124
|
+
def create_db &block
|
125
|
+
puts "Creating database #{@db}"
|
126
|
+
db = SQL::Database.new name: @db
|
127
|
+
@service.insert_database(@proj_id, @inst, db, &block)
|
128
|
+
end
|
129
|
+
|
130
|
+
##
|
131
|
+
# @private Creates a user for a Cloud SQL instance.
|
132
|
+
def create_user
|
133
|
+
puts "Creating user #{@user}"
|
134
|
+
user = SQL::User.new(name: @user, password: @pwd)
|
135
|
+
run_sql_task @service.insert_user(@proj_id, @inst, user)
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# @private Updates the password of the root user if a new Cloud SQL
|
140
|
+
# instance was created.
|
141
|
+
def update_root_user
|
142
|
+
return if @custom
|
143
|
+
cmd = "gcloud sql users set-password root % --password #{@pwd} "\
|
144
|
+
"-i #{@inst} --project #{@proj_id}"
|
145
|
+
`#{cmd}`
|
146
|
+
end
|
147
|
+
|
148
|
+
##
|
149
|
+
# @private Fetches a Cloud SQL instance.
|
150
|
+
#
|
151
|
+
# @return [Google::Apis::SqladminV1beta4::DatabaseInstance
|
152
|
+
def instance
|
153
|
+
@service.get_instance @proj_id, @inst
|
154
|
+
end
|
155
|
+
|
156
|
+
##
|
157
|
+
# Deletes the Cloud SQL instance for a gemserver.
|
158
|
+
def del_instance
|
159
|
+
puts "Deleting instance: #{@inst}"
|
160
|
+
@service.delete_instance @proj_id, @inst
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# Sets various Cloud SQL settings used to create a Cloud SQL
|
165
|
+
# instance.
|
166
|
+
def load_config
|
167
|
+
@db = @config[:db_connection_options][:database]
|
168
|
+
@user = @config[:db_connection_options][:username]
|
169
|
+
@pwd = @config[:db_connection_options][:password]
|
170
|
+
@proj_id = @config[:proj_id]
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# Saves the Cloud SQL configuration in the appropriate configuration
|
175
|
+
# file and app configuration file.
|
176
|
+
def update_config
|
177
|
+
puts "Updating configurations: app.yaml and config.yml "
|
178
|
+
conn_name = instance.connection_name
|
179
|
+
@config.update_config "/cloudsql/#{conn_name}",
|
180
|
+
:db_connection_options,
|
181
|
+
:socket
|
182
|
+
@config.update_app conn_name, "beta_settings", "cloud_sql_instances"
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Runs a Cloud SQL task and polls for its completion.
|
187
|
+
def run_sql_task op
|
188
|
+
while @service.get_operation(@proj_id, op.name).status != "DONE"
|
189
|
+
sleep 2
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# Copyright 2017 Google Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "google/cloud/gemserver"
|
16
|
+
require "google/cloud/resource_manager"
|
17
|
+
require "securerandom"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
module Gemserver
|
22
|
+
class CLI
|
23
|
+
##
|
24
|
+
# # Project
|
25
|
+
#
|
26
|
+
# Holds a reference to a project on Google Cloud Platform.
|
27
|
+
#
|
28
|
+
class Project
|
29
|
+
|
30
|
+
##
|
31
|
+
# The name of the project on Google Cloud platform; same as ID.
|
32
|
+
# @return [String]
|
33
|
+
attr_accessor :proj_name
|
34
|
+
|
35
|
+
##
|
36
|
+
# The Configuration object storing the settings used by the Project
|
37
|
+
# object.
|
38
|
+
# @return [Configuration]
|
39
|
+
attr_accessor :config
|
40
|
+
|
41
|
+
##
|
42
|
+
# Initializes the project name and Configuration object.
|
43
|
+
def initialize name = nil
|
44
|
+
@proj_name = name
|
45
|
+
@config = Configuration.new
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Fetches a reference to the given project on Google Cloud Platform
|
50
|
+
# and prompts the user to configure it correctly.
|
51
|
+
def create
|
52
|
+
raise "Project name was not provided!" unless @proj_name
|
53
|
+
begin
|
54
|
+
@config.update_config @proj_name, :proj_id
|
55
|
+
create_gae_project
|
56
|
+
enable_api
|
57
|
+
enable_billing
|
58
|
+
project
|
59
|
+
rescue Google::Cloud::PermissionDeniedError, RuntimeError => e
|
60
|
+
puts "Permission denied. You might not be authorized with " \
|
61
|
+
"gcloud. Read github.com/GoogleCloudPlatform/google-cloud`." \
|
62
|
+
"-ruby/google-cloud-gemserver/docs/authentication.md for " \
|
63
|
+
"more information on how to get authenticated."
|
64
|
+
puts "If you still get this error the Cloud Resource Manager " \
|
65
|
+
"API might not be enabled."
|
66
|
+
abort "More details: #{e.message}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
##
|
73
|
+
# @private Checks if the current Google Cloud Platform project
|
74
|
+
# contains a Google App Engine project. If not, one is created.
|
75
|
+
def create_gae_project
|
76
|
+
return if project_exists?
|
77
|
+
puts "Required Google App Engine project does not exist."
|
78
|
+
system "gcloud app create --project #{@proj_name}"
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# @private Checks if a Google App Engine project exists.
|
83
|
+
#
|
84
|
+
# @return [Boolean]
|
85
|
+
def project_exists?
|
86
|
+
system "gcloud app describe --project #{@proj_name} >/dev/null 2>&1"
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# @private Prompts the user to press enter.
|
91
|
+
#
|
92
|
+
# @return [String]
|
93
|
+
def prompt_user
|
94
|
+
puts "\nPress enter to continue..."
|
95
|
+
STDIN.gets
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# @private Fetches a given project on Google Cloud Platform.
|
100
|
+
#
|
101
|
+
# @return [Google::Cloud::ResourceManager::Project]
|
102
|
+
def project
|
103
|
+
resource_manager = Google::Cloud::ResourceManager.new
|
104
|
+
resource_manager.project @proj_name
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# @private Prompts the user to enable necessary APIs for the
|
109
|
+
# gemserver to work as intended.
|
110
|
+
#
|
111
|
+
# @return [String]
|
112
|
+
def enable_api
|
113
|
+
puts "\nEnable the Google Cloud SQL API if it is not already "\
|
114
|
+
"enabled by visiting:\n https://console.developers.google.com"\
|
115
|
+
"/apis/api/sqladmin.googleapis.com/overview?"\
|
116
|
+
"project=#{@proj_name} and clicking \"Enable\""
|
117
|
+
puts "\nEnable the Google Cloud Resource manager API if it is not"\
|
118
|
+
"already enabled by visiting:\nhttps://console.developers.google"\
|
119
|
+
".com/apis/api/cloudresourcemanager.googleapis.com/overview?"\
|
120
|
+
"project=#{@proj_name} and clicking \"Enable\""
|
121
|
+
puts "\nEnable the Google App Engine Admin API if it is not "\
|
122
|
+
"already enabled by visiting:\nhttps://console.developers.google"\
|
123
|
+
".com/apis/api/appengine.googleapis.com/overview?"\
|
124
|
+
"project=#{@proj_name} and clicking \"Enable\""
|
125
|
+
prompt_user
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# @private Prompts the user to enable billing such that the gemserver
|
130
|
+
# work as intended.
|
131
|
+
#
|
132
|
+
# @return [String]
|
133
|
+
def enable_billing
|
134
|
+
puts "\nEnable billing for the project you just created by "\
|
135
|
+
"visiting: \nconsole.cloud.google.com/billing?project="\
|
136
|
+
"#{@proj_name}\nand setting up a billing account."
|
137
|
+
prompt_user
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# Copyright 2017 Google Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# @https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "google/cloud/gemserver"
|
16
|
+
require "net/http"
|
17
|
+
require "yaml"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
module Gemserver
|
22
|
+
class CLI
|
23
|
+
##
|
24
|
+
#
|
25
|
+
# # Request
|
26
|
+
#
|
27
|
+
# Responsible for sending requests to the gemserver for operations that
|
28
|
+
# involve the database. Gem operations are done with the 'gem' command
|
29
|
+
# and are not in the scope of Request.
|
30
|
+
class Request
|
31
|
+
|
32
|
+
##
|
33
|
+
# The HTTP object used to connect to and send requests to the
|
34
|
+
# gemserver.
|
35
|
+
# @return [Net::HTTP]
|
36
|
+
attr_accessor :http
|
37
|
+
|
38
|
+
##
|
39
|
+
# Initialize the Backend object by constructing an HTTP object for the
|
40
|
+
# gemserver.
|
41
|
+
#
|
42
|
+
# @param [String] url The URL of the gemserver. Optional.
|
43
|
+
#
|
44
|
+
# @param [String] proj_name The name of the Google Cloud Platform the
|
45
|
+
# gemserver was deployed to. Optional.
|
46
|
+
def initialize url = nil, proj_name = nil
|
47
|
+
gemserver_url = url.nil? == true ? remote(proj_name) : url
|
48
|
+
@http = Net::HTTP.new gemserver_url
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Send a request to the gemserver to create a key with certain
|
53
|
+
# permissions.
|
54
|
+
#
|
55
|
+
# @param [String] permissions The permissions the generated key will
|
56
|
+
# have (read, write, or both). Optional.
|
57
|
+
#
|
58
|
+
# @return [Net::HTTPResponse]
|
59
|
+
def create_key permissions = nil
|
60
|
+
send_req Net::HTTP::Post, "/api/v1/key", {permissions: permissions}
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Send a request to the gemserver to delete a key.
|
65
|
+
#
|
66
|
+
# @param [String] key The key to delete.
|
67
|
+
#
|
68
|
+
# @return [Net::HTTPResponse]
|
69
|
+
def delete_key key
|
70
|
+
send_req Net::HTTP::Put, "/api/v1/key", {key: key}
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Send a request to the gemserver to fetch information about stored
|
75
|
+
# private gems and cached gem dependencies.
|
76
|
+
#
|
77
|
+
# @return [Net::HTTPResponse]
|
78
|
+
def stats
|
79
|
+
send_req Net::HTTP::Post, "/api/v1/stats"
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Sends a request to the gemserver to ensure it is accessible.
|
84
|
+
#
|
85
|
+
# @return [Net::HTTPResponse]
|
86
|
+
def health
|
87
|
+
send_req Net::HTTP::Get, "/health"
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
##
|
93
|
+
# @private The URL of the gemserver.
|
94
|
+
#
|
95
|
+
# @param [String] proj_name The Google Cloud Platform project the
|
96
|
+
# gemserver was deployed to.
|
97
|
+
#
|
98
|
+
# @return [String]
|
99
|
+
def remote proj_name
|
100
|
+
descrip = YAML.load(`gcloud app describe --project #{proj_name}`)
|
101
|
+
descrip["defaultHostname"]
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# @private Makes a request to the gemserver and returns the response.
|
106
|
+
#
|
107
|
+
# @param [Net::HTTP] type The type of HTTP request.
|
108
|
+
#
|
109
|
+
# @param [String] endpoint The endpoint the request is made to on the
|
110
|
+
# gemserver.
|
111
|
+
#
|
112
|
+
# @param [Object] params The data passed to the gemserver to be
|
113
|
+
# processed. Optional.
|
114
|
+
#
|
115
|
+
# @return [String]
|
116
|
+
def send_req type, endpoint, params = nil
|
117
|
+
auth = Google::Cloud::Gemserver::Authentication.new
|
118
|
+
t = auth.access_token["access_token"]
|
119
|
+
req = type.new endpoint
|
120
|
+
req["Authorization"] = Signet::OAuth2.generate_bearer_authorization_header t
|
121
|
+
if type != Net::HTTP::Get
|
122
|
+
req.set_form_data(params) if params
|
123
|
+
end
|
124
|
+
@http.request req
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|