Convert clusters to use a top-level controller
In preparation so that we can create both cluster attached to project and cluster attached to group. - Move ClustersController to top level - Move Clusters::ApplicationsController to top-level too - Creates a Clusters::BaseController to share common functions - Do not rely on @project ivar. Anything could set the ivar. - Fix Vue page components due to new data-page value Because of the controller change we have gone from `projects:clusters:new` to `clusters:new`, so we need to update the file location of the page components. There is somewhere a function that will convert data-page to a file location. On that note, projects/clusters/gcp/new/, translate to Projects::Clusters::Gcp#new doesn't exist so replace that with clusters/create_gcp/ and clusters/create_user/
This commit is contained in:
parent
5a95374182
commit
5b3c096c9e
38 changed files with 136 additions and 62 deletions
|
@ -1,5 +1,7 @@
|
|||
import initDismissableCallout from '~/dismissable_callout';
|
||||
import initGkeDropdowns from '~/projects/gke_cluster_dropdowns';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initDismissableCallout('.gcp-signup-offer');
|
||||
initGkeDropdowns();
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
import initDismissableCallout from '~/dismissable_callout';
|
||||
import initGkeDropdowns from '~/projects/gke_cluster_dropdowns';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initDismissableCallout('.gcp-signup-offer');
|
||||
initGkeDropdowns();
|
||||
});
|
7
app/assets/javascripts/pages/clusters/new/index.js
Normal file
7
app/assets/javascripts/pages/clusters/new/index.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import initDismissableCallout from '~/dismissable_callout';
|
||||
import initGkeDropdowns from '~/projects/gke_cluster_dropdowns';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initDismissableCallout('.gcp-signup-offer');
|
||||
initGkeDropdowns();
|
||||
});
|
|
@ -1,21 +1,7 @@
|
|||
import initDismissableCallout from '~/dismissable_callout';
|
||||
import initGkeDropdowns from '~/projects/gke_cluster_dropdowns';
|
||||
import Project from './project';
|
||||
import ShortcutsNavigation from '../../behaviors/shortcuts/shortcuts_navigation';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const { page } = document.body.dataset;
|
||||
const newClusterViews = [
|
||||
'projects:clusters:new',
|
||||
'projects:clusters:create_gcp',
|
||||
'projects:clusters:create_user',
|
||||
];
|
||||
|
||||
if (newClusterViews.indexOf(page) > -1) {
|
||||
initDismissableCallout('.gcp-signup-offer');
|
||||
initGkeDropdowns();
|
||||
}
|
||||
|
||||
new Project(); // eslint-disable-line no-new
|
||||
new ShortcutsNavigation(); // eslint-disable-line no-new
|
||||
});
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Projects::Clusters::ApplicationsController < Projects::ApplicationController
|
||||
class Clusters::ApplicationsController < Clusters::BaseController
|
||||
before_action :cluster
|
||||
before_action :authorize_read_cluster!
|
||||
before_action :authorize_create_cluster!, only: [:create]
|
||||
|
||||
def create
|
42
app/controllers/clusters/base_controller.rb
Normal file
42
app/controllers/clusters/base_controller.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Clusters::BaseController < ApplicationController
|
||||
include RoutableActions
|
||||
|
||||
skip_before_action :authenticate_user!
|
||||
before_action :require_project_id
|
||||
before_action :project, if: :project_type?
|
||||
before_action :repository, if: :project_type?
|
||||
before_action :authorize_read_cluster!
|
||||
|
||||
private
|
||||
|
||||
# We can extend to `#group_type?` in the future
|
||||
def require_project_id
|
||||
not_found unless project_type?
|
||||
end
|
||||
|
||||
def project
|
||||
@project ||= find_routable!(Project, File.join(params[:namespace_id], params[:project_id]))
|
||||
end
|
||||
|
||||
def repository
|
||||
@repository ||= project.repository
|
||||
end
|
||||
|
||||
def authorize_read_cluster!
|
||||
access_denied! unless can?(current_user, :read_cluster, clusterable)
|
||||
end
|
||||
|
||||
def authorize_create_cluster!
|
||||
access_denied! unless can?(current_user, :create_cluster, clusterable)
|
||||
end
|
||||
|
||||
def clusterable
|
||||
project if project_type?
|
||||
end
|
||||
|
||||
def project_type?
|
||||
params[:project_id].present?
|
||||
end
|
||||
end
|
|
@ -1,8 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Projects::ClustersController < Projects::ApplicationController
|
||||
class ClustersController < Clusters::BaseController
|
||||
before_action :cluster, except: [:index, :new, :create_gcp, :create_user]
|
||||
before_action :authorize_read_cluster!
|
||||
before_action :generate_gcp_authorize_url, only: [:new]
|
||||
before_action :validate_gcp_token, only: [:new]
|
||||
before_action :gcp_cluster, only: [:new]
|
||||
|
@ -11,6 +10,9 @@ class Projects::ClustersController < Projects::ApplicationController
|
|||
before_action :authorize_update_cluster!, only: [:update]
|
||||
before_action :authorize_admin_cluster!, only: [:destroy]
|
||||
before_action :update_applications_status, only: [:status]
|
||||
|
||||
layout :determine_layout
|
||||
|
||||
helper_method :token_in_session
|
||||
|
||||
STATUS_POLLING_INTERVAL = 10_000
|
||||
|
@ -29,7 +31,7 @@ class Projects::ClustersController < Projects::ApplicationController
|
|||
Gitlab::PollingInterval.set_header(response, interval: STATUS_POLLING_INTERVAL)
|
||||
|
||||
render json: ClusterSerializer
|
||||
.new(project: @project, current_user: @current_user)
|
||||
.new(project: project, current_user: @current_user)
|
||||
.represent_status(@cluster)
|
||||
end
|
||||
end
|
||||
|
@ -105,6 +107,12 @@ class Projects::ClustersController < Projects::ApplicationController
|
|||
|
||||
private
|
||||
|
||||
def determine_layout
|
||||
if project_type?
|
||||
'project'
|
||||
end
|
||||
end
|
||||
|
||||
def cluster
|
||||
@cluster ||= project.clusters.find(params[:id])
|
||||
.present(current_user: current_user)
|
||||
|
@ -169,7 +177,7 @@ class Projects::ClustersController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def generate_gcp_authorize_url
|
||||
state = generate_session_key_redirect(new_project_cluster_path(@project).to_s)
|
||||
state = generate_session_key_redirect(new_project_cluster_path(project).to_s)
|
||||
|
||||
@authorize_url = GoogleApi::CloudPlatform::Client.new(
|
||||
nil, callback_google_api_auth_url,
|
|
@ -10,7 +10,7 @@ module ClustersHelper
|
|||
return unless show_gcp_signup_offer?
|
||||
|
||||
content_tag :section, class: 'no-animate expanded' do
|
||||
render 'projects/clusters/gcp_signup_offer_banner'
|
||||
render 'clusters/gcp_signup_offer_banner'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
.tab-content.gitlab-tab-content
|
||||
.tab-pane{ id: 'create-gcp-cluster-pane', class: active_when(active_tab == 'gcp'), role: 'tabpanel' }
|
||||
= render 'projects/clusters/gcp/header'
|
||||
= render 'clusters/gcp/header'
|
||||
- if @valid_gcp_token
|
||||
= render 'projects/clusters/gcp/form'
|
||||
= render 'clusters/gcp/form'
|
||||
- elsif @authorize_url
|
||||
.signin-with-google
|
||||
= link_to(image_tag('auth_buttons/signin_with_google.png', width: '191px'), @authorize_url)
|
||||
|
@ -32,5 +32,5 @@
|
|||
= s_('Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service.').html_safe % { link_to_documentation: link }
|
||||
|
||||
.tab-pane{ id: 'add-user-cluster-pane', class: active_when(active_tab == 'user'), role: 'tabpanel' }
|
||||
= render 'projects/clusters/user/header'
|
||||
= render 'projects/clusters/user/form'
|
||||
= render 'clusters/user/header'
|
||||
= render 'clusters/user/form'
|
|
@ -38,9 +38,9 @@
|
|||
%p= s_('ClusterIntegration|See and edit the details for your Kubernetes cluster')
|
||||
.settings-content
|
||||
- if @cluster.managed?
|
||||
= render 'projects/clusters/gcp/show'
|
||||
= render 'clusters/gcp/show'
|
||||
- else
|
||||
= render 'projects/clusters/user/show'
|
||||
= render 'clusters/user/show'
|
||||
|
||||
%section.settings.no-animate#js-cluster-advanced-settings{ class: ('expanded' if expanded) }
|
||||
.settings-header
|
6
changelogs/unreleased/top_level_clusters_controller.yml
Normal file
6
changelogs/unreleased/top_level_clusters_controller.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Change to top level controller for clusters so that we can use it for project
|
||||
clusters (now) and group clusters (later)
|
||||
merge_request: 22438
|
||||
author:
|
||||
type: other
|
|
@ -84,6 +84,23 @@ Rails.application.routes.draw do
|
|||
draw :instance_statistics
|
||||
end
|
||||
|
||||
concern :clusterable do
|
||||
resources :clusters, except: [:edit, :create], controller: '/clusters' do
|
||||
collection do
|
||||
post :create_gcp
|
||||
post :create_user
|
||||
end
|
||||
|
||||
member do
|
||||
get :status, format: :json
|
||||
|
||||
scope :applications do
|
||||
post '/:application', to: '/clusters/applications#create', as: :install_applications
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
draw :api
|
||||
draw :sidekiq
|
||||
draw :help
|
||||
|
|
|
@ -206,20 +206,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
|
|||
end
|
||||
end
|
||||
|
||||
resources :clusters, except: [:edit, :create] do
|
||||
collection do
|
||||
post :create_gcp
|
||||
post :create_user
|
||||
end
|
||||
|
||||
member do
|
||||
get :status, format: :json
|
||||
|
||||
scope :applications do
|
||||
post '/:application', to: 'clusters/applications#create', as: :install_applications
|
||||
end
|
||||
end
|
||||
end
|
||||
concerns :clusterable
|
||||
|
||||
resources :environments, except: [:destroy] do
|
||||
member do
|
||||
|
|
|
@ -4,7 +4,7 @@ module QA
|
|||
module Operations
|
||||
module Kubernetes
|
||||
class Add < Page::Base
|
||||
view 'app/views/projects/clusters/new.html.haml' do
|
||||
view 'app/views/clusters/new.html.haml' do
|
||||
element :add_existing_cluster_button, "Add existing cluster" # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ module QA
|
|||
module Operations
|
||||
module Kubernetes
|
||||
class AddExisting < Page::Base
|
||||
view 'app/views/projects/clusters/user/_form.html.haml' do
|
||||
view 'app/views/clusters/user/_form.html.haml' do
|
||||
element :cluster_name, 'text_field :name' # rubocop:disable QA/ElementWithPattern
|
||||
element :api_url, 'text_field :api_url' # rubocop:disable QA/ElementWithPattern
|
||||
element :ca_certificate, 'text_area :ca_cert' # rubocop:disable QA/ElementWithPattern
|
||||
|
|
|
@ -4,7 +4,7 @@ module QA
|
|||
module Operations
|
||||
module Kubernetes
|
||||
class Index < Page::Base
|
||||
view 'app/views/projects/clusters/_empty_state.html.haml' do
|
||||
view 'app/views/clusters/_empty_state.html.haml' do
|
||||
element :add_kubernetes_cluster_button, "link_to s_('ClusterIntegration|Add Kubernetes cluster')" # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Projects::Clusters::ApplicationsController do
|
||||
describe Clusters::ApplicationsController do
|
||||
include AccessMatchersForController
|
||||
|
||||
def current_application
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Projects::ClustersController do
|
||||
describe ClustersController do
|
||||
include AccessMatchersForController
|
||||
include GoogleApi::CloudPlatformHelpers
|
||||
|
||||
|
@ -218,9 +220,9 @@ describe Projects::ClustersController do
|
|||
describe 'security' do
|
||||
before do
|
||||
allow_any_instance_of(described_class)
|
||||
.to receive(:token_in_session).and_return('token')
|
||||
.to receive(:token_in_session).and_return('token')
|
||||
allow_any_instance_of(described_class)
|
||||
.to receive(:expires_at_in_session).and_return(1.hour.since.to_i.to_s)
|
||||
.to receive(:expires_at_in_session).and_return(1.hour.since.to_i.to_s)
|
||||
allow_any_instance_of(GoogleApi::CloudPlatform::Client)
|
||||
.to receive(:projects_zones_clusters_create) do
|
||||
OpenStruct.new(
|
||||
|
@ -322,10 +324,11 @@ describe Projects::ClustersController do
|
|||
let(:cluster) { create(:cluster, :providing_by_gcp, projects: [project]) }
|
||||
|
||||
def go
|
||||
get :status, namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
id: cluster,
|
||||
format: :json
|
||||
get :status,
|
||||
namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
id: cluster,
|
||||
format: :json
|
||||
end
|
||||
|
||||
describe 'functionality' do
|
||||
|
@ -359,9 +362,10 @@ describe Projects::ClustersController do
|
|||
let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
|
||||
|
||||
def go
|
||||
get :show, namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
id: cluster
|
||||
get :show,
|
||||
namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
id: cluster
|
||||
end
|
||||
|
||||
describe 'functionality' do
|
||||
|
@ -530,9 +534,10 @@ describe Projects::ClustersController do
|
|||
let!(:cluster) { create(:cluster, :provided_by_gcp, :production_environment, projects: [project]) }
|
||||
|
||||
def go
|
||||
delete :destroy, namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
id: cluster
|
||||
delete :destroy,
|
||||
namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
id: cluster
|
||||
end
|
||||
|
||||
describe 'functionality' do
|
||||
|
@ -591,4 +596,10 @@ describe Projects::ClustersController do
|
|||
it { expect { go }.to be_denied_for(:external) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'no project_id param' do
|
||||
it 'does not respond to any action without project_id param' do
|
||||
expect { get :index }.to raise_error(ActionController::UrlGenerationError)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -9,16 +9,16 @@ describe 'Gcp Cluster', :js do
|
|||
before do
|
||||
project.add_maintainer(user)
|
||||
gitlab_sign_in(user)
|
||||
allow(Projects::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 }
|
||||
allow(ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 }
|
||||
end
|
||||
|
||||
context 'when user has signed with Google' do
|
||||
let(:project_id) { 'test-project-1234' }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Projects::ClustersController)
|
||||
allow_any_instance_of(ClustersController)
|
||||
.to receive(:token_in_session).and_return('token')
|
||||
allow_any_instance_of(Projects::ClustersController)
|
||||
allow_any_instance_of(ClustersController)
|
||||
.to receive(:expires_at_in_session).and_return(1.hour.since.to_i.to_s)
|
||||
end
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ describe 'User Cluster', :js do
|
|||
before do
|
||||
project.add_maintainer(user)
|
||||
gitlab_sign_in(user)
|
||||
allow(Projects::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 }
|
||||
allow(ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 }
|
||||
end
|
||||
|
||||
context 'when user does not have a cluster and visits cluster index page' do
|
||||
|
|
Loading…
Reference in a new issue