Commit abb530a6 authored by Thong Kuah's avatar Thong Kuah 🌏 Committed by Stan Hu

DELETE clusters/:id/:application endpoint

Add endpoint to delete/uninstall a cluster application
parent 43c284b7
......@@ -4,6 +4,7 @@ class Clusters::ApplicationsController < Clusters::BaseController
before_action :cluster
before_action :authorize_create_cluster!, only: [:create]
before_action :authorize_update_cluster!, only: [:update]
before_action :authorize_admin_cluster!, only: [:destroy]
def create
request_handler do
......@@ -21,6 +22,14 @@ class Clusters::ApplicationsController < Clusters::BaseController
end
end
def destroy
request_handler do
Clusters::Applications::DestroyService
.new(@cluster, current_user, cluster_application_destroy_params)
.execute(request)
end
end
private
def request_handler
......@@ -40,4 +49,8 @@ class Clusters::ApplicationsController < Clusters::BaseController
def cluster_application_params
params.permit(:application, :hostname, :email)
end
def cluster_application_destroy_params
params.permit(:application)
end
end
# frozen_string_literal: true
module Clusters
module Applications
class DestroyService < ::Clusters::Applications::BaseService
def execute(_request)
instantiate_application.tap do |application|
break unless application.can_uninstall?
application.make_scheduled!
Clusters::Applications::UninstallWorker.perform_async(application.name, application.id)
end
end
private
def builder
cluster.method("application_#{application_name}").call
end
end
end
end
......@@ -33,6 +33,7 @@
- gcp_cluster:cluster_configure
- gcp_cluster:cluster_project_configure
- gcp_cluster:clusters_applications_wait_for_uninstall_app
- gcp_cluster:clusters_applications_uninstall
- github_import_advance_stage
- github_importer:github_import_import_diff_note
......
# frozen_string_literal: true
module Clusters
module Applications
class UninstallWorker
include ApplicationWorker
include ClusterQueue
include ClusterApplications
def perform(app_name, app_id)
find_application(app_name, app_id) do |app|
Clusters::Applications::UninstallService.new(app).execute
end
end
end
end
end
......@@ -103,6 +103,7 @@ Rails.application.routes.draw do
scope :applications do
post '/:application', to: 'clusters/applications#create', as: :install_applications
patch '/:application', to: 'clusters/applications#update', as: :update_applications
delete '/:application', to: 'clusters/applications#destroy', as: :uninstall_applications
end
get :cluster_status, format: :json
......
......@@ -144,4 +144,64 @@ describe Groups::Clusters::ApplicationsController do
it_behaves_like 'a secure endpoint'
end
end
describe 'DELETE destroy' do
subject do
delete :destroy, params: params.merge(group_id: group)
end
let!(:application) { create(:clusters_applications_cert_managers, :installed, cluster: cluster) }
let(:application_name) { application.name }
let(:params) { { application: application_name, id: cluster.id } }
let(:worker_class) { Clusters::Applications::UninstallWorker }
describe 'functionality' do
let(:user) { create(:user) }
before do
group.add_maintainer(user)
sign_in(user)
end
context "when cluster and app exists" do
xit "schedules an application update" do
expect(worker_class).to receive(:perform_async).with(application.name, application.id).once
is_expected.to have_http_status(:no_content)
expect(cluster.application_cert_manager).to be_scheduled
end
end
context 'when cluster do not exists' do
before do
cluster.destroy!
end
it { is_expected.to have_http_status(:not_found) }
end
context 'when application is unknown' do
let(:application_name) { 'unkwnown-app' }
it { is_expected.to have_http_status(:not_found) }
end
context 'when application is already scheduled' do
before do
application.make_scheduled!
end
xit { is_expected.to have_http_status(:bad_request) }
end
end
describe 'security' do
before do
allow(worker_class).to receive(:perform_async)
end
it_behaves_like 'a secure endpoint'
end
end
end
......@@ -145,4 +145,66 @@ describe Projects::Clusters::ApplicationsController do
it_behaves_like 'a secure endpoint'
end
end
describe 'DELETE destroy' do
subject do
delete :destroy, params: params.merge(namespace_id: project.namespace, project_id: project)
end
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
let!(:application) { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
let(:application_name) { application.name }
let(:params) { { application: application_name, id: cluster.id } }
let(:worker_class) { Clusters::Applications::UninstallWorker }
describe 'functionality' do
let(:user) { create(:user) }
before do
project.add_maintainer(user)
sign_in(user)
end
context "when cluster and app exists" do
it "schedules an application update" do
expect(worker_class).to receive(:perform_async).with(application.name, application.id).once
is_expected.to have_http_status(:no_content)
expect(cluster.application_prometheus).to be_scheduled
end
end
context 'when cluster do not exists' do
before do
cluster.destroy!
end
it { is_expected.to have_http_status(:not_found) }
end
context 'when application is unknown' do
let(:application_name) { 'unkwnown-app' }
it { is_expected.to have_http_status(:not_found) }
end
context 'when application is already scheduled' do
before do
application.make_scheduled!
end
it { is_expected.to have_http_status(:bad_request) }
end
end
describe 'security' do
before do
allow(worker_class).to receive(:perform_async)
end
it_behaves_like 'a secure endpoint'
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Clusters::Applications::DestroyService, '#execute' do
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:user) { create(:user) }
let(:params) { { application: 'prometheus' } }
let(:service) { described_class.new(cluster, user, params) }
let(:test_request) { double }
let(:worker_class) { Clusters::Applications::UninstallWorker }
subject { service.execute(test_request) }
before do
allow(worker_class).to receive(:perform_async)
end
context 'application is not installed' do
it 'raises Clusters::Applications::BaseService::InvalidApplicationError' do
expect(worker_class).not_to receive(:perform_async)
expect { subject }
.to raise_exception { Clusters::Applications::BaseService::InvalidApplicationError }
.and not_change { Clusters::Applications::Prometheus.count }
.and not_change { Clusters::Applications::Prometheus.with_status(:scheduled).count }
end
end
context 'application is installed' do
context 'application is schedulable' do
let!(:application) do
create(:clusters_applications_prometheus, :installed, cluster: cluster)
end
it 'makes application scheduled!' do
subject
expect(application.reload).to be_scheduled
end
it 'schedules UninstallWorker' do
expect(worker_class).to receive(:perform_async).with(application.name, application.id)
subject
end
end
context 'application is not schedulable' do
let!(:application) do
create(:clusters_applications_prometheus, :updating, cluster: cluster)
end
it 'raises StateMachines::InvalidTransition' do
expect(worker_class).not_to receive(:perform_async)
expect { subject }
.to raise_exception { StateMachines::InvalidTransition }
.and not_change { Clusters::Applications::Prometheus.with_status(:scheduled).count }
end
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