diff options
18 files changed, 191 insertions, 52 deletions
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index 8354c28778c..34c510cb468 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -168,6 +168,9 @@ export default { knativeInstalled() { return this.applications.knative.status === APPLICATION_STATUS.INSTALLED; }, + knativeExternalIp() { + return this.applications.knative.externalIp; + }, }, created() { this.helmInstallIllustration = helmInstallIllustration; @@ -444,6 +447,49 @@ export default { /> </div> </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> </application-row> </div> diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js index 3678be59d24..2d69da8eaec 100644 --- a/app/assets/javascripts/clusters/stores/clusters_store.js +++ b/app/assets/javascripts/clusters/stores/clusters_store.js @@ -60,6 +60,7 @@ export default class ClusterStore { requestStatus: null, requestReason: null, hostname: null, + externalIp: null, }, }, }; @@ -111,6 +112,8 @@ export default class ClusterStore { } else if (appId === KNATIVE) { 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; } }); } diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb index bd0286ee3f9..8f8790585a3 100644 --- a/app/models/clusters/applications/ingress.rb +++ b/app/models/clusters/applications/ingress.rb @@ -51,6 +51,10 @@ module Clusters ClusterWaitForIngressIpAddressWorker.perform_async(name, id) end + + def ingress_service + cluster.kubeclient.get_service('ingress-nginx-ingress-controller', Gitlab::Kubernetes::Helm::NAMESPACE) + end end end end diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb index c66d5ce54db..c0aaa8dce20 100644 --- a/app/models/clusters/applications/knative.rb +++ b/app/models/clusters/applications/knative.rb @@ -6,9 +6,7 @@ module Clusters VERSION = '0.1.3'.freeze REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze - # This is required for helm version <= 2.10.x in order to support - # Setting up CRDs - ISTIO_CRDS = 'https://storage.googleapis.com/triggermesh-charts/istio-crds.yaml'.freeze + FETCH_IP_ADDRESS_DELAY = 30.seconds self.table_name = 'clusters_applications_knative' @@ -16,6 +14,16 @@ module Clusters include ::Clusters::Concerns::ApplicationStatus include ::Clusters::Concerns::ApplicationVersion 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 @@ -36,19 +44,23 @@ module Clusters rbac: cluster.platform_kubernetes_rbac?, chart: chart, files: files, - repository: REPOSITORY, - preinstall: install_script + repository: REPOSITORY ) end - def client - cluster.platform_kubernetes.kubeclient.knative_client + def schedule_status_update + return unless installed? + return if external_ip + + ClusterWaitForIngressIpAddressWorker.perform_async(name, id) end - private + def ingress_service + cluster.kubeclient.get_service('knative-ingressgateway', 'istio-system') + end - def install_script - ["/usr/bin/kubectl apply -f #{ISTIO_CRDS}"] + def client + cluster.platform_kubernetes.kubeclient.knative_client end end end diff --git a/app/services/clusters/applications/check_ingress_ip_address_service.rb b/app/services/clusters/applications/check_ingress_ip_address_service.rb index f32e73e8b1c..0ec06e776a7 100644 --- a/app/services/clusters/applications/check_ingress_ip_address_service.rb +++ b/app/services/clusters/applications/check_ingress_ip_address_service.rb @@ -30,7 +30,7 @@ module Clusters def service strong_memoize(:ingress_service) do - kubeclient.get_service('ingress-nginx-ingress-controller', Gitlab::Kubernetes::Helm::NAMESPACE) + app.ingress_service end end end diff --git a/changelogs/unreleased/triggermesh-phase2-external-ip.yml b/changelogs/unreleased/triggermesh-phase2-external-ip.yml new file mode 100644 index 00000000000..582c8f6df2e --- /dev/null +++ b/changelogs/unreleased/triggermesh-phase2-external-ip.yml @@ -0,0 +1,5 @@ +--- +title: Add an external IP address to the knative cluster application page +merge_request: +author: Chris Baumbauer +type: fixed diff --git a/db/migrate/20181116050532_knative_external_ip.rb b/db/migrate/20181116050532_knative_external_ip.rb new file mode 100644 index 00000000000..f1f903fb692 --- /dev/null +++ b/db/migrate/20181116050532_knative_external_ip.rb @@ -0,0 +1,14 @@ +# 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 diff --git a/db/schema.rb b/db/schema.rb index acabd7b442b..b3ae6cc0f14 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -698,6 +698,7 @@ ActiveRecord::Schema.define(version: 20181126150622) do t.string "version", null: false t.string "hostname" t.text "status_reason" + t.string "external_ip" t.index ["cluster_id"], name: "index_clusters_applications_knative_on_cluster_id", unique: true, using: :btree end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 71374388a7d..8fe767021a5 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1454,6 +1454,9 @@ msgstr "" msgid "ClusterIntegration|Copy Jupyter Hostname to clipboard" msgstr "" +msgid "ClusterIntegration|Copy Knative IP Address to clipboard" +msgstr "" + msgid "ClusterIntegration|Copy Kubernetes cluster name" msgstr "" @@ -1559,6 +1562,9 @@ msgstr "" msgid "ClusterIntegration|Knative Domain Name:" msgstr "" +msgid "ClusterIntegration|Knative IP Address:" +msgstr "" + msgid "ClusterIntegration|Kubernetes cluster" msgstr "" diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb index 7fc3d16e864..fe56ac5b71d 100644 --- a/spec/factories/clusters/applications/helm.rb +++ b/spec/factories/clusters/applications/helm.rb @@ -59,6 +59,7 @@ FactoryBot.define do end factory :clusters_applications_runner, class: Clusters::Applications::Runner do + runner factory: %i(ci_runner) cluster factory: %i(cluster with_installed_helm provided_by_gcp) end diff --git a/spec/javascripts/clusters/stores/clusters_store_spec.js b/spec/javascripts/clusters/stores/clusters_store_spec.js index 6a08d08f33e..7ea0878ad45 100644 --- a/spec/javascripts/clusters/stores/clusters_store_spec.js +++ b/spec/javascripts/clusters/stores/clusters_store_spec.js @@ -107,6 +107,7 @@ describe('Clusters Store', () => { requestStatus: null, requestReason: null, hostname: null, + externalIp: null, }, cert_manager: { title: 'Cert-Manager', diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb index 6b0b23eeab3..cfe0e216c78 100644 --- a/spec/models/clusters/applications/ingress_spec.rb +++ b/spec/models/clusters/applications/ingress_spec.rb @@ -5,7 +5,7 @@ describe Clusters::Applications::Ingress do include_examples 'cluster application core 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 allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb index faaabafddb7..a40edbf267b 100644 --- a/spec/models/clusters/applications/jupyter_spec.rb +++ b/spec/models/clusters/applications/jupyter_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' describe Clusters::Applications::Jupyter do 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) } diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb index be2a91d566b..d43d88c2924 100644 --- a/spec/models/clusters/applications/knative_spec.rb +++ b/spec/models/clusters/applications/knative_spec.rb @@ -7,6 +7,11 @@ describe Clusters::Applications::Knative do include_examples 'cluster application status 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 subject { described_class.installed } @@ -45,6 +50,48 @@ describe Clusters::Applications::Knative do it { is_expected.to contain_exactly(cluster) } 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 subject { knative.install_command } diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb index b5aa1dcece5..893ed3e3f64 100644 --- a/spec/models/clusters/applications/prometheus_spec.rb +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -5,7 +5,7 @@ describe Clusters::Applications::Prometheus do include_examples 'cluster application core 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 subject { described_class.installed } diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb index a8b28a335d6..97e50809647 100644 --- a/spec/models/clusters/applications/runner_spec.rb +++ b/spec/models/clusters/applications/runner_spec.rb @@ -5,7 +5,7 @@ describe Clusters::Applications::Runner do include_examples 'cluster application core 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) } @@ -90,7 +90,7 @@ describe Clusters::Applications::Runner do context 'without a runner' do let(:project) { create(: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 expect do diff --git a/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb b/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb index eb0bdb61ee3..f3036fbcb0e 100644 --- a/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb +++ b/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb @@ -28,41 +28,7 @@ describe Clusters::Applications::CheckIngressIpAddressService do allow(application.cluster).to receive(:kubeclient).and_return(kubeclient) end - describe '#execute' do - context 'when the ingress ip address is available' do - it 'updates the external_ip for the app' do - subject + include_examples 'check ingress ip executions', :clusters_applications_ingress - 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 - - 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 + include_examples 'check ingress ip executions', :clusters_applications_knative end diff --git a/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb b/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb new file mode 100644 index 00000000000..14638a574a5 --- /dev/null +++ b/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb @@ -0,0 +1,33 @@ +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 |