Commit 3a3a767c authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'triggermesh-phase2-external-ip' into 'master'

Expose External IP address for Knative's gateway

See merge request gitlab-org/gitlab-ce!23162
parents 195e3371 2937be7b
...@@ -168,6 +168,9 @@ export default { ...@@ -168,6 +168,9 @@ export default {
knativeInstalled() { knativeInstalled() {
return this.applications.knative.status === APPLICATION_STATUS.INSTALLED; return this.applications.knative.status === APPLICATION_STATUS.INSTALLED;
}, },
knativeExternalIp() {
return this.applications.knative.externalIp;
},
}, },
created() { created() {
this.helmInstallIllustration = helmInstallIllustration; this.helmInstallIllustration = helmInstallIllustration;
...@@ -443,6 +446,49 @@ export default { ...@@ -443,6 +446,49 @@ export default {
/> />
</div> </div>
</template> </template>
<template v-if="knativeInstalled">
<div class="form-group">
<label for="knative-ip-address">
{{ s__('ClusterIntegration|Knative IP Address:') }}
</label>
<div v-if="knativeExternalIp" class="input-group">
<input
id="knative-ip-address"
:value="knativeExternalIp"
type="text"
class="form-control js-ip-address"
readonly
/>
<span class="input-group-append">
<clipboard-button
:text="knativeExternalIp"
:title="s__('ClusterIntegration|Copy Knative IP Address to clipboard')"
class="input-group-text js-clipboard-btn"
/>
</span>
</div>
<input v-else type="text" class="form-control js-ip-address" readonly value="?" />
</div>
<p v-if="!knativeExternalIp" class="settings-message js-no-ip-message">
{{
s__(`ClusterIntegration|The IP address is in
the process of being assigned. Please check your Kubernetes
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
}}
</p>
<p>
{{
s__(`ClusterIntegration|Point a wildcard DNS to this
generated IP address in order to access
your application after it has been deployed.`)
}}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }}
</a>
</p>
</template>
</div> </div>
</application-row> </application-row>
</div> </div>
......
...@@ -60,6 +60,7 @@ export default class ClusterStore { ...@@ -60,6 +60,7 @@ export default class ClusterStore {
requestStatus: null, requestStatus: null,
requestReason: null, requestReason: null,
hostname: null, hostname: null,
externalIp: null,
}, },
}, },
}; };
...@@ -111,6 +112,8 @@ export default class ClusterStore { ...@@ -111,6 +112,8 @@ export default class ClusterStore {
} else if (appId === KNATIVE) { } else if (appId === KNATIVE) {
this.state.applications.knative.hostname = this.state.applications.knative.hostname =
serverAppEntry.hostname || this.state.applications.knative.hostname; serverAppEntry.hostname || this.state.applications.knative.hostname;
this.state.applications.knative.externalIp =
serverAppEntry.external_ip || this.state.applications.knative.externalIp;
} }
}); });
} }
......
...@@ -51,6 +51,10 @@ module Clusters ...@@ -51,6 +51,10 @@ module Clusters
ClusterWaitForIngressIpAddressWorker.perform_async(name, id) ClusterWaitForIngressIpAddressWorker.perform_async(name, id)
end end
def ingress_service
cluster.kubeclient.get_service('ingress-nginx-ingress-controller', Gitlab::Kubernetes::Helm::NAMESPACE)
end
end end
end end
end end
...@@ -6,9 +6,7 @@ module Clusters ...@@ -6,9 +6,7 @@ module Clusters
VERSION = '0.1.3'.freeze VERSION = '0.1.3'.freeze
REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze
# This is required for helm version <= 2.10.x in order to support FETCH_IP_ADDRESS_DELAY = 30.seconds
# Setting up CRDs
ISTIO_CRDS = 'https://storage.googleapis.com/triggermesh-charts/istio-crds.yaml'.freeze
self.table_name = 'clusters_applications_knative' self.table_name = 'clusters_applications_knative'
...@@ -16,6 +14,16 @@ module Clusters ...@@ -16,6 +14,16 @@ module Clusters
include ::Clusters::Concerns::ApplicationStatus include ::Clusters::Concerns::ApplicationStatus
include ::Clusters::Concerns::ApplicationVersion include ::Clusters::Concerns::ApplicationVersion
include ::Clusters::Concerns::ApplicationData include ::Clusters::Concerns::ApplicationData
include AfterCommitQueue
state_machine :status do
before_transition any => [:installed] do |application|
application.run_after_commit do
ClusterWaitForIngressIpAddressWorker.perform_in(
FETCH_IP_ADDRESS_DELAY, application.name, application.id)
end
end
end
default_value_for :version, VERSION default_value_for :version, VERSION
...@@ -36,19 +44,23 @@ module Clusters ...@@ -36,19 +44,23 @@ module Clusters
rbac: cluster.platform_kubernetes_rbac?, rbac: cluster.platform_kubernetes_rbac?,
chart: chart, chart: chart,
files: files, files: files,
repository: REPOSITORY, repository: REPOSITORY
preinstall: install_script
) )
end end
def client def schedule_status_update
cluster.platform_kubernetes.kubeclient.knative_client return unless installed?
return if external_ip
ClusterWaitForIngressIpAddressWorker.perform_async(name, id)
end end
private def ingress_service
cluster.kubeclient.get_service('knative-ingressgateway', 'istio-system')
end
def install_script def client
["/usr/bin/kubectl apply -f #{ISTIO_CRDS}"] cluster.platform_kubernetes.kubeclient.knative_client
end end
end end
end end
......
...@@ -30,7 +30,7 @@ module Clusters ...@@ -30,7 +30,7 @@ module Clusters
def service def service
strong_memoize(:ingress_service) do strong_memoize(:ingress_service) do
kubeclient.get_service('ingress-nginx-ingress-controller', Gitlab::Kubernetes::Helm::NAMESPACE) app.ingress_service
end end
end end
end end
......
---
title: Add an external IP address to the knative cluster application page
merge_request:
author: Chris Baumbauer
type: fixed
# 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 KnativeExternalIp < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :clusters_applications_knative, :external_ip, :string
end
end
...@@ -698,6 +698,7 @@ ActiveRecord::Schema.define(version: 20181126153547) do ...@@ -698,6 +698,7 @@ ActiveRecord::Schema.define(version: 20181126153547) do
t.string "version", null: false t.string "version", null: false
t.string "hostname" t.string "hostname"
t.text "status_reason" t.text "status_reason"
t.string "external_ip"
t.index ["cluster_id"], name: "index_clusters_applications_knative_on_cluster_id", unique: true, using: :btree t.index ["cluster_id"], name: "index_clusters_applications_knative_on_cluster_id", unique: true, using: :btree
end end
......
...@@ -1451,6 +1451,9 @@ msgstr "" ...@@ -1451,6 +1451,9 @@ msgstr ""
msgid "ClusterIntegration|Copy Jupyter Hostname to clipboard" msgid "ClusterIntegration|Copy Jupyter Hostname to clipboard"
msgstr "" msgstr ""
msgid "ClusterIntegration|Copy Knative IP Address to clipboard"
msgstr ""
msgid "ClusterIntegration|Copy Kubernetes cluster name" msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr "" msgstr ""
...@@ -1559,6 +1562,9 @@ msgstr "" ...@@ -1559,6 +1562,9 @@ msgstr ""
msgid "ClusterIntegration|Knative Domain Name:" msgid "ClusterIntegration|Knative Domain Name:"
msgstr "" msgstr ""
msgid "ClusterIntegration|Knative IP Address:"
msgstr ""
msgid "ClusterIntegration|Kubernetes cluster" msgid "ClusterIntegration|Kubernetes cluster"
msgstr "" msgstr ""
......
...@@ -59,6 +59,7 @@ FactoryBot.define do ...@@ -59,6 +59,7 @@ FactoryBot.define do
end end
factory :clusters_applications_runner, class: Clusters::Applications::Runner do factory :clusters_applications_runner, class: Clusters::Applications::Runner do
runner factory: %i(ci_runner)
cluster factory: %i(cluster with_installed_helm provided_by_gcp) cluster factory: %i(cluster with_installed_helm provided_by_gcp)
end end
......
...@@ -107,6 +107,7 @@ describe('Clusters Store', () => { ...@@ -107,6 +107,7 @@ describe('Clusters Store', () => {
requestStatus: null, requestStatus: null,
requestReason: null, requestReason: null,
hostname: null, hostname: null,
externalIp: null,
}, },
cert_manager: { cert_manager: {
title: 'Cert-Manager', title: 'Cert-Manager',
......
...@@ -5,7 +5,7 @@ describe Clusters::Applications::Ingress do ...@@ -5,7 +5,7 @@ describe Clusters::Applications::Ingress do
include_examples 'cluster application core specs', :clusters_applications_ingress include_examples 'cluster application core specs', :clusters_applications_ingress
include_examples 'cluster application status specs', :clusters_applications_ingress include_examples 'cluster application status specs', :clusters_applications_ingress
include_examples 'cluster application helm specs', :clusters_applications_knative include_examples 'cluster application helm specs', :clusters_applications_ingress
before do before do
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in)
......
...@@ -2,7 +2,7 @@ require 'rails_helper' ...@@ -2,7 +2,7 @@ require 'rails_helper'
describe Clusters::Applications::Jupyter do describe Clusters::Applications::Jupyter do
include_examples 'cluster application core specs', :clusters_applications_jupyter include_examples 'cluster application core specs', :clusters_applications_jupyter
include_examples 'cluster application helm specs', :clusters_applications_knative include_examples 'cluster application helm specs', :clusters_applications_jupyter
it { is_expected.to belong_to(:oauth_application) } it { is_expected.to belong_to(:oauth_application) }
......
...@@ -7,6 +7,11 @@ describe Clusters::Applications::Knative do ...@@ -7,6 +7,11 @@ describe Clusters::Applications::Knative do
include_examples 'cluster application status specs', :clusters_applications_knative include_examples 'cluster application status specs', :clusters_applications_knative
include_examples 'cluster application helm specs', :clusters_applications_knative include_examples 'cluster application helm specs', :clusters_applications_knative
before do
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in)
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async)
end
describe '.installed' do describe '.installed' do
subject { described_class.installed } subject { described_class.installed }
...@@ -45,6 +50,48 @@ describe Clusters::Applications::Knative do ...@@ -45,6 +50,48 @@ describe Clusters::Applications::Knative do
it { is_expected.to contain_exactly(cluster) } it { is_expected.to contain_exactly(cluster) }
end end
describe 'make_installed with external_ip' do
before do
application.make_installed!
end
let(:application) { create(:clusters_applications_knative, :installing) }
it 'schedules a ClusterWaitForIngressIpAddressWorker' do
expect(ClusterWaitForIngressIpAddressWorker).to have_received(:perform_in)
.with(Clusters::Applications::Knative::FETCH_IP_ADDRESS_DELAY, 'knative', application.id)
end
end
describe '#schedule_status_update with external_ip' do
let(:application) { create(:clusters_applications_knative, :installed) }
before do
application.schedule_status_update
end
it 'schedules a ClusterWaitForIngressIpAddressWorker' do
expect(ClusterWaitForIngressIpAddressWorker).to have_received(:perform_async)
.with('knative', application.id)
end
context 'when the application is not installed' do
let(:application) { create(:clusters_applications_knative, :installing) }
it 'does not schedule a ClusterWaitForIngressIpAddressWorker' do
expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_async)
end
end
context 'when there is already an external_ip' do
let(:application) { create(:clusters_applications_knative, :installed, external_ip: '111.222.222.111') }
it 'does not schedule a ClusterWaitForIngressIpAddressWorker' do
expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in)
end
end
end
describe '#install_command' do describe '#install_command' do
subject { knative.install_command } subject { knative.install_command }
......
...@@ -5,7 +5,7 @@ describe Clusters::Applications::Prometheus do ...@@ -5,7 +5,7 @@ describe Clusters::Applications::Prometheus do
include_examples 'cluster application core specs', :clusters_applications_prometheus include_examples 'cluster application core specs', :clusters_applications_prometheus
include_examples 'cluster application status specs', :clusters_applications_prometheus include_examples 'cluster application status specs', :clusters_applications_prometheus
include_examples 'cluster application helm specs', :clusters_applications_knative include_examples 'cluster application helm specs', :clusters_applications_prometheus
describe '.installed' do describe '.installed' do
subject { described_class.installed } subject { described_class.installed }
......
...@@ -5,7 +5,7 @@ describe Clusters::Applications::Runner do ...@@ -5,7 +5,7 @@ describe Clusters::Applications::Runner do
include_examples 'cluster application core specs', :clusters_applications_runner include_examples 'cluster application core specs', :clusters_applications_runner
include_examples 'cluster application status specs', :clusters_applications_runner include_examples 'cluster application status specs', :clusters_applications_runner
include_examples 'cluster application helm specs', :clusters_applications_knative include_examples 'cluster application helm specs', :clusters_applications_runner
it { is_expected.to belong_to(:runner) } it { is_expected.to belong_to(:runner) }
...@@ -90,7 +90,7 @@ describe Clusters::Applications::Runner do ...@@ -90,7 +90,7 @@ describe Clusters::Applications::Runner do
context 'without a runner' do context 'without a runner' do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:cluster) { create(:cluster, :with_installed_helm, projects: [project]) } let(:cluster) { create(:cluster, :with_installed_helm, projects: [project]) }
let(:application) { create(:clusters_applications_runner, cluster: cluster) } let(:application) { create(:clusters_applications_runner, runner: nil, cluster: cluster) }
it 'creates a runner' do it 'creates a runner' do
expect do expect do
......
...@@ -28,41 +28,7 @@ describe Clusters::Applications::CheckIngressIpAddressService do ...@@ -28,41 +28,7 @@ describe Clusters::Applications::CheckIngressIpAddressService do
allow(application.cluster).to receive(:kubeclient).and_return(kubeclient) allow(application.cluster).to receive(:kubeclient).and_return(kubeclient)
end end
describe '#execute' do include_examples 'check ingress ip executions', :clusters_applications_ingress
context 'when the ingress ip address is available' do
it 'updates the external_ip for the app' do
subject
expect(application.external_ip).to eq('111.222.111.222') include_examples 'check ingress ip executions', :clusters_applications_knative
end
end
context 'when the ingress ip address is not available' do
let(:ingress) { nil }
it 'does not error' do
subject
end
end
context 'when the exclusive lease cannot be obtained' do
it 'does not call kubeclient' do
stub_exclusive_lease_taken(lease_key, timeout: 15.seconds.to_i)
subject
expect(kubeclient).not_to have_received(:get_service)
end
end
context 'when there is already an external_ip' do
let(:application) { create(:clusters_applications_ingress, :installed, external_ip: '001.111.002.111') }
it 'does not call kubeclient' do
subject
expect(kubeclient).not_to have_received(:get_service)
end
end
end
end end
shared_examples 'check ingress ip executions' do |app_name|
describe '#execute' do
let(:application) { create(app_name, :installed) }
let(:service) { described_class.new(application) }
let(:kubeclient) { double(::Kubeclient::Client, get_service: kube_service) }
context 'when the ingress ip address is available' do
it 'updates the external_ip for the app' do
subject
expect(application.external_ip).to eq('111.222.111.222')
end
end
context 'when the ingress ip address is not available' do
let(:ingress) { nil }
it 'does not error' do
subject
end
end
context 'when the exclusive lease cannot be obtained' do
it 'does not call kubeclient' do
stub_exclusive_lease_taken(lease_key, timeout: 15.seconds.to_i)
subject
expect(kubeclient).not_to have_received(:get_service)
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