Commit 941340e8 authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch '273501-activation-api' into 'master'

Cloud License: Subscription activation service

See merge request gitlab-org/gitlab!51450
parents ec84c3db 49ba1b6a
# frozen_string_literal: true
# Activating self-managed instances
# Part of Cloud Licensing https://gitlab.com/groups/gitlab-org/-/epics/1735
module GitlabSubscriptions
class ActivateService
ERROR_MESSAGES = {
not_self_managed: 'Not self-managed instance',
disabled: 'Cloud license is disabled'
}.freeze
def execute(activation_code)
return error(ERROR_MESSAGES[:not_self_managed]) if Gitlab.com?
return error(ERROR_MESSAGES[:disabled]) unless application_settings.cloud_license_enabled?
response = client.activate(activation_code)
return response unless response[:success]
if application_settings.update(cloud_license_auth_token: response[:authentication_token])
response
else
error(application_settings.errors.full_messages)
end
rescue => e
error(e.message)
end
private
def client
Gitlab::SubscriptionPortal::Client
end
def error(message)
{ success: false, errors: Array(message) }
end
def application_settings
Gitlab::CurrentSettings.current_application_settings
end
end
end
......@@ -24,6 +24,27 @@ module Gitlab
http_get("api/payment_methods/#{id}", admin_headers)
end
def activate(activation_code)
uuid = Gitlab::CurrentSettings.uuid
query = <<~GQL
mutation {
cloudActivationActivate(input: { activationCode: "#{activation_code}", instanceIdentifier: "#{uuid}" }) {
authenticationToken
errors
}
}
GQL
response = http_post("graphql", admin_headers, { query: query }).dig(:data, 'data', 'cloudActivationActivate')
if response['errors'].blank?
{ success: true, authentication_token: response['authenticationToken'] }
else
{ success: false, errors: response['errors'] }
end
end
private
def http_get(path, headers)
......
......@@ -93,4 +93,48 @@ RSpec.describe Gitlab::SubscriptionPortal::Client do
it_behaves_like 'when response code is 422'
it_behaves_like 'when response code is 500'
end
describe '#activate' do
let(:authentication_token) { 'authentication_token' }
it 'returns success' do
expect(described_class).to receive(:http_post).and_return(
{
success: true,
data: {
"data" => {
"cloudActivationActivate" => {
"authenticationToken" => authentication_token,
"errors" => []
}
}
}
}
)
result = described_class.activate('activation_code_abc')
expect(result).to eq({ authentication_token: authentication_token, success: true })
end
it 'returns failure' do
expect(described_class).to receive(:http_post).and_return(
{
success: true,
data: {
"data" => {
"cloudActivationActivate" => {
"authenticationToken" => nil,
"errors" => ["invalid activation code"]
}
}
}
}
)
result = described_class.activate('activation_code_abc')
expect(result).to eq({ errors: ["invalid activation code"], success: false })
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSubscriptions::ActivateService do
let!(:application_settings) do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
create(:application_setting, cloud_license_enabled: cloud_license_enabled)
end
let(:cloud_license_enabled) { true }
let(:authentication_token) { 'authentication_token' }
let(:activation_code) { 'activation_code' }
def stub_client_activate
expect(Gitlab::SubscriptionPortal::Client).to receive(:activate)
.with(activation_code)
.and_return(response)
end
before do
allow(Gitlab::CurrentSettings).to receive(:current_application_settings).and_return(application_settings)
end
context 'when CustomerDot returns success' do
let(:response) { { success: true, authentication_token: authentication_token } }
before do
stub_client_activate
end
it 'persists authentication_token' do
expect(subject.execute(activation_code)).to eq(response)
expect(application_settings.reload.cloud_license_auth_token).to eq(authentication_token)
end
context 'when persisting fails' do
let(:response) { { success: true, authentication_token: authentication_token } }
it 'returns error' do
application_settings.errors.add(:base, :invalid)
allow(application_settings).to receive(:update).and_return(false)
expect(subject.execute(activation_code)).to eq({ errors: ["is invalid"], success: false })
end
end
end
context 'when CustomerDot returns failure' do
let(:response) { { success: false, errors: ['foo'] } }
it 'returns error' do
stub_client_activate
expect(subject.execute(activation_code)).to eq(response)
expect(application_settings.reload.cloud_license_auth_token).to be_nil
end
end
context 'when not self managed instance' do
let(:response) { { success: false, errors: [described_class::ERROR_MESSAGES[:not_self_managed]] }}
it 'returns error' do
allow(Gitlab).to receive(:com?).and_return(true)
expect(Gitlab::SubscriptionPortal::Client).not_to receive(:activate)
expect(subject.execute(activation_code)).to eq(response)
end
end
context 'when cloud licensing disabled' do
let(:response) { { success: false, errors: [described_class::ERROR_MESSAGES[:disabled]] }}
let(:cloud_license_enabled) { false }
it 'returns error' do
expect(Gitlab::SubscriptionPortal::Client).not_to receive(:activate)
expect(subject.execute(activation_code)).to eq(response)
end
end
context 'when error is raised' do
it 'captures error' do
expect(Gitlab::SubscriptionPortal::Client).to receive(:activate).and_raise('foo')
expect(subject.execute(activation_code)).to eq({ success: false, errors: ['foo'] })
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