Commit 65640529 authored by Tiger's avatar Tiger

Add logic to create a cluster management project

This logic isn't currently used by any process, but
eventually a management project will be created when
a user installs an application to the cluster (if
there is no management project already specified).
This will usually be when installing the first
application to the cluster, but could also be on
subsequent installs if the project is somehow unset
or deleted.

The project is currently created empty, the next
step will be to populate it with a sample cluster
management repository.
parent e0449925
# frozen_string_literal: true
module Clusters
module Management
class CreateProjectService
CreateError = Class.new(StandardError)
attr_reader :cluster, :current_user
def initialize(cluster, current_user:)
@cluster = cluster
@current_user = current_user
end
def execute
return unless management_project_required?
ActiveRecord::Base.transaction do
project = create_management_project!
update_cluster!(project)
end
end
private
def management_project_required?
Feature.enabled?(:auto_create_cluster_management_project) && cluster.management_project.nil?
end
def project_params
{
name: project_name,
description: project_description,
namespace_id: namespace.id,
visibility_level: Gitlab::VisibilityLevel::PRIVATE
}
end
def project_name
"#{cluster.name} Cluster Management"
end
def project_description
"This project is automatically generated and will be used to manage your Kubernetes cluster. [More information](#{docs_path})"
end
def docs_path
Rails.application.routes.url_helpers.help_page_path('user/clusters/management_project')
end
def create_management_project!
::Projects::CreateService.new(current_user, project_params).execute.tap do |project|
errors = project.errors.full_messages
if errors.any?
raise CreateError.new("Failed to create project: #{errors}")
end
end
end
def update_cluster!(project)
unless cluster.update(management_project: project)
raise CreateError.new("Failed to update cluster: #{cluster.errors.full_messages}")
end
end
def namespace
case cluster.cluster_type
when 'project_type'
cluster.project.namespace
when 'group_type'
cluster.group
when 'instance_type'
instance_administrators_group
else
raise NotImplementedError
end
end
def instance_administrators_group
Gitlab::CurrentSettings.instance_administrators_group ||
raise(CreateError.new('Instance administrators group not found'))
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Clusters::Management::CreateProjectService do
let(:cluster) { create(:cluster, :project) }
let(:current_user) { create(:user) }
subject { described_class.new(cluster, current_user: current_user).execute }
shared_examples 'management project is not required' do
it 'does not create a project' do
expect { subject }.not_to change(cluster, :management_project)
end
end
context ':auto_create_cluster_management_project feature flag is disabled' do
before do
stub_feature_flags(auto_create_cluster_management_project: false)
end
include_examples 'management project is not required'
end
context 'cluster already has a management project' do
let(:cluster) { create(:cluster, :management_project) }
include_examples 'management project is not required'
end
shared_examples 'creates a management project' do
let(:project_params) do
{
name: "#{cluster.name} Cluster Management",
description: 'This project is automatically generated and will be used to manage your Kubernetes cluster. [More information](/help/user/clusters/management_project)',
namespace_id: namespace&.id,
visibility_level: Gitlab::VisibilityLevel::PRIVATE
}
end
it 'creates a management project' do
expect(Projects::CreateService).to receive(:new)
.with(current_user, project_params)
.and_call_original
subject
management_project = cluster.management_project
expect(management_project).to be_present
expect(management_project).to be_private
expect(management_project.name).to eq "#{cluster.name} Cluster Management"
expect(management_project.namespace).to eq namespace
end
end
context 'project cluster' do
let(:cluster) { create(:cluster, projects: [project]) }
let(:project) { create(:project, namespace: current_user.namespace) }
let(:namespace) { project.namespace }
include_examples 'creates a management project'
end
context 'group cluster' do
let(:cluster) { create(:cluster, :group, user: current_user) }
let(:namespace) { cluster.group }
before do
namespace.add_user(current_user, Gitlab::Access::MAINTAINER)
end
include_examples 'creates a management project'
end
context 'instance cluster' do
let(:cluster) { create(:cluster, :instance, user: current_user) }
let(:namespace) { create(:group) }
before do
stub_application_setting(instance_administrators_group: namespace)
namespace.add_user(current_user, Gitlab::Access::MAINTAINER)
end
include_examples 'creates a management project'
end
describe 'error handling' do
let(:project) { cluster.project }
before do
allow(Projects::CreateService).to receive(:new)
.and_return(double(execute: project))
end
context 'project is invalid' do
let(:errors) { double(full_messages: ["Error message"]) }
let(:project) { instance_double(Project, errors: errors) }
it { expect { subject }.to raise_error(described_class::CreateError, /Failed to create project/) }
end
context 'instance administrators group is missing' do
let(:cluster) { create(:cluster, :instance) }
it { expect { subject }.to raise_error(described_class::CreateError, /Instance administrators group not found/) }
end
context 'cluster is invalid' do
before do
allow(cluster).to receive(:update).and_return(false)
end
it { expect { subject }.to raise_error(described_class::CreateError, /Failed to update cluster/) }
end
context 'unknown cluster type' do
before do
allow(cluster).to receive(:cluster_type).and_return("unknown_type")
end
it { expect { subject }.to raise_error(NotImplementedError) }
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment