summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiger <twatson@gitlab.com>2019-08-23 15:38:25 +1000
committerTiger <twatson@gitlab.com>2019-09-02 13:30:35 +1000
commitd0b403a289a924421633ead6f3ab1dbd4fbec051 (patch)
treed79c0d024aca8ef44922b53cb6458f1d48a54e9a
parent34357e03866e73c17df60ba003d46482193cbcd4 (diff)
downloadgitlab-ce-46686-aws-cluster-provider.tar.gz
Add AWS cluster provider46686-aws-cluster-provider
Almost identical to the existing GCP cluster data model, introduce model to represent an EKS cluster that has been created by GitLab.
-rw-r--r--app/models/clusters/cluster.rb21
-rw-r--r--app/models/clusters/concerns/provider_status.rb50
-rw-r--r--app/models/clusters/providers/aws.rb53
-rw-r--r--app/models/clusters/providers/gcp.rb51
-rw-r--r--db/migrate/20190821040941_create_cluster_providers_aws.rb32
-rw-r--r--db/schema.rb18
-rw-r--r--lib/gitlab/regex.rb9
-rw-r--r--lib/gitlab/usage_data.rb1
-rw-r--r--spec/db/schema_spec.rb1
-rw-r--r--spec/factories/clusters/clusters.rb8
-rw-r--r--spec/factories/clusters/providers/aws.rb34
-rw-r--r--spec/lib/gitlab/regex_spec.rb9
-rw-r--r--spec/models/clusters/cluster_spec.rb10
-rw-r--r--spec/models/clusters/providers/aws_spec.rb110
-rw-r--r--spec/models/clusters/providers/gcp_spec.rb115
-rw-r--r--spec/support/shared_examples/models/clusters/providers/provider_status.rb67
16 files changed, 467 insertions, 122 deletions
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 444e1a82c97..a9392bd40f9 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -34,6 +34,7 @@ module Clusters
# we force autosave to happen when we save `Cluster` model
has_one :provider_gcp, class_name: 'Clusters::Providers::Gcp', autosave: true
+ has_one :provider_aws, class_name: 'Clusters::Providers::Aws', autosave: true
has_one :platform_kubernetes, class_name: 'Clusters::Platforms::Kubernetes', inverse_of: :cluster, autosave: true
@@ -89,14 +90,20 @@ module Clusters
enum provider_type: {
user: 0,
- gcp: 1
+ gcp: 1,
+ aws: 2
}
scope :enabled, -> { where(enabled: true) }
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 :user_provided, -> { where(provider_type: provider_types[:user]) }
+ scope :gcp_provided, -> { where(provider_type: provider_types[:gcp]) }
+ scope :aws_provided, -> { where(provider_type: provider_types[:aws]) }
+
+ scope :gcp_installed, -> { gcp_provided.joins(:provider_gcp).merge(Clusters::Providers::Gcp.created) }
+ scope :aws_installed, -> { aws_provided.joins(:provider_aws).merge(Clusters::Providers::Aws.created) }
+
scope :managed, -> { where(managed: true) }
scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) }
@@ -139,7 +146,11 @@ module Clusters
end
def provider
- return provider_gcp if gcp?
+ if gcp?
+ provider_gcp
+ elsif aws?
+ provider_aws
+ end
end
def platform
diff --git a/app/models/clusters/concerns/provider_status.rb b/app/models/clusters/concerns/provider_status.rb
new file mode 100644
index 00000000000..9141d8fea8a
--- /dev/null
+++ b/app/models/clusters/concerns/provider_status.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Concerns
+ module ProviderStatus
+ extend ActiveSupport::Concern
+
+ included do
+ scope :created, -> { where(status: state_machines[:status].states[:created].value) }
+
+ 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
diff --git a/app/models/clusters/providers/aws.rb b/app/models/clusters/providers/aws.rb
new file mode 100644
index 00000000000..77d9114093e
--- /dev/null
+++ b/app/models/clusters/providers/aws.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Providers
+ class Aws < ApplicationRecord
+ include Clusters::Concerns::ProviderStatus
+
+ self.table_name = 'cluster_providers_aws'
+
+ belongs_to :cluster, inverse_of: :provider_aws, class_name: 'Clusters::Cluster'
+
+ default_value_for :region, 'us-east-1'
+ default_value_for :num_nodes, 3
+ default_value_for :machine_type, 'm5.large'
+
+ attr_encrypted :secret_access_key,
+ mode: :per_attribute_iv,
+ key: Settings.attr_encrypted_db_key_base_truncated,
+ algorithm: 'aes-256-cbc'
+
+ validates :aws_account_id,
+ length: { is: 12 },
+ format: {
+ with: Gitlab::Regex.aws_account_id_regex,
+ message: Gitlab::Regex.aws_account_id_regex_message
+ }
+
+ validates :num_nodes,
+ presence: true,
+ numericality: {
+ only_integer: true,
+ greater_than: 0
+ }
+
+ validates :region, :machine_type, presence: true
+
+ before_validation :sanitize_aws_account_id
+
+ def nullify_credentials
+ assign_attributes(
+ access_key_id: nil,
+ secret_access_key: nil
+ )
+ end
+
+ private
+
+ def sanitize_aws_account_id
+ self.aws_account_id&.gsub!(/\D/, '')
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/providers/gcp.rb b/app/models/clusters/providers/gcp.rb
index 390748bf252..0069946132d 100644
--- a/app/models/clusters/providers/gcp.rb
+++ b/app/models/clusters/providers/gcp.rb
@@ -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'
@@ -32,50 +34,23 @@ 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
+ def assign_operation_id(operation_id)
+ raise ArgumentError.new('operation_id is required') unless operation_id.present?
- @api_client ||= GoogleApi::CloudPlatform::Client.new(access_token, nil)
+ assign_attributes(operation_id: operation_id)
end
end
end
diff --git a/db/migrate/20190821040941_create_cluster_providers_aws.rb b/db/migrate/20190821040941_create_cluster_providers_aws.rb
new file mode 100644
index 00000000000..1dcc32ec09a
--- /dev/null
+++ b/db/migrate/20190821040941_create_cluster_providers_aws.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class CreateClusterProvidersAws < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ create_table :cluster_providers_aws do |t|
+ t.references :cluster, null: false, type: :bigint, index: { unique: true }, foreign_key: { on_delete: :cascade }
+
+ t.integer :status, null: false
+ t.text :status_reason
+
+ t.string :aws_account_id, null: false, limit: 12
+ t.string :region, null: false, limit: 64
+ t.integer :num_nodes, null: false
+ t.string :machine_type, null: false, limit: 64
+
+ t.string :access_key_id, limit: 64
+ t.text :encrypted_secret_access_key
+ t.string :encrypted_secret_access_key_iv, limit: 255
+
+ t.timestamps_with_timezone null: false
+
+ t.index [:cluster_id, :status]
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 5999a859e77..add2d63d909 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -905,6 +905,23 @@ ActiveRecord::Schema.define(version: 2019_08_28_083843) do
t.index ["project_id"], name: "index_cluster_projects_on_project_id"
end
+ create_table "cluster_providers_aws", force: :cascade do |t|
+ t.bigint "cluster_id", null: false
+ t.integer "status", null: false
+ t.text "status_reason"
+ t.string "aws_account_id", null: false
+ t.string "region", null: false
+ t.integer "num_nodes", null: false
+ t.string "machine_type", null: false
+ t.string "access_key_id"
+ t.text "encrypted_secret_access_key"
+ t.string "encrypted_secret_access_key_iv"
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.index ["cluster_id", "status"], name: "index_cluster_providers_aws_on_cluster_id_and_status"
+ t.index ["cluster_id"], name: "index_cluster_providers_aws_on_cluster_id", unique: true
+ end
+
create_table "cluster_providers_gcp", id: :serial, force: :cascade do |t|
t.integer "cluster_id", null: false
t.integer "status"
@@ -3790,6 +3807,7 @@ ActiveRecord::Schema.define(version: 2019_08_28_083843) do
add_foreign_key "cluster_platforms_kubernetes", "clusters", on_delete: :cascade
add_foreign_key "cluster_projects", "clusters", on_delete: :cascade
add_foreign_key "cluster_projects", "projects", on_delete: :cascade
+ add_foreign_key "cluster_providers_aws", "clusters", on_delete: :cascade
add_foreign_key "cluster_providers_gcp", "clusters", on_delete: :cascade
add_foreign_key "clusters", "users", on_delete: :nullify
add_foreign_key "clusters_applications_cert_managers", "clusters", on_delete: :cascade
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index e6372a42dda..a366b84cfdd 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -115,5 +115,14 @@ module Gitlab
def jira_transition_id_regex
@jira_transition_id_regex ||= /\d+/
end
+
+ # https://docs.aws.amazon.com/general/latest/gr/acct-identifiers.html
+ def aws_account_id_regex
+ /\A\d+\z/
+ end
+
+ def aws_account_id_regex_message
+ "can contain only digits, optionally separated by '-'"
+ end
end
end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index a93301cb4ce..4338c9afc25 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -66,6 +66,7 @@ module Gitlab
clusters_disabled: count(::Clusters::Cluster.disabled),
project_clusters_disabled: count(::Clusters::Cluster.disabled.project_type),
group_clusters_disabled: count(::Clusters::Cluster.disabled.group_type),
+ clusters_platforms_eks: count(::Clusters::Cluster.aws_installed.enabled),
clusters_platforms_gke: count(::Clusters::Cluster.gcp_installed.enabled),
clusters_platforms_user: count(::Clusters::Cluster.user_provided.enabled),
clusters_applications_helm: count(::Clusters::Applications::Helm.available),
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 52af470efac..c0578773ac9 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -24,6 +24,7 @@ describe 'Database schema' do
ci_pipelines: %w[user_id],
ci_runner_projects: %w[runner_id],
ci_trigger_requests: %w[commit_id],
+ cluster_providers_aws: %w[aws_account_id access_key_id],
cluster_providers_gcp: %w[gcp_project_id operation_id],
deploy_keys_projects: %w[deploy_key_id],
deployments: %w[deployable_id environment_id user_id],
diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb
index d294e6d055e..39ab9685584 100644
--- a/spec/factories/clusters/clusters.rb
+++ b/spec/factories/clusters/clusters.rb
@@ -49,6 +49,14 @@ FactoryBot.define do
platform_kubernetes factory: [:cluster_platform_kubernetes, :configured]
end
+ trait :provided_by_aws do
+ provider_type :aws
+ platform_type :kubernetes
+
+ provider_aws factory: [:cluster_provider_aws, :created]
+ platform_kubernetes factory: [:cluster_platform_kubernetes, :configured]
+ end
+
trait :providing_by_gcp do
provider_type :gcp
provider_gcp factory: [:cluster_provider_gcp, :creating]
diff --git a/spec/factories/clusters/providers/aws.rb b/spec/factories/clusters/providers/aws.rb
new file mode 100644
index 00000000000..ff4fae9195a
--- /dev/null
+++ b/spec/factories/clusters/providers/aws.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :cluster_provider_aws, class: Clusters::Providers::Aws do
+ cluster
+ aws_account_id '123456789012'
+
+ trait :scheduled do
+ access_key_id 'access_key_id'
+ secret_access_key 'secret_access_key'
+ end
+
+ trait :creating do
+ access_key_id 'access_key_id'
+ secret_access_key 'secret_access_key'
+
+ after(:build) do |provider|
+ provider.make_creating
+ end
+ end
+
+ trait :created do
+ after(:build) do |provider|
+ provider.make_created
+ end
+ end
+
+ trait :errored do
+ after(:build) do |provider|
+ provider.make_errored('An error occurred')
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index e19210d8fbf..1341602d748 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -65,4 +65,13 @@ describe Gitlab::Regex do
it { is_expected.not_to match('.my/image') }
it { is_expected.not_to match('my/image.') }
end
+
+ describe '.aws_account_id_regex' do
+ subject { described_class.aws_account_id_regex }
+
+ it { is_expected.to match('12345') }
+ it { is_expected.to match('123456789012') }
+ it { is_expected.not_to match('abcdefg') }
+ it { is_expected.not_to match('1234-5678-9012') }
+ end
end
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 9afbe6328ca..7337871224b 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -16,6 +16,7 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
it { is_expected.to have_many(:cluster_groups) }
it { is_expected.to have_many(:groups) }
it { is_expected.to have_one(:provider_gcp) }
+ it { is_expected.to have_one(:provider_aws) }
it { is_expected.to have_one(:platform_kubernetes) }
it { is_expected.to have_one(:application_helm) }
it { is_expected.to have_one(:application_ingress) }
@@ -374,7 +375,14 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
it 'returns a provider' do
is_expected.to eq(cluster.provider_gcp)
- expect(subject.class.name.deconstantize).to eq(Clusters::Providers.to_s)
+ end
+ end
+
+ context 'when provider is aws' do
+ let(:cluster) { create(:cluster, :provided_by_aws) }
+
+ it 'returns a provider' do
+ is_expected.to eq(cluster.provider_aws)
end
end
diff --git a/spec/models/clusters/providers/aws_spec.rb b/spec/models/clusters/providers/aws_spec.rb
new file mode 100644
index 00000000000..1f39539caf8
--- /dev/null
+++ b/spec/models/clusters/providers/aws_spec.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Clusters::Providers::Aws do
+ it { is_expected.to belong_to(:cluster) }
+ it { is_expected.to validate_presence_of(:region) }
+
+ include_examples 'provider status', :cluster_provider_aws
+
+ describe 'default_value_for' do
+ let(:provider) { build(:cluster_provider_aws) }
+
+ it "sets default values" do
+ expect(provider.region).to eq('us-east-1')
+ expect(provider.num_nodes).to eq(3)
+ expect(provider.machine_type).to eq('m5.large')
+ end
+ end
+
+ describe 'validation' do
+ subject { provider.valid? }
+
+ context ':aws_account_id' do
+ let(:provider) { build(:cluster_provider_aws, aws_account_id: aws_account_id) }
+
+ context 'length is shorter than 12' do
+ let(:aws_account_id) { '1' * 11 }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'length is longer than 12' do
+ let(:aws_account_id) { '1' * 13 }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'has invalid characters' do
+ let(:aws_account_id) { '0123456789ab' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'account ID is valid' do
+ let(:aws_account_id) { '123456789012' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'account ID is valid, but contains hypens' do
+ let(:aws_account_id) { '1234-5678-9012' }
+
+ it { is_expected.to be_truthy }
+
+ it 'strips hyphens before validating' do
+ is_expected.to be_truthy
+
+ expect(provider.aws_account_id).to eq('123456789012')
+ end
+ end
+ end
+
+ context ':num_nodes' do
+ let(:provider) { build(:cluster_provider_aws, num_nodes: num_nodes) }
+
+ context 'contains non-digit characters' do
+ let(:num_nodes) { 'A3' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'is blank' do
+ let(:num_nodes) { nil }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'is less than 1' do
+ let(:num_nodes) { 0 }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'is a positive integer' do
+ let(:num_nodes) { 3 }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+ end
+
+ describe '#nullify_credentials' do
+ let(:provider) { create(:cluster_provider_aws, :scheduled) }
+
+ subject { provider.nullify_credentials }
+
+ before do
+ expect(provider.access_key_id).to be_present
+ expect(provider.secret_access_key).to be_present
+ end
+
+ it 'removes access_key_id and secret_access_key' do
+ subject
+
+ expect(provider.access_key_id).to be_nil
+ expect(provider.secret_access_key).to be_nil
+ end
+ end
+end
diff --git a/spec/models/clusters/providers/gcp_spec.rb b/spec/models/clusters/providers/gcp_spec.rb
index 785db4febe0..c0aa3fb2c9d 100644
--- a/spec/models/clusters/providers/gcp_spec.rb
+++ b/spec/models/clusters/providers/gcp_spec.rb
@@ -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,110 +86,67 @@ 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) }
+ describe '#api_client' do
+ subject { gcp.api_client }
- before do
- gcp.make_created
- end
+ context 'when status is creating' do
+ let(:gcp) { build(:cluster_provider_gcp, :creating) }
- 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
+ it 'returns Cloud Platform API clinet' do
+ expect(subject).to be_an_instance_of(GoogleApi::CloudPlatform::Client)
+ expect(subject.access_token).to eq(gcp.access_token)
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 }
+ context 'when status is created' do
+ let(:gcp) { build(:cluster_provider_gcp, :created) }
- it 'raises an error' do
- expect { gcp.make_creating(operation_id) }
- .to raise_error('operation_id is required')
- end
- end
+ it { is_expected.to be_nil }
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)
+ context 'when status is errored' do
+ let(:gcp) { build(:cluster_provider_gcp, :errored) }
- expect(gcp.status_reason).not_to be_nil
- end
- end
+ it { is_expected.to be_nil }
end
end
- describe '#on_creation?' do
- subject { gcp.on_creation? }
+ describe '#nullify_credentials' do
+ let(:provider) { create(:cluster_provider_gcp, :creating) }
- context 'when status is creating' do
- let(:gcp) { create(:cluster_provider_gcp, :creating) }
+ subject { provider.nullify_credentials }
- it { is_expected.to be_truthy }
+ before do
+ expect(provider.access_token).to be_present
+ expect(provider.operation_id).to be_present
end
- context 'when status is created' do
- let(:gcp) { create(:cluster_provider_gcp, :created) }
+ it 'removes access_token and operation_id' do
+ subject
- it { is_expected.to be_falsey }
+ expect(provider.access_token).to be_nil
+ expect(provider.operation_id).to be_nil
end
end
- describe '#api_client' do
- subject { gcp.api_client }
-
- context 'when status is creating' do
- let(:gcp) { build(:cluster_provider_gcp, :creating) }
+ describe '#assign_operation_id' do
+ let(:provider) { create(:cluster_provider_gcp, :scheduled) }
+ let(:operation_id) { 'operation-123' }
- it 'returns Cloud Platform API clinet' do
- expect(subject).to be_an_instance_of(GoogleApi::CloudPlatform::Client)
- expect(subject.access_token).to eq(gcp.access_token)
- end
- end
+ subject { provider.assign_operation_id(operation_id) }
- context 'when status is created' do
- let(:gcp) { build(:cluster_provider_gcp, :created) }
+ it 'sets operation_id' do
+ subject
- it { is_expected.to be_nil }
+ expect(provider.operation_id).to eq(operation_id)
end
- context 'when status is errored' do
- let(:gcp) { build(:cluster_provider_gcp, :errored) }
+ context 'operation ID is nil' do
+ let(:operation_id) { nil }
- it { is_expected.to be_nil }
+ it 'raises an error' do
+ expect { subject }.to raise_error(ArgumentError, 'operation_id is required')
+ end
end
end
end
diff --git a/spec/support/shared_examples/models/clusters/providers/provider_status.rb b/spec/support/shared_examples/models/clusters/providers/provider_status.rb
new file mode 100644
index 00000000000..507634d8ce7
--- /dev/null
+++ b/spec/support/shared_examples/models/clusters/providers/provider_status.rb
@@ -0,0 +1,67 @@
+# 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)
+ 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 'sets operation_id' do
+ expect(provider).to receive(:assign_operation_id).with(operation_id)
+
+ provider.make_creating(operation_id)
+ end
+ end
+
+ context 'when any => [:errored]' do
+ let(:provider) { build(factory, :creating) }
+ let(:status_reason) { 'err msg' }
+
+ it 'removes access_token and operation_id' do
+ expect(provider).to receive(:nullify_credentials)
+
+ provider.make_errored(status_reason)
+
+ expect(provider.status_reason).to eq(status_reason)
+ expect(provider).to be_errored
+ 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
+ subject { provider.on_creation? }
+
+ context 'when status is creating' do
+ let(:provider) { create(factory, :creating) }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when status is created' do
+ let(:provider) { create(factory, :created) }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+end