summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/google_api/authorizations_controller.rb27
-rw-r--r--app/controllers/projects/clusters_controller.rb102
-rw-r--r--app/models/ci/cluster.rb14
-rw-r--r--app/models/project.rb1
-rw-r--r--app/views/projects/clusters/edit.html.haml2
-rw-r--r--app/views/projects/clusters/new.html.haml17
-rw-r--r--config/routes.rb1
-rw-r--r--config/routes/google_api.rb5
-rw-r--r--config/routes/project.rb7
-rw-r--r--db/migrate/20170924094327_create_ci_clusters.rb29
-rw-r--r--db/schema.rb68
-rw-r--r--lib/google_api/authentication.rb51
-rw-r--r--lib/google_api/cloud_platform/client.rb24
13 files changed, 323 insertions, 25 deletions
diff --git a/app/controllers/google_api/authorizations_controller.rb b/app/controllers/google_api/authorizations_controller.rb
new file mode 100644
index 00000000000..e99c38025b8
--- /dev/null
+++ b/app/controllers/google_api/authorizations_controller.rb
@@ -0,0 +1,27 @@
+module GoogleApi
+ class AuthorizationsController < ApplicationController
+ # callback_google_api_authorizations GET|POST /google_api/authorizations/callback(.:format) google_api/authorizations#callback
+ ##
+ # TODO:
+ # - Is it ok to use both "http://localhost:3000/google_api/authorizations/callback"(For login) and "http://localhost:3000/google_api/authorizations/callback"(For API token)
+ def callback
+ session[access_token_key] = api_client.get_token(params[:code])
+
+ if params[:state]
+ redirect_to params[:state]
+ else
+ redirect_to root_url
+ end
+ end
+
+ def api_client
+ @api_client ||=
+ GoogleApi::Authentication.new(nil, callback_google_api_authorizations_url)
+ end
+
+ def access_token_key
+ # :"#{api_client.scope}_access_token"
+ :"hoge_access_token" # TODO:
+ end
+ end
+end
diff --git a/app/controllers/projects/clusters_controller.rb b/app/controllers/projects/clusters_controller.rb
new file mode 100644
index 00000000000..5c9319f661a
--- /dev/null
+++ b/app/controllers/projects/clusters_controller.rb
@@ -0,0 +1,102 @@
+class Projects::ClustersController < Projects::ApplicationController
+ # before_action :authenticate_google_api
+ before_action :cluster
+
+ # before_action :authorize_admin_clusters! # TODO: Authentication
+
+ def index
+ if cluster
+ redirect_to action: 'edit'
+ else
+ redirect_to action: 'new'
+ end
+ end
+
+ ##
+ # TODO:
+ # - Show form for "Create on Google Container Engine"
+ # - Show form for "Use existing kubernets cluster"
+ # - If user has not authroized yet, Show "Sign in with Google" button
+ # - If user has already authroized, Skip "Sign in with Google" button
+ # - user.is_authenticated_for_gcp?
+ # - user.authenticate_for_gcp!
+ # - Create this module which can be used from view
+ def new
+ unless session[access_token_key]
+ @authorize_url = api_client.authorize_url
+ end
+ end
+
+ ##
+ # TODO:
+ # - If create on GKE, Use Google::Apis::ContainerV1::ContainerService
+ # - If create manually, save in db (Prob, Project > Setting)
+ # - Dry up with Service
+ def create
+ redirect_to action: 'index'
+ end
+
+ # TODO: Show results/status. Edits Swtich for enable/disable.
+ # If created with GKE, non-editable form. enable/disable switch.
+ # If created manually, editable form. enable/disable switch.
+ # GKE params are on-off swtich
+ # Manul params are on-off swtich, Endpoint, CACert, k8s Token, Proj namespace.
+ def edit
+ unless session[access_token_key]
+ @authorize_url = api_client.authorize_url
+ end
+ end
+
+ def update
+ cluster.update(schedule_params)
+ render :edit
+ end
+
+ # In presenter
+ # TODO: Generate a link to the cluster on GKE
+
+ def gcp_projects
+ # api_client.blah
+ # TODO: Return all avaiable GCP Projects.
+ # TODO: Return json
+ # TODO: Dry with concern
+ end
+
+ def gke_zones
+ # api_client.blah
+ # TODO: Return all avaiable zones on GKE.
+ # TODO: Return json
+ # TODO: Dry with concern
+ end
+
+ private
+
+ # def authenticate_google_api
+ # if cluster&.on_gke? && session[access_token_key].blank?
+ # redirect_to api_client.authorize_url(callback_import_url)
+ # end
+ # end
+
+ def cluster
+ # Each project has only one cluster, for now. In the future iteraiton, we'll support multiple clusters
+ @cluster ||= project.clusters.first
+ end
+
+ def cluster_params
+ params.require(:cluster).permit(:aaa)
+ end
+
+ def api_client
+ @api_client ||=
+ GoogleApi::CloudPlatform::Client.new(
+ session[access_token_key],
+ callback_google_api_authorizations_url,
+ state: namespace_project_clusters_url.to_s
+ )
+ end
+
+ def access_token_key
+ # :"#{api_client.scope}_access_token"
+ :"hoge_access_token" # TODO:
+ end
+end
diff --git a/app/models/ci/cluster.rb b/app/models/ci/cluster.rb
new file mode 100644
index 00000000000..2e614a1a373
--- /dev/null
+++ b/app/models/ci/cluster.rb
@@ -0,0 +1,14 @@
+module Ci
+ class Cluster < ActiveRecord::Base
+ extend Gitlab::Ci::Model
+
+ belongs_to :project
+ belongs_to :owner, class_name: 'User'
+
+ enum creation_type: {
+ unknown: nil,
+ on_gke: 1,
+ manual: 2
+ }
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index f7221e4f3b2..6b896746864 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -171,6 +171,7 @@ class Project < ActiveRecord::Base
has_many :commit_statuses
has_many :pipelines, class_name: 'Ci::Pipeline'
+ has_many :clusters, class_name: 'Ci::Cluster'
# Ci::Build objects store data on the file system such as artifact files and
# build traces. Currently there's no efficient way of removing this data in
diff --git a/app/views/projects/clusters/edit.html.haml b/app/views/projects/clusters/edit.html.haml
new file mode 100644
index 00000000000..6445b3ee75d
--- /dev/null
+++ b/app/views/projects/clusters/edit.html.haml
@@ -0,0 +1,2 @@
+edit/show cluster
+= @cluster.inspect
diff --git a/app/views/projects/clusters/new.html.haml b/app/views/projects/clusters/new.html.haml
new file mode 100644
index 00000000000..5e291d07835
--- /dev/null
+++ b/app/views/projects/clusters/new.html.haml
@@ -0,0 +1,17 @@
+Create a new cluster
+
+%br
+
+- if @authorize_url
+ I have not authenticated yet. I can authenticate from
+ = link_to("authenticate from here", @authorize_url)
+- else
+ I have already authenticated.
+ %br
+ Avaiable GCP project lists
+ %br
+ Avaiable zones
+ %br
+ = link_to "Create on Google Container Engine", namespace_project_clusters_path(@project.namespace, @project, param1: 'value1', param2: 'value2'), method: :post
+ = link_to "Use existing kubernets cluster", namespace_project_clusters_path(@project.namespace, @project, param1: 'value1', param2: 'value2'), method: :post
+
diff --git a/config/routes.rb b/config/routes.rb
index 5683725c8a2..405bfcc2d8e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -87,6 +87,7 @@ Rails.application.routes.draw do
resources :issues, module: :boards, only: [:index, :update]
end
+ draw :google_api
draw :import
draw :uploads
draw :explore
diff --git a/config/routes/google_api.rb b/config/routes/google_api.rb
new file mode 100644
index 00000000000..57e15d0d39c
--- /dev/null
+++ b/config/routes/google_api.rb
@@ -0,0 +1,5 @@
+namespace :google_api do
+ resource :authorizations, only: [], controller: :authorizations do
+ match :callback, via: [:get, :post]
+ end
+end
diff --git a/config/routes/project.rb b/config/routes/project.rb
index b36d13888cd..5a43e2274a6 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -183,6 +183,13 @@ constraints(ProjectUrlConstrainer.new) do
end
end
+ resources :clusters, except: [:show, :destroy] do
+ collection do
+ get :gcp_projects # TODO: This doesn't belong here. Grape or under user. Hint. Serilizer
+ get :gke_zones
+ end
+ end
+
resources :environments, except: [:destroy] do
member do
post :stop
diff --git a/db/migrate/20170924094327_create_ci_clusters.rb b/db/migrate/20170924094327_create_ci_clusters.rb
new file mode 100644
index 00000000000..86e75edf203
--- /dev/null
+++ b/db/migrate/20170924094327_create_ci_clusters.rb
@@ -0,0 +1,29 @@
+class CreateCiClusters < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ create_table :ci_clusters do |t|
+ t.integer :project_id
+ t.integer :owner_id
+ t.datetime_with_timezone :created_at, null: false
+ t.datetime_with_timezone :updated_at, null: false
+ t.boolean :enabled, default: true
+ t.string :end_point
+ t.text :ca_cert # Base64?
+ t.string :token
+ t.string :username
+ t.string :password
+ t.string :project_namespace
+ t.integer :creation_type # manual or on_gke
+ end
+
+ # TODO: fk, index, encypt
+
+ add_foreign_key :ci_clusters, :projects
+ add_foreign_key :ci_clusters, :users, column: :owner_id
+ end
+
+ def down
+ drop_table :ci_clusters
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 80ef91ec95d..5258adcbcb7 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170921115009) do
+ActiveRecord::Schema.define(version: 20170924094327) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -32,8 +32,8 @@ ActiveRecord::Schema.define(version: 20170921115009) do
t.text "description", null: false
t.string "header_logo"
t.string "logo"
- t.datetime_with_timezone "created_at", null: false
- t.datetime_with_timezone "updated_at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.text "description_html"
t.integer "cached_markdown_version"
end
@@ -101,10 +101,6 @@ ActiveRecord::Schema.define(version: 20170921115009) do
t.text "help_page_text_html"
t.text "shared_runners_text_html"
t.text "after_sign_up_text_html"
- t.integer "rsa_key_restriction", default: 0, null: false
- t.integer "dsa_key_restriction", default: 0, null: false
- t.integer "ecdsa_key_restriction", default: 0, null: false
- t.integer "ed25519_key_restriction", default: 0, null: false
t.boolean "housekeeping_enabled", default: true, null: false
t.boolean "housekeeping_bitmaps_enabled", default: true, null: false
t.integer "housekeeping_incremental_repack_period", default: 10, null: false
@@ -132,6 +128,10 @@ ActiveRecord::Schema.define(version: 20170921115009) do
t.boolean "password_authentication_enabled"
t.integer "performance_bar_allowed_group_id"
t.boolean "hashed_storage_enabled", default: false, null: false
+ t.integer "rsa_key_restriction", default: 0, null: false
+ t.integer "dsa_key_restriction", default: 0, null: false
+ t.integer "ecdsa_key_restriction", default: 0, null: false
+ t.integer "ed25519_key_restriction", default: 0, null: false
t.boolean "project_export_enabled", default: true, null: false
t.boolean "auto_devops_enabled", default: false, null: false
end
@@ -256,7 +256,6 @@ ActiveRecord::Schema.define(version: 20170921115009) do
add_index "ci_builds", ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree
add_index "ci_builds", ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree
add_index "ci_builds", ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree
- add_index "ci_builds", ["id"], name: "index_for_ci_builds_retried_migration", where: "(retried IS NULL)", using: :btree
add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree
add_index "ci_builds", ["protected"], name: "index_ci_builds_on_protected", using: :btree
add_index "ci_builds", ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree
@@ -267,6 +266,21 @@ ActiveRecord::Schema.define(version: 20170921115009) do
add_index "ci_builds", ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree
add_index "ci_builds", ["user_id"], name: "index_ci_builds_on_user_id", using: :btree
+ create_table "ci_clusters", force: :cascade do |t|
+ t.integer "project_id"
+ t.integer "owner_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.boolean "enabled", default: true
+ t.string "end_point"
+ t.text "ca_cert"
+ t.string "token"
+ t.string "username"
+ t.string "password"
+ t.string "project_namespace"
+ t.integer "creation_type"
+ end
+
create_table "ci_group_variables", force: :cascade do |t|
t.string "key", null: false
t.text "value"
@@ -275,8 +289,8 @@ ActiveRecord::Schema.define(version: 20170921115009) do
t.string "encrypted_value_iv"
t.integer "group_id", null: false
t.boolean "protected", default: false, null: false
- t.datetime_with_timezone "created_at", null: false
- t.datetime_with_timezone "updated_at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
end
add_index "ci_group_variables", ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree
@@ -288,8 +302,8 @@ ActiveRecord::Schema.define(version: 20170921115009) do
t.string "encrypted_value_salt"
t.string "encrypted_value_iv"
t.integer "pipeline_schedule_id", null: false
- t.datetime_with_timezone "created_at"
- t.datetime_with_timezone "updated_at"
+ t.datetime "created_at"
+ t.datetime "updated_at"
end
add_index "ci_pipeline_schedule_variables", ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree
@@ -341,12 +355,14 @@ ActiveRecord::Schema.define(version: 20170921115009) do
t.integer "auto_canceled_by_id"
t.integer "pipeline_schedule_id"
t.integer "source"
- t.integer "config_source"
t.boolean "protected"
+ t.integer "iid"
+ t.integer "config_source"
end
add_index "ci_pipelines", ["auto_canceled_by_id"], name: "index_ci_pipelines_on_auto_canceled_by_id", using: :btree
add_index "ci_pipelines", ["pipeline_schedule_id"], name: "index_ci_pipelines_on_pipeline_schedule_id", using: :btree
+ add_index "ci_pipelines", ["project_id", "iid"], name: "index_ci_pipelines_on_project_id_and_iid", unique: true, using: :btree
add_index "ci_pipelines", ["project_id", "ref", "status"], name: "index_ci_pipelines_on_project_id_and_ref_and_status", using: :btree
add_index "ci_pipelines", ["project_id", "sha"], name: "index_ci_pipelines_on_project_id_and_sha", using: :btree
add_index "ci_pipelines", ["project_id"], name: "index_ci_pipelines_on_project_id", using: :btree
@@ -538,8 +554,8 @@ ActiveRecord::Schema.define(version: 20170921115009) do
t.integer "project_id"
t.integer "author_id", null: false
t.integer "target_id"
- t.datetime_with_timezone "created_at", null: false
- t.datetime_with_timezone "updated_at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "action", limit: 2, null: false
t.string "target_type"
end
@@ -577,8 +593,8 @@ ActiveRecord::Schema.define(version: 20170921115009) do
add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree
create_table "gpg_keys", force: :cascade do |t|
- t.datetime_with_timezone "created_at", null: false
- t.datetime_with_timezone "updated_at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "user_id"
t.binary "primary_keyid"
t.binary "fingerprint"
@@ -590,8 +606,8 @@ ActiveRecord::Schema.define(version: 20170921115009) do
add_index "gpg_keys", ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree
create_table "gpg_signatures", force: :cascade do |t|
- t.datetime_with_timezone "created_at", null: false
- t.datetime_with_timezone "updated_at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "project_id"
t.integer "gpg_key_id"
t.binary "commit_sha"
@@ -789,8 +805,8 @@ ActiveRecord::Schema.define(version: 20170921115009) do
add_index "members", ["user_id"], name: "index_members_on_user_id", using: :btree
create_table "merge_request_diff_commits", id: false, force: :cascade do |t|
- t.datetime_with_timezone "authored_date"
- t.datetime_with_timezone "committed_date"
+ t.datetime "authored_date"
+ t.datetime "committed_date"
t.integer "merge_request_diff_id", null: false
t.integer "relative_order", null: false
t.binary "sha", null: false
@@ -1113,8 +1129,8 @@ ActiveRecord::Schema.define(version: 20170921115009) do
create_table "project_auto_devops", force: :cascade do |t|
t.integer "project_id", null: false
- t.datetime_with_timezone "created_at", null: false
- t.datetime_with_timezone "updated_at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.boolean "enabled"
t.string "domain"
end
@@ -1204,7 +1220,6 @@ ActiveRecord::Schema.define(version: 20170921115009) do
t.string "repository_storage", default: "default", null: false
t.boolean "request_access_enabled", default: false, null: false
t.boolean "has_external_wiki"
- t.string "ci_config_path"
t.boolean "lfs_enabled"
t.text "description_html"
t.boolean "only_allow_merge_if_all_discussions_are_resolved"
@@ -1212,8 +1227,9 @@ ActiveRecord::Schema.define(version: 20170921115009) do
t.integer "auto_cancel_pending_pipelines", default: 1, null: false
t.string "import_jid"
t.integer "cached_markdown_version"
- t.text "delete_error"
t.datetime "last_repository_updated_at"
+ t.string "ci_config_path"
+ t.text "delete_error"
t.integer "storage_version", limit: 2
t.boolean "resolve_outdated_diff_discussions"
end
@@ -1685,6 +1701,8 @@ ActiveRecord::Schema.define(version: 20170921115009) do
add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify
add_foreign_key "ci_builds", "ci_stages", column: "stage_id", name: "fk_3a9eaa254d", on_delete: :cascade
add_foreign_key "ci_builds", "projects", name: "fk_befce0568a", on_delete: :cascade
+ add_foreign_key "ci_clusters", "projects"
+ add_foreign_key "ci_clusters", "users", column: "owner_id"
add_foreign_key "ci_group_variables", "namespaces", column: "group_id", name: "fk_33ae4d58d8", on_delete: :cascade
add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade
add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade
diff --git a/lib/google_api/authentication.rb b/lib/google_api/authentication.rb
new file mode 100644
index 00000000000..d7b473525fb
--- /dev/null
+++ b/lib/google_api/authentication.rb
@@ -0,0 +1,51 @@
+module GoogleApi
+ class Authentication
+ attr_reader :access_token, :redirect_uri, :state
+
+ def initialize(access_token, redirect_uri, state: nil)
+ @access_token = access_token
+ @redirect_uri = redirect_uri
+ @state = state
+ end
+
+ def client
+ return @client if defined?(@client)
+
+ unless config
+ raise 'OAuth configuration for google_oauth2 missing.'
+ end
+
+ @client = ::OAuth2::Client.new(
+ config.app_id,
+ config.app_secret,
+ site: 'https://accounts.google.com',
+ token_url: '/o/oauth2/token',
+ authorize_url: '/o/oauth2/auth'
+ )
+ end
+
+ def authorize_url
+ client.auth_code.authorize_url(
+ redirect_uri: redirect_uri,
+ scope: scope,
+ state: state # This is used for arbitary redirection
+ )
+ end
+
+ def get_token(code)
+ client.auth_code.get_token(code, redirect_uri: redirect_uri).token
+ end
+
+ protected
+
+ def scope
+ raise NotImplementedError
+ end
+
+ private
+
+ def config
+ Gitlab.config.omniauth.providers.find { |provider| provider.name == "google_oauth2" }
+ end
+ end
+end
diff --git a/lib/google_api/cloud_platform/client.rb b/lib/google_api/cloud_platform/client.rb
new file mode 100644
index 00000000000..2c2aefc542c
--- /dev/null
+++ b/lib/google_api/cloud_platform/client.rb
@@ -0,0 +1,24 @@
+module GoogleApi
+ module CloudPlatform
+ class Client < GoogleApi::Authentication
+ # Google::Apis::ContainerV1::ContainerService.new
+ def scope
+ 'https://www.googleapis.com/auth/cloud-platform'
+ end
+
+ def projects_zones_clusters_get
+ # TODO:
+ # service = Google::Apis::ContainerV1::ContainerService.new
+ # service.authorization = access_token
+ # project_id = params['project_id']
+ # ...
+ # response = service.list_zone_clusters(project_id, zone)
+ response
+ end
+
+ def projects_zones_clusters_create
+ # TODO
+ end
+ end
+ end
+end