Commit 1c314b31 authored by Tiger's avatar Tiger

Extract cluster provider state machine into module

This allows new cluster providers (eg. AWS) to share
the same state machine.
parent 4d2c46e5
......@@ -101,7 +101,7 @@ module Clusters
scope :disabled, -> { where(enabled: false) }
scope :user_provided, -> { where(provider_type: ::Clusters::Cluster.provider_types[:user]) }
scope :gcp_provided, -> { where(provider_type: ::Clusters::Cluster.provider_types[:gcp]) }
scope :gcp_installed, -> { gcp_provided.includes(:provider_gcp).where(cluster_providers_gcp: { status: ::Clusters::Providers::Gcp.state_machines[:status].states[:created].value }) }
scope :gcp_installed, -> { gcp_provided.joins(:provider_gcp).merge(Clusters::Providers::Gcp.with_status(:created)) }
scope :managed, -> { where(managed: true) }
scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) }
......
# frozen_string_literal: true
module Clusters
module Concerns
module ProviderStatus
extend ActiveSupport::Concern
included do
state_machine :status, initial: :scheduled do
state :scheduled, value: 1
state :creating, value: 2
state :created, value: 3
state :errored, value: 4
event :make_creating do
transition any - [:creating] => :creating
end
event :make_created do
transition any - [:created] => :created
end
event :make_errored do
transition any - [:errored] => :errored
end
before_transition any => [:errored, :created] do |provider|
provider.nullify_credentials
end
before_transition any => [:creating] do |provider, transition|
operation_id = transition.args.first
provider.assign_operation_id(operation_id) if operation_id
end
before_transition any => [:errored] do |provider, transition|
status_reason = transition.args.first
provider.status_reason = status_reason if status_reason
end
end
def on_creation?
scheduled? || creating?
end
end
end
end
end
......@@ -3,6 +3,8 @@
module Clusters
module Providers
class Gcp < ApplicationRecord
include Clusters::Concerns::ProviderStatus
self.table_name = 'cluster_providers_gcp'
belongs_to :cluster, inverse_of: :provider_gcp, class_name: 'Clusters::Cluster'
......@@ -35,50 +37,21 @@ module Clusters
greater_than: 0
}
state_machine :status, initial: :scheduled do
state :scheduled, value: 1
state :creating, value: 2
state :created, value: 3
state :errored, value: 4
event :make_creating do
transition any - [:creating] => :creating
end
event :make_created do
transition any - [:created] => :created
end
event :make_errored do
transition any - [:errored] => :errored
end
before_transition any => [:errored, :created] do |provider|
provider.access_token = nil
provider.operation_id = nil
end
before_transition any => [:creating] do |provider, transition|
operation_id = transition.args.first
raise ArgumentError.new('operation_id is required') unless operation_id.present?
provider.operation_id = operation_id
end
def api_client
return unless access_token
before_transition any => [:errored] do |provider, transition|
status_reason = transition.args.first
provider.status_reason = status_reason if status_reason
end
@api_client ||= GoogleApi::CloudPlatform::Client.new(access_token, nil)
end
def on_creation?
scheduled? || creating?
def nullify_credentials
assign_attributes(
access_token: nil,
operation_id: nil
)
end
def api_client
return unless access_token
@api_client ||= GoogleApi::CloudPlatform::Client.new(access_token, nil)
def assign_operation_id(operation_id)
assign_attributes(operation_id: operation_id)
end
def knative_pre_installed?
......
......@@ -6,6 +6,8 @@ describe Clusters::Providers::Gcp do
it { is_expected.to belong_to(:cluster) }
it { is_expected.to validate_presence_of(:zone) }
include_examples 'provider status', :cluster_provider_gcp
describe 'default_value_for' do
let(:gcp) { build(:cluster_provider_gcp) }
......@@ -84,88 +86,6 @@ describe Clusters::Providers::Gcp do
it { is_expected.not_to be_legacy_abac }
end
describe '#state_machine' do
context 'when any => [:created]' do
let(:gcp) { build(:cluster_provider_gcp, :creating) }
before do
gcp.make_created
end
it 'nullify access_token and operation_id' do
expect(gcp.access_token).to be_nil
expect(gcp.operation_id).to be_nil
expect(gcp).to be_created
end
end
context 'when any => [:creating]' do
let(:gcp) { build(:cluster_provider_gcp) }
context 'when operation_id is present' do
let(:operation_id) { 'operation-xxx' }
before do
gcp.make_creating(operation_id)
end
it 'sets operation_id' do
expect(gcp.operation_id).to eq(operation_id)
expect(gcp).to be_creating
end
end
context 'when operation_id is nil' do
let(:operation_id) { nil }
it 'raises an error' do
expect { gcp.make_creating(operation_id) }
.to raise_error('operation_id is required')
end
end
end
context 'when any => [:errored]' do
let(:gcp) { build(:cluster_provider_gcp, :creating) }
let(:status_reason) { 'err msg' }
it 'nullify access_token and operation_id' do
gcp.make_errored(status_reason)
expect(gcp.access_token).to be_nil
expect(gcp.operation_id).to be_nil
expect(gcp.status_reason).to eq(status_reason)
expect(gcp).to be_errored
end
context 'when status_reason is nil' do
let(:gcp) { build(:cluster_provider_gcp, :errored) }
it 'does not set status_reason' do
gcp.make_errored(nil)
expect(gcp.status_reason).not_to be_nil
end
end
end
end
describe '#on_creation?' do
subject { gcp.on_creation? }
context 'when status is creating' do
let(:gcp) { create(:cluster_provider_gcp, :creating) }
it { is_expected.to be_truthy }
end
context 'when status is created' do
let(:gcp) { create(:cluster_provider_gcp, :created) }
it { is_expected.to be_falsey }
end
end
describe '#knative_pre_installed?' do
subject { gcp.knative_pre_installed? }
......@@ -206,4 +126,31 @@ describe Clusters::Providers::Gcp do
it { is_expected.to be_nil }
end
end
describe '#nullify_credentials' do
let(:provider) { create(:cluster_provider_gcp, :creating) }
before do
expect(provider.access_token).to be_present
expect(provider.operation_id).to be_present
end
it 'removes access_token and operation_id' do
provider.nullify_credentials
expect(provider.access_token).to be_nil
expect(provider.operation_id).to be_nil
end
end
describe '#assign_operation_id' do
let(:provider) { create(:cluster_provider_gcp, :scheduled) }
let(:operation_id) { 'operation-123' }
it 'sets operation_id' do
provider.assign_operation_id(operation_id)
expect(provider.operation_id).to eq(operation_id)
end
end
end
# frozen_string_literal: true
shared_examples 'provider status' do |factory|
describe 'state_machine' do
context 'when any => [:created]' do
let(:provider) { build(factory, :creating) }
it 'nullifies API credentials' do
expect(provider).to receive(:nullify_credentials).and_call_original
provider.make_created
expect(provider).to be_created
end
end
context 'when any => [:creating]' do
let(:provider) { build(factory) }
let(:operation_id) { 'operation-xxx' }
it 'calls #operation_id on the provider' do
expect(provider).to receive(:assign_operation_id).with(operation_id).and_call_original
provider.make_creating(operation_id)
end
end
context 'when any => [:errored]' do
let(:provider) { build(factory, :creating) }
let(:status_reason) { 'err msg' }
it 'calls #nullify_credentials on the provider' do
expect(provider).to receive(:nullify_credentials).and_call_original
provider.make_errored(status_reason)
end
it 'sets a status reason' do
provider.make_errored(status_reason)
expect(provider.status_reason).to eq('err msg')
end
context 'when status_reason is nil' do
let(:provider) { build(factory, :errored) }
it 'does not set status_reason' do
provider.make_errored(nil)
expect(provider.status_reason).not_to be_nil
end
end
end
end
describe '#on_creation?' do
using RSpec::Parameterized::TableSyntax
subject { provider.on_creation? }
where(:status, :result) do
:scheduled | true
:creating | true
:created | false
:errored | false
end
with_them do
let(:provider) { build(factory, status) }
it { is_expected.to eq result }
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