Read about our upcoming Code of Conduct on this issue

Commit 1427bdca authored by Kamil Trzcinski's avatar Kamil Trzcinski
Browse files

Revert back FetchKubernetesTokenService

parent 5b732ee4d678
......@@ -29,7 +29,6 @@ def login
def new
@cluster = Clusters::Cluster.new.tap do |cluster|
cluster.build_provider_gcp
cluster.build_platform_kubernetes
end
end
......
......@@ -18,8 +18,6 @@ class Cluster < ActiveRecord::Base
accepts_nested_attributes_for :provider_gcp, update_only: true
accepts_nested_attributes_for :platform_kubernetes, update_only: true
validates :provider_type, presence: true
validates :platform_type, presence: true
validates :name, cluster_name: true
validate :restrict_modification, on: :update
......
......@@ -28,7 +28,7 @@ class Kubernetes < ActiveRecord::Base
}
# We expect to be `active?` only when enabled and cluster is created (the api_url is assigned)
with_options presence: true, if: :active? do
with_options presence: true, if: :enabled? do
validates :api_url, url: true, presence: true
validates :token, presence: true
end
......@@ -42,10 +42,6 @@ class Kubernetes < ActiveRecord::Base
delegate :project, to: :cluster, allow_nil: true
delegate :enabled?, to: :cluster, allow_nil: true
def active?
enabled? && api_url.present?
end
class << self
def namespace_for_project(project)
"#{project.path}-#{project.id}"
......@@ -87,7 +83,7 @@ def update_kubernetes_integration!
return raise 'Kubernetes service already configured' unless manages_kubernetes_service?
ensure_kubernetes_service.update!(
active: active?,
active: enabled?,
api_url: api_url,
namespace: namespace,
token: token,
......
##
# TODO:
# Almost components in this class were copied from app/models/project_services/kubernetes_service.rb
# We should dry up those classes not to repeat the same code.
# Maybe we should have a special facility (e.g. lib/kubernetes_api) to maintain all Kubernetes API caller.
module Ci
class FetchKubernetesTokenService
attr_reader :api_url, :ca_pem, :username, :password
def initialize(api_url, ca_pem, username, password)
@api_url = api_url
@ca_pem = ca_pem
@username = username
@password = password
end
def execute
read_secrets.each do |secret|
name = secret.dig('metadata', 'name')
if /default-token/ =~ name
token_base64 = secret.dig('data', 'token')
return Base64.decode64(token_base64) if token_base64
end
end
nil
end
private
def read_secrets
kubeclient = build_kubeclient!
kubeclient.get_secrets.as_json
rescue KubeException => err
raise err unless err.error_code == 404
[]
end
def build_kubeclient!(api_path: 'api', api_version: 'v1')
raise "Incomplete settings" unless api_url && username && password
::Kubeclient::Client.new(
join_api_url(api_path),
api_version,
auth_options: { username: username, password: password },
ssl_options: kubeclient_ssl_options,
http_proxy_uri: ENV['http_proxy']
)
end
def join_api_url(api_path)
url = URI.parse(api_url)
prefix = url.path.sub(%r{/+\z}, '')
url.path = [prefix, api_path].join("/")
url.to_s
end
def kubeclient_ssl_options
opts = { verify_ssl: OpenSSL::SSL::VERIFY_PEER }
if ca_pem.present?
opts[:cert_store] = OpenSSL::X509::Store.new
opts[:cert_store].add_cert(OpenSSL::X509::Certificate.new(ca_pem))
end
opts
end
end
end
......@@ -9,10 +9,7 @@ def execute(provider)
configure_provider
configure_kubernetes
ActiveRecord::Base.transaction do
kubernetes.save!
provider.make_created!
end
provider.make_created!
rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
provider.make_errored!("Failed to request to CloudPlatform; #{e.message}")
rescue KubeException => e
......@@ -28,23 +25,21 @@ def configure_provider
end
def configure_kubernetes
kubernetes.api_url = 'https://' + gke_cluster.endpoint
kubernetes.ca_cert = Base64.decode64(gke_cluster.master_auth.cluster_ca_certificate)
kubernetes.username = gke_cluster.master_auth.username
kubernetes.password = gke_cluster.master_auth.password
kubernetes.token = request_kuberenetes_token
cluster.platform_type = :kubernetes
cluster.build_platform_kubernetes(
api_url: 'https://' + gke_cluster.endpoint,
ca_cert: Base64.decode64(gke_cluster.master_auth.cluster_ca_certificate),
username: gke_cluster.master_auth.username,
password: gke_cluster.master_auth.password,
token: request_kuberenetes_token)
end
def request_kuberenetes_token
kubernetes.read_secrets.each do |secret|
name = secret.dig('metadata', 'name')
if /default-token/ =~ name
token_base64 = secret.dig('data', 'token')
return Base64.decode64(token_base64) if token_base64
end
end
nil
Ci::FetchKubernetesTokenService.new(
'https://' + gke_cluster.endpoint,
Base64.decode64(gke_cluster.master_auth.cluster_ca_certificate),
gke_cluster.master_auth.username,
gke_cluster.master_auth.password)
end
def gke_cluster
......@@ -57,10 +52,6 @@ def gke_cluster
def cluster
@cluster ||= provider.cluster
end
def kubernetes
@kubernetes ||= cluster.platform_kubernetes
end
end
end
end
......@@ -5,8 +5,7 @@
= s_('ClusterIntegration|Read our %{link_to_help_page} on cluster integration.').html_safe % { link_to_help_page: link_to_help_page}
= form_for @cluster, url: namespace_project_clusters_path(@project.namespace, @project, @cluster), as: :cluster do |field|
= field.hidden_field :platform_type, :value => 'kubernetes'
= field.hidden_field :provider_type, :value => 'gcp'
= field.hidden_field :provider_type, value: :gcp
= form_errors(@cluster)
.form-group
= field.label :name, s_('ClusterIntegration|Cluster name')
......@@ -32,10 +31,5 @@
= link_to(s_('ClusterIntegration|See machine types'), 'https://cloud.google.com/compute/docs/machine-types', target: '_blank', rel: 'noopener noreferrer')
= provider_gcp_field.text_field :machine_type, class: 'form-control', placeholder: 'n1-standard-4'
= field.fields_for :platform_kubernetes, @cluster.platform_kubernetes do |platform_kubernetes_field|
.form-group
= platform_kubernetes_field.label :namespace, s_('ClusterIntegration|Project namespace (optional, unique)')
= platform_kubernetes_field.text_field :namespace, class: 'form-control', placeholder: Clusters::Platforms::Kubernetes.namespace_for_project(@project)
.form-group
= field.submit s_('ClusterIntegration|Create cluster'), class: 'btn btn-save'
......@@ -5,8 +5,8 @@ def change
create_table :clusters do |t|
t.references :user, null: false, index: true, foreign_key: { on_delete: :nullify }
t.integer :provider_type, null: false
t.integer :platform_type, null: false
t.integer :provider_type
t.integer :platform_type
t.datetime_with_timezone :created_at, null: false
t.datetime_with_timezone :updated_at, null: false
......
......@@ -508,8 +508,8 @@
create_table "clusters", force: :cascade do |t|
t.integer "user_id", null: false
t.integer "provider_type", null: false
t.integer "platform_type", null: false
t.integer "provider_type"
t.integer "platform_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "enabled", default: true
......
require 'spec_helper'
describe Ci::FetchKubernetesTokenService do
describe '#execute' do
subject { described_class.new(api_url, ca_pem, username, password).execute }
let(:api_url) { 'http://111.111.111.111' }
let(:ca_pem) { '' }
let(:username) { 'admin' }
let(:password) { 'xxx' }
context 'when params correct' do
let(:token) { 'xxx.token.xxx' }
let(:secrets_json) do
[
{
'metadata': {
name: metadata_name
},
'data': {
'token': Base64.encode64(token)
}
}
]
end
before do
allow_any_instance_of(Kubeclient::Client)
.to receive(:get_secrets).and_return(secrets_json)
end
context 'when default-token exists' do
let(:metadata_name) { 'default-token-123' }
it { is_expected.to eq(token) }
end
context 'when default-token does not exist' do
let(:metadata_name) { 'another-token-123' }
it { is_expected.to be_nil }
end
end
context 'when api_url is nil' do
let(:api_url) { nil }
it { expect { subject }.to raise_error("Incomplete settings") }
end
context 'when username is nil' do
let(:username) { nil }
it { expect { subject }.to raise_error("Incomplete settings") }
end
context 'when password is nil' do
let(:password) { nil }
it { expect { subject }.to raise_error("Incomplete settings") }
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