Commit 5596eed1 authored by Mike Greiling's avatar Mike Greiling

Merge branch 'ingress-hostnames' into 'master'

Add support for ingress hostnames

Closes #58244, #56158, and #46691

See merge request gitlab-org/gitlab-ce!25181
parents 87e1b2bb 460797de
...@@ -89,53 +89,26 @@ export default { ...@@ -89,53 +89,26 @@ export default {
ingressInstalled() { ingressInstalled() {
return this.applications.ingress.status === APPLICATION_STATUS.INSTALLED; return this.applications.ingress.status === APPLICATION_STATUS.INSTALLED;
}, },
ingressExternalIp() { ingressExternalEndpoint() {
return this.applications.ingress.externalIp; return this.applications.ingress.externalIp || this.applications.ingress.externalHostname;
}, },
certManagerInstalled() { certManagerInstalled() {
return this.applications.cert_manager.status === APPLICATION_STATUS.INSTALLED; return this.applications.cert_manager.status === APPLICATION_STATUS.INSTALLED;
}, },
ingressDescription() { ingressDescription() {
const extraCostParagraph = sprintf( return sprintf(
_.escape(
s__(
`ClusterIntegration|%{boldNotice} This will add some extra resources
like a load balancer, which may incur additional costs depending on
the hosting provider your Kubernetes cluster is installed on. If you are using
Google Kubernetes Engine, you can %{pricingLink}.`,
),
),
{
boldNotice: `<strong>${_.escape(s__('ClusterIntegration|Note:'))}</strong>`,
pricingLink: `<a href="https://cloud.google.com/compute/pricing#lb" target="_blank" rel="noopener noreferrer">
${_.escape(s__('ClusterIntegration|check the pricing here'))}</a>`,
},
false,
);
const externalIpParagraph = sprintf(
_.escape( _.escape(
s__( s__(
`ClusterIntegration|After installing Ingress, you will need to point your wildcard DNS `ClusterIntegration|Installing Ingress may incur additional costs. Learn more about %{pricingLink}.`,
at the generated external IP address in order to view your app after it is deployed. %{ingressHelpLink}`,
), ),
), ),
{ {
ingressHelpLink: `<a href="${this.ingressHelpPath}"> pricingLink: `<strong><a href="https://cloud.google.com/compute/pricing#lb"
${_.escape(s__('ClusterIntegration|More information'))} target="_blank" rel="noopener noreferrer">
</a>`, ${_.escape(s__('ClusterIntegration|pricing'))}</a></strong>`,
}, },
false, false,
); );
return `
<p>
${extraCostParagraph}
</p>
<p class="settings-message append-bottom-0">
${externalIpParagraph}
</p>
`;
}, },
certManagerDescription() { certManagerDescription() {
return sprintf( return sprintf(
...@@ -196,11 +169,26 @@ export default { ...@@ -196,11 +169,26 @@ export default {
knativeUpgradeFailed() { knativeUpgradeFailed() {
return this.knative.status === APPLICATION_STATUS.UPDATE_ERRORED; return this.knative.status === APPLICATION_STATUS.UPDATE_ERRORED;
}, },
knativeExternalIp() { knativeExternalEndpoint() {
return this.knative.externalIp; return this.knative.externalIp || this.knative.externalHostname;
},
knativeDescription() {
return sprintf(
_.escape(
s__(
`ClusterIntegration|Installing Knative may incur additional costs. Learn more about %{pricingLink}.`,
),
),
{
pricingLink: `<strong><a href="https://cloud.google.com/compute/pricing#lb"
target="_blank" rel="noopener noreferrer">
${_.escape(s__('ClusterIntegration|pricing'))}</a></strong>`,
},
false,
);
}, },
canUpdateKnativeEndpoint() { canUpdateKnativeEndpoint() {
return this.knativeExternalIp && !this.knativeUpgradeFailed && !this.knativeUpgrading; return this.knativeExternalEndpoint && !this.knativeUpgradeFailed && !this.knativeUpgrading;
}, },
knativeHostname: { knativeHostname: {
get() { get() {
...@@ -289,30 +277,30 @@ export default { ...@@ -289,30 +277,30 @@ export default {
<template v-if="ingressInstalled"> <template v-if="ingressInstalled">
<div class="form-group"> <div class="form-group">
<label for="ingress-ip-address"> <label for="ingress-endpoint">
{{ s__('ClusterIntegration|Ingress IP Address') }} {{ s__('ClusterIntegration|Ingress Endpoint') }}
</label> </label>
<div v-if="ingressExternalIp" class="input-group"> <div v-if="ingressExternalEndpoint" class="input-group">
<input <input
id="ingress-ip-address" id="ingress-endpoint"
:value="ingressExternalIp" :value="ingressExternalEndpoint"
type="text" type="text"
class="form-control js-ip-address" class="form-control js-endpoint"
readonly readonly
/> />
<span class="input-group-append"> <span class="input-group-append">
<clipboard-button <clipboard-button
:text="ingressExternalIp" :text="ingressExternalEndpoint"
:title="s__('ClusterIntegration|Copy Ingress IP Address to clipboard')" :title="s__('ClusterIntegration|Copy Ingress Endpoint to clipboard')"
class="input-group-text js-clipboard-btn" class="input-group-text js-clipboard-btn"
/> />
</span> </span>
</div> </div>
<input v-else type="text" class="form-control js-ip-address" readonly value="?" /> <input v-else type="text" class="form-control js-endpoint" readonly value="?" />
<p class="form-text text-muted"> <p class="form-text text-muted">
{{ {{
s__(`ClusterIntegration|Point a wildcard DNS to this s__(`ClusterIntegration|Point a wildcard DNS to this
generated IP address in order to access generated endpoint in order to access
your application after it has been deployed.`) your application after it has been deployed.`)
}} }}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
...@@ -321,19 +309,21 @@ export default { ...@@ -321,19 +309,21 @@ export default {
</p> </p>
</div> </div>
<p v-if="!ingressExternalIp" class="settings-message js-no-ip-message"> <p v-if="!ingressExternalEndpoint" class="settings-message js-no-endpoint-message">
{{ {{
s__(`ClusterIntegration|The IP address is in s__(`ClusterIntegration|The endpoint is in
the process of being assigned. Please check your Kubernetes the process of being assigned. Please check your Kubernetes
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
}} }}
<a :href="ingressHelpPath" target="_blank" rel="noopener noreferrer"> <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }} {{ __('More information') }}
</a> </a>
</p> </p>
</template> </template>
<div v-html="ingressDescription"></div> <template v-if="!ingressInstalled">
<div class="bs-callout bs-callout-info" v-html="ingressDescription"></div>
</template>
</div> </div>
</application-row> </application-row>
<application-row <application-row
...@@ -443,7 +433,7 @@ export default { ...@@ -443,7 +433,7 @@ export default {
}} }}
</p> </p>
<template v-if="ingressExternalIp"> <template v-if="ingressExternalEndpoint">
<div class="form-group"> <div class="form-group">
<label for="jupyter-hostname"> <label for="jupyter-hostname">
{{ s__('ClusterIntegration|Jupyter Hostname') }} {{ s__('ClusterIntegration|Jupyter Hostname') }}
...@@ -493,7 +483,7 @@ export default { ...@@ -493,7 +483,7 @@ export default {
> >
<div slot="description"> <div slot="description">
<span v-if="!rbac"> <span v-if="!rbac">
<p v-if="!rbac" class="bs-callout bs-callout-info append-bottom-0"> <p v-if="!rbac" class="rbac-notice bs-callout bs-callout-info append-bottom-0">
{{ {{
s__(`ClusterIntegration|You must have an RBAC-enabled cluster s__(`ClusterIntegration|You must have an RBAC-enabled cluster
to install Knative.`) to install Knative.`)
...@@ -534,31 +524,31 @@ export default { ...@@ -534,31 +524,31 @@ export default {
</template> </template>
<template v-if="knativeInstalled"> <template v-if="knativeInstalled">
<div class="form-group col-sm-12 col-md-6 pl-md-0 mb-0 mt-3 mt-md-0"> <div class="form-group col-sm-12 col-md-6 pl-md-0 mb-0 mt-3 mt-md-0">
<label for="knative-ip-address"> <label for="knative-endpoint">
<strong> <strong>
{{ s__('ClusterIntegration|Knative Endpoint:') }} {{ s__('ClusterIntegration|Knative Endpoint:') }}
</strong> </strong>
</label> </label>
<div v-if="knativeExternalIp" class="input-group"> <div v-if="knativeExternalEndpoint" class="input-group">
<input <input
id="knative-ip-address" id="knative-endpoint"
:value="knativeExternalIp" :value="knativeExternalEndpoint"
type="text" type="text"
class="form-control js-knative-ip-address" class="form-control js-knative-endpoint"
readonly readonly
/> />
<span class="input-group-append"> <span class="input-group-append">
<clipboard-button <clipboard-button
:text="knativeExternalIp" :text="knativeExternalEndpoint"
:title="s__('ClusterIntegration|Copy Knative Endpoint to clipboard')" :title="s__('ClusterIntegration|Copy Knative Endpoint to clipboard')"
class="input-group-text js-knative-ip-clipboard-btn" class="input-group-text js-knative-endpoint-clipboard-btn"
/> />
</span> </span>
</div> </div>
<input <input
v-else v-else
type="text" type="text"
class="form-control js-knative-ip-address" class="form-control js-knative-endpoint"
readonly readonly
value="?" value="?"
/> />
...@@ -576,11 +566,11 @@ export default { ...@@ -576,11 +566,11 @@ export default {
</p> </p>
<p <p
v-if="!knativeExternalIp" v-if="!knativeExternalEndpoint"
class="settings-message js-no-knative-ip-message mt-2 mr-3 mb-0 ml-3 " class="settings-message js-no-knative-endpoint-message mt-2 mr-3 mb-0 ml-3"
> >
{{ {{
s__(`ClusterIntegration|The IP address is in s__(`ClusterIntegration|The endpoint is in
the process of being assigned. Please check your Kubernetes the process of being assigned. Please check your Kubernetes
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
}} }}
......
...@@ -25,6 +25,7 @@ export default class ClusterStore { ...@@ -25,6 +25,7 @@ export default class ClusterStore {
requestStatus: null, requestStatus: null,
requestReason: null, requestReason: null,
externalIp: null, externalIp: null,
externalHostname: null,
}, },
cert_manager: { cert_manager: {
title: s__('ClusterIntegration|Cert-Manager'), title: s__('ClusterIntegration|Cert-Manager'),
...@@ -68,6 +69,7 @@ export default class ClusterStore { ...@@ -68,6 +69,7 @@ export default class ClusterStore {
hostname: null, hostname: null,
isEditingHostName: false, isEditingHostName: false,
externalIp: null, externalIp: null,
externalHostname: null,
}, },
}, },
}; };
...@@ -120,6 +122,7 @@ export default class ClusterStore { ...@@ -120,6 +122,7 @@ export default class ClusterStore {
if (appId === INGRESS) { if (appId === INGRESS) {
this.state.applications.ingress.externalIp = serverAppEntry.external_ip; this.state.applications.ingress.externalIp = serverAppEntry.external_ip;
this.state.applications.ingress.externalHostname = serverAppEntry.external_hostname;
} else if (appId === CERT_MANAGER) { } else if (appId === CERT_MANAGER) {
this.state.applications.cert_manager.email = this.state.applications.cert_manager.email =
this.state.applications.cert_manager.email || serverAppEntry.email; this.state.applications.cert_manager.email || serverAppEntry.email;
...@@ -136,6 +139,8 @@ export default class ClusterStore { ...@@ -136,6 +139,8 @@ export default class ClusterStore {
} }
this.state.applications.knative.externalIp = this.state.applications.knative.externalIp =
serverAppEntry.external_ip || this.state.applications.knative.externalIp; serverAppEntry.external_ip || this.state.applications.knative.externalIp;
this.state.applications.knative.externalHostname =
serverAppEntry.external_hostname || this.state.applications.knative.externalHostname;
} else if (appId === RUNNER) { } else if (appId === RUNNER) {
this.state.applications.runner.version = version; this.state.applications.runner.version = version;
this.state.applications.runner.upgradeAvailable = upgradeAvailable; this.state.applications.runner.upgradeAvailable = upgradeAvailable;
......
...@@ -48,6 +48,7 @@ module Clusters ...@@ -48,6 +48,7 @@ module Clusters
def schedule_status_update def schedule_status_update
return unless installed? return unless installed?
return if external_ip return if external_ip
return if external_hostname
ClusterWaitForIngressIpAddressWorker.perform_async(name, id) ClusterWaitForIngressIpAddressWorker.perform_async(name, id)
end end
......
...@@ -18,8 +18,10 @@ module Clusters ...@@ -18,8 +18,10 @@ module Clusters
def set_initial_status def set_initial_status
return unless not_installable? return unless not_installable?
return unless cluster&.application_ingress_available?
if cluster&.application_ingress_available? && cluster.application_ingress.external_ip ingress = cluster.application_ingress
if ingress.external_ip || ingress.external_hostname
self.status = 'installable' self.status = 'installable'
end end
end end
......
...@@ -66,6 +66,7 @@ module Clusters ...@@ -66,6 +66,7 @@ module Clusters
def schedule_status_update def schedule_status_update
return unless installed? return unless installed?
return if external_ip return if external_ip
return if external_hostname
ClusterWaitForIngressIpAddressWorker.perform_async(name, id) ClusterWaitForIngressIpAddressWorker.perform_async(name, id)
end end
......
...@@ -67,6 +67,7 @@ module Clusters ...@@ -67,6 +67,7 @@ module Clusters
delegate :available?, to: :application_prometheus, prefix: true, allow_nil: true delegate :available?, to: :application_prometheus, prefix: true, allow_nil: true
delegate :available?, to: :application_knative, prefix: true, allow_nil: true delegate :available?, to: :application_knative, prefix: true, allow_nil: true
delegate :external_ip, to: :application_ingress, prefix: true, allow_nil: true delegate :external_ip, to: :application_ingress, prefix: true, allow_nil: true
delegate :external_hostname, to: :application_ingress, prefix: true, allow_nil: true
alias_attribute :base_domain, :domain alias_attribute :base_domain, :domain
......
...@@ -6,6 +6,7 @@ class ClusterApplicationEntity < Grape::Entity ...@@ -6,6 +6,7 @@ class ClusterApplicationEntity < Grape::Entity
expose :status_reason expose :status_reason
expose :version expose :version
expose :external_ip, if: -> (e, _) { e.respond_to?(:external_ip) } expose :external_ip, if: -> (e, _) { e.respond_to?(:external_ip) }
expose :external_hostname, if: -> (e, _) { e.respond_to?(:external_hostname) }
expose :hostname, if: -> (e, _) { e.respond_to?(:hostname) } expose :hostname, if: -> (e, _) { e.respond_to?(:hostname) }
expose :email, if: -> (e, _) { e.respond_to?(:email) } expose :email, if: -> (e, _) { e.respond_to?(:email) }
expose :update_available?, as: :update_available, if: -> (e, _) { e.respond_to?(:update_available?) } expose :update_available?, as: :update_available, if: -> (e, _) { e.respond_to?(:update_available?) }
......
...@@ -11,9 +11,13 @@ module Clusters ...@@ -11,9 +11,13 @@ module Clusters
def execute def execute
return if app.external_ip return if app.external_ip
return if app.external_hostname
return unless try_obtain_lease return unless try_obtain_lease
app.update!(external_ip: ingress_ip) if ingress_ip app.external_ip = ingress_ip if ingress_ip
app.external_hostname = ingress_hostname if ingress_hostname
app.save! if app.changed?
end end
private private
...@@ -25,12 +29,16 @@ module Clusters ...@@ -25,12 +29,16 @@ module Clusters
end end
def ingress_ip def ingress_ip
service.status.loadBalancer.ingress&.first&.ip ingress_service&.ip
end
def ingress_hostname
ingress_service&.hostname
end end
def service def ingress_service
strong_memoize(:ingress_service) do strong_memoize(:ingress_service) do
app.ingress_service app.ingress_service.status.loadBalancer.ingress&.first
end end
end end
end end
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
= s_('ClusterIntegration|Alternatively') = s_('ClusterIntegration|Alternatively')
%code #{@cluster.application_ingress_external_ip}.nip.io %code #{@cluster.application_ingress_external_ip}.nip.io
= s_('ClusterIntegration| can be used instead of a custom domain.') = s_('ClusterIntegration| can be used instead of a custom domain.')
- custom_domain_url = help_page_path('user/project/clusters/index', anchor: 'pointing-your-dns-at-the-cluster-ip') - custom_domain_url = help_page_path('user/project/clusters/index', anchor: 'pointing-your-dns-at-the-external-endpoint')
- custom_domain_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: custom_domain_url } - custom_domain_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: custom_domain_url }
= s_('ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}.').html_safe % { custom_domain_start: custom_domain_start, custom_domain_end: '</a>'.html_safe } = s_('ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}.').html_safe % { custom_domain_start: custom_domain_start, custom_domain_end: '</a>'.html_safe }
......
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
cluster_status: @cluster.status_name, cluster_status: @cluster.status_name,
cluster_status_reason: @cluster.status_reason, cluster_status_reason: @cluster.status_reason,
help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications'), help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications'),
ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-ip-address'), ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-endpoint'),
ingress_dns_help_path: help_page_path('topics/autodevops/quick_start_guide.md', anchor: 'point-dns-at-cluster-ip'), ingress_dns_help_path: help_page_path('user/project/clusters/index.md', anchor: 'manually-determining-the-external-endpoint'),
manage_prometheus_path: manage_prometheus_path } } manage_prometheus_path: manage_prometheus_path } }
.js-cluster-application-notice .js-cluster-application-notice
......
---
title: Added support for ingress hostnames
merge_request: 25181
author: walkafwalka
type: added
# frozen_string_literal: true
class AddExternalHostnameToIngressAndKnative < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
add_column :clusters_applications_ingress, :external_hostname, :string
add_column :clusters_applications_knative, :external_hostname, :string
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20190301081611) do ActiveRecord::Schema.define(version: 20190301182457) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -708,6 +708,7 @@ ActiveRecord::Schema.define(version: 20190301081611) do ...@@ -708,6 +708,7 @@ ActiveRecord::Schema.define(version: 20190301081611) do
t.string "cluster_ip" t.string "cluster_ip"
t.text "status_reason" t.text "status_reason"
t.string "external_ip" t.string "external_ip"
t.string "external_hostname"
t.index ["cluster_id"], name: "index_clusters_applications_ingress_on_cluster_id", unique: true, using: :btree t.index ["cluster_id"], name: "index_clusters_applications_ingress_on_cluster_id", unique: true, using: :btree
end end
...@@ -733,6 +734,7 @@ ActiveRecord::Schema.define(version: 20190301081611) do ...@@ -733,6 +734,7 @@ ActiveRecord::Schema.define(version: 20190301081611) do
t.string "hostname" t.string "hostname"
t.text "status_reason" t.text "status_reason"
t.string "external_ip" t.string "external_ip"
t.string "external_hostname"
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
......
...@@ -387,27 +387,27 @@ Upgrades will reset values back to the values built into the `runner` ...@@ -387,27 +387,27 @@ Upgrades will reset values back to the values built into the `runner`
chart plus the values set by chart plus the values set by
[`values.yaml`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/vendor/runner/values.yaml) [`values.yaml`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/vendor/runner/values.yaml)
## Getting the external IP address ## Getting the external endpoint
NOTE: **Note:** NOTE: **Note:**
With the following procedure, a load balancer must be installed in your cluster With the following procedure, a load balancer must be installed in your cluster
to obtain the external IP address. You can use either to obtain the endpoint. You can use either
[Ingress](#installing-applications), or Knative's own load balancer [Ingress](#installing-applications), or Knative's own load balancer
([Istio](https://istio.io)) if using [Knative](#installing-applications). ([Istio](https://istio.io)) if using [Knative](#installing-applications).
In order to publish your web application, you first need to find the external IP In order to publish your web application, you first need to find the endpoint which will be either an IP
address associated to your load balancer. address or a hostname associated with your load balancer.
### Let GitLab fetch the IP address ### Let GitLab fetch the external endpoint
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17052) in GitLab 10.6. > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17052) in GitLab 10.6.
If you [installed Ingress or Knative](#installing-applications), If you [installed Ingress or Knative](#installing-applications),
you should see the Ingress IP address on this same page within a few minutes. you should see the Ingress Endpoint on this same page within a few minutes.
If you don't see this, GitLab might not be able to determine the IP address of If you don't see this, GitLab might not be able to determine the external endpoint of
your ingress application in which case you should manually determine it. your ingress application in which case you should manually determine it.
### Manually determining the IP address ### Manually determining the external endpoint
If the cluster is on GKE, click the **Google Kubernetes Engine** link in the If the cluster is on GKE, click the **Google Kubernetes Engine** link in the
**Advanced settings**, or go directly to the **Advanced settings**, or go directly to the
...@@ -417,7 +417,7 @@ the `gcloud` command in a local terminal or using the **Cloud Shell**. ...@@ -417,7 +417,7 @@ the `gcloud` command in a local terminal or using the **Cloud Shell**.
If the cluster is not on GKE, follow the specific instructions for your If the cluster is not on GKE, follow the specific instructions for your
Kubernetes provider to configure `kubectl` with the right credentials. Kubernetes provider to configure `kubectl` with the right credentials.
The output of the following examples will show the external IP address of your The output of the following examples will show the external endpoint of your
cluster. This information can then be used to set up DNS entries and forwarding cluster. This information can then be used to set up DNS entries and forwarding
rules that allow external access to your deployed applications. rules that allow external access to your deployed applications.
...@@ -425,19 +425,19 @@ If you installed the Ingress [via the **Applications**](#installing-applications ...@@ -425,19 +425,19 @@ If you installed the Ingress [via the **Applications**](#installing-applications
run the following command: run the following command:
```bash ```bash
kubectl get svc --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip} ' kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
``` ```
For Istio/Knative, the command will be different: Some Kubernetes clusters return a hostname instead, like [Amazon EKS](https://aws.amazon.com/eks/). For these platforms, run:
```bash ```bash
kubectl get svc --namespace=istio-system knative-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} ' kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
``` ```
Some Kubernetes clusters return a hostname instead, like [Amazon EKS](https://aws.amazon.com/eks/). For these platforms, run: For Istio/Knative, the command will be different:
```bash ```bash
kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -o jsonpath="{.status.loadBalancer.ingress[0].hostname}". kubectl get svc --namespace=istio-system knative-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} '
``` ```
Otherwise, you can list the IP addresses of all load balancers: Otherwise, you can list the IP addresses of all load balancers:
...@@ -456,13 +456,12 @@ reserved IP. ...@@ -456,13 +456,12 @@ reserved IP.
Read how to [promote an ephemeral external IP address in GKE](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip). Read how to [promote an ephemeral external IP address in GKE](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip).
### Pointing your DNS at the cluster IP ### Pointing your DNS at the external endpoint
Once you've set up the static IP, you should associate it to a [wildcard DNS Once you've set up the external endpoint, you should associate it with a [wildcard DNS
record](https://en.wikipedia.org/wiki/Wildcard_DNS_record), in order to be able record](https://en.wikipedia.org/wiki/Wildcard_DNS_record) such as `*.example.com.`
to reach your apps. This heavily depends on your domain provider, but in case in order to be able to reach your apps. If your external endpoint is an IP address,
you aren't sure, just create an A record with a wildcard host like use an A record. If your external endpoint is a hostname, use a CNAME record.
`*.example.com.`.
## Multiple Kubernetes clusters **[PREMIUM]** ## Multiple Kubernetes clusters **[PREMIUM]**
......
...@@ -37,9 +37,9 @@ To run Knative on Gitlab, you will need: ...@@ -37,9 +37,9 @@ To run Knative on Gitlab, you will need:
applications or functions onto your cluster. You can install the GitLab Runner applications or functions onto your cluster. You can install the GitLab Runner
onto the existing Kubernetes cluster. See [Installing Applications](../index.md#installing-applications) for more information. onto the existing Kubernetes cluster. See [Installing Applications](../index.md#installing-applications) for more information.
1. **Domain Name:** Knative will provide its own load balancer using Istio. It will provide an 1. **Domain Name:** Knative will provide its own load balancer using Istio. It will provide an
external IP address for all the applications served by Knative. You will be prompted to enter a external IP address or hostname for all the applications served by Knative. You will be prompted to enter a
wildcard domain where your applications will be served. Configure your DNS server to use the wildcard domain where your applications will be served. Configure your DNS server to use the
external IP address for that domain. external IP address or hostname for that domain.
1. **`.gitlab-ci.yml`:** GitLab uses [Kaniko](https://github.com/GoogleContainerTools/kaniko) 1. **`.gitlab-ci.yml`:** GitLab uses [Kaniko](https://github.com/GoogleContainerTools/kaniko)
to build the application and the [TriggerMesh CLI](https://github.com/triggermesh/tm) to simplify the to build the application and the [TriggerMesh CLI](https://github.com/triggermesh/tm) to simplify the
deployment of knative services and functions. deployment of knative services and functions.
...@@ -62,18 +62,8 @@ The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22. ...@@ -62,18 +62,8 @@ The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22.
![install-knative](img/install-knative.png) ![install-knative](img/install-knative.png)
1. After the Knative installation has finished, you can wait for the IP address to be displayed in the 1. After the Knative installation has finished, you can wait for the IP address or hostname to be displayed in the
**Knative IP Address** field (takes up to 5 minutes) or retrieve the Istio Ingress IP address by running the following command: **Knative Endpoint** field or [retrieve the Istio Ingress Endpoint manually](../#manually-determining-the-external-endpoint).
```bash
kubectl get svc --namespace=istio-system knative-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} '
```
Output:
```bash
35.161.143.124 my-machine-name:~ my-user$
```
NOTE: **Note:** NOTE: **Note:**
Running `kubectl` commands on your cluster requires setting up access to the cluster first. Running `kubectl` commands on your cluster requires setting up access to the cluster first.
...@@ -82,8 +72,8 @@ The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22. ...@@ -82,8 +72,8 @@ The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22.
1. The ingress is now available at this address and will route incoming requests to the proper service based on the DNS 1. The ingress is now available at this address and will route incoming requests to the proper service based on the DNS
name in the request. To support this, a wildcard DNS A record should be created for the desired domain name. For example, name in the request. To support this, a wildcard DNS A record should be created for the desired domain name. For example,
if your Knative base domain is `example.com` then you need to create an A record with domain `*.example.com` if your Knative base domain is `knative.info` then you need to create an A record or CNAME record with domain `*.knative.info`
pointing the ip address of the ingress. pointing the ip address or hostname of the ingress.
![dns entry](img/dns-entry.png) ![dns entry](img/dns-entry.png)
......
...@@ -30,7 +30,7 @@ For other deployments, there is [some configuration](#manually-setting-up-nginx- ...@@ -30,7 +30,7 @@ For other deployments, there is [some configuration](#manually-setting-up-nginx-
### About managed NGINX Ingress deployments ### About managed NGINX Ingress deployments
NGINX Ingress is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/kubernetes/charts/tree/master/stable/nginx-ingress). NGINX Ingress will be [externally reachable via the Load Balancer's IP](../../clusters/index.md#getting-the-external-ip-address). NGINX Ingress is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/kubernetes/charts/tree/master/stable/nginx-ingress). NGINX Ingress will be [externally reachable via the Load Balancer's Endpoint](../../clusters/index.md#getting-the-external-endpoint).
NGINX is configured for Prometheus monitoring, by setting: NGINX is configured for Prometheus monitoring, by setting:
......
...@@ -30,7 +30,7 @@ For other deployments, there is [some configuration](#manually-setting-up-nginx- ...@@ -30,7 +30,7 @@ For other deployments, there is [some configuration](#manually-setting-up-nginx-
### About managed NGINX Ingress deployments ### About managed NGINX Ingress deployments
NGINX Ingress is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/kubernetes/charts/tree/master/stable/nginx-ingress). NGINX Ingress will be [externally reachable via the Load Balancer's IP](../../clusters/index.md#getting-the-external-ip-address). NGINX Ingress is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/kubernetes/charts/tree/master/stable/nginx-ingress). NGINX Ingress will be [externally reachable via the Load Balancer's Endpoint](../../clusters/index.md#getting-the-external-endpoint).
NGINX is configured for Prometheus monitoring, by setting: NGINX is configured for Prometheus monitoring, by setting:
......
...@@ -1614,9 +1614,6 @@ msgstr "" ...@@ -1614,9 +1614,6 @@ msgstr ""
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster" msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
msgstr "" msgstr ""
msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which may incur additional costs depending on the hosting provider your Kubernetes cluster is installed on. If you are using Google Kubernetes Engine, you can %{pricingLink}."
msgstr ""
msgid "ClusterIntegration|%{title} upgraded successfully." msgid "ClusterIntegration|%{title} upgraded successfully."
msgstr "" msgstr ""
...@@ -1638,9 +1635,6 @@ msgstr "" ...@@ -1638,9 +1635,6 @@ msgstr ""
msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration" msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration"
msgstr "" msgstr ""
msgid "ClusterIntegration|After installing Ingress, you will need to point your wildcard DNS at the generated external IP address in order to view your app after it is deployed. %{ingressHelpLink}"
msgstr ""
msgid "ClusterIntegration|Alternatively" msgid "ClusterIntegration|Alternatively"
msgstr "" msgstr ""
...@@ -1695,7 +1689,7 @@ msgstr "" ...@@ -1695,7 +1689,7 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate" msgid "ClusterIntegration|Copy CA Certificate"
msgstr "" msgstr ""
msgid "ClusterIntegration|Copy Ingress IP Address to clipboard" msgid "ClusterIntegration|Copy Ingress Endpoint to clipboard"
msgstr "" msgstr ""
msgid "ClusterIntegration|Copy Jupyter Hostname to clipboard" msgid "ClusterIntegration|Copy Jupyter Hostname to clipboard"
...@@ -1782,7 +1776,7 @@ msgstr "" ...@@ -1782,7 +1776,7 @@ msgstr ""
msgid "ClusterIntegration|Ingress" msgid "ClusterIntegration|Ingress"
msgstr "" msgstr ""
msgid "ClusterIntegration|Ingress IP Address" msgid "ClusterIntegration|Ingress Endpoint"
msgstr "" msgstr ""
msgid "ClusterIntegration|Ingress gives you a way to route requests to services based on the request host or path, centralizing a number of services into a single entrypoint." msgid "ClusterIntegration|Ingress gives you a way to route requests to services based on the request host or path, centralizing a number of services into a single entrypoint."
...@@ -1797,6 +1791,12 @@ msgstr "" ...@@ -1797,6 +1791,12 @@ msgstr ""
msgid "ClusterIntegration|Installing" msgid "ClusterIntegration|Installing"
msgstr "" msgstr ""
msgid "ClusterIntegration|Installing Ingress may incur additional costs. Learn more about %{pricingLink}."
msgstr ""
msgid "ClusterIntegration|Installing Knative may incur additional costs. Learn more about %{pricingLink}."
msgstr ""
msgid "ClusterIntegration|Integrate Kubernetes cluster automation" msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
msgstr "" msgstr ""
...@@ -1878,9 +1878,6 @@ msgstr "" ...@@ -1878,9 +1878,6 @@ msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}" msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}"
msgstr "" msgstr ""
msgid "ClusterIntegration|More information"
msgstr ""
msgid "ClusterIntegration|No machine types matched your search" msgid "ClusterIntegration|No machine types matched your search"
msgstr "" msgstr ""
...@@ -1893,9 +1890,6 @@ msgstr "" ...@@ -1893,9 +1890,6 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search" msgid "ClusterIntegration|No zones matched your search"
msgstr "" msgstr ""
msgid "ClusterIntegration|Note:"
msgstr ""
msgid "ClusterIntegration|Number of nodes" msgid "ClusterIntegration|Number of nodes"
msgstr "" msgstr ""
...@@ -1905,7 +1899,7 @@ msgstr "" ...@@ -1905,7 +1899,7 @@ msgstr ""
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr "" msgstr ""
msgid "ClusterIntegration|Point a wildcard DNS to this generated IP address in order to access your application after it has been deployed." msgid "ClusterIntegration|Point a wildcard DNS to this generated endpoint in order to access your application after it has been deployed."
msgstr "" msgstr ""
msgid "ClusterIntegration|Project cluster" msgid "ClusterIntegration|Project cluster"
...@@ -1998,7 +1992,7 @@ msgstr "" ...@@ -1998,7 +1992,7 @@ msgstr ""
msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{auto_devops_start}Auto DevOps%{auto_devops_end}. The domain should have a wildcard DNS configured matching the domain." msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{auto_devops_start}Auto DevOps%{auto_devops_end}. The domain should have a wildcard DNS configured matching the domain."
msgstr "" msgstr ""
msgid "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." msgid "ClusterIntegration|The endpoint is in the process of being assigned. Please check your Kubernetes cluster or Quotas on Google Kubernetes Engine if it takes a long time."
msgstr "" msgstr ""
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below" msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
...@@ -2058,9 +2052,6 @@ msgstr "" ...@@ -2058,9 +2052,6 @@ msgstr ""
msgid "ClusterIntegration|access to Google Kubernetes Engine" msgid "ClusterIntegration|access to Google Kubernetes Engine"
msgstr "" msgstr ""
msgid "ClusterIntegration|check the pricing here"
msgstr ""
msgid "ClusterIntegration|documentation" msgid "ClusterIntegration|documentation"
msgstr "" msgstr ""
...@@ -2070,6 +2061,9 @@ msgstr "" ...@@ -2070,6 +2061,9 @@ msgstr ""
msgid "ClusterIntegration|meets the requirements" msgid "ClusterIntegration|meets the requirements"
msgstr "" msgstr ""
msgid "ClusterIntegration|pricing"
msgstr ""
msgid "ClusterIntegration|properly configured" msgid "ClusterIntegration|properly configured"
msgstr "" msgstr ""
......
...@@ -11,7 +11,7 @@ module QA ...@@ -11,7 +11,7 @@ module QA
end end
view 'app/assets/javascripts/clusters/components/applications.vue' do view 'app/assets/javascripts/clusters/components/applications.vue' do
element :ingress_ip_address, 'id="ingress-ip-address"' # rubocop:disable QA/ElementWithPattern element :ingress_ip_address, 'id="ingress-endpoint"' # rubocop:disable QA/ElementWithPattern
end end
view 'app/views/clusters/clusters/_form.html.haml' do view 'app/views/clusters/clusters/_form.html.haml' do
...@@ -35,7 +35,7 @@ module QA ...@@ -35,7 +35,7 @@ module QA
def ingress_ip def ingress_ip
# We need to wait longer since it can take some time before the # We need to wait longer since it can take some time before the
# ip address is assigned for the ingress controller # ip address is assigned for the ingress controller
page.find('#ingress-ip-address', wait: 1200).value page.find('#ingress-endpoint', wait: 1200).value
end end
def set_domain(domain) def set_domain(domain)
......
...@@ -82,7 +82,7 @@ describe 'Clusters Applications', :js do ...@@ -82,7 +82,7 @@ describe 'Clusters Applications', :js do
it 'should show info block and not be installable' do it 'should show info block and not be installable' do
page.within('.js-cluster-application-row-knative') do page.within('.js-cluster-application-row-knative') do
expect(page).to have_css('.bs-callout-info') expect(page).to have_css('.rbac-notice')
expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to eq('true') expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to eq('true')
end end
end end
...@@ -93,7 +93,7 @@ describe 'Clusters Applications', :js do ...@@ -93,7 +93,7 @@ describe 'Clusters Applications', :js do
it 'should not show callout block and be installable' do it 'should not show callout block and be installable' do
page.within('.js-cluster-application-row-knative') do page.within('.js-cluster-application-row-knative') do
expect(page).not_to have_css('.bs-callout-info') expect(page).not_to have_css('.rbac-notice')
expect(page).to have_css('.js-cluster-application-install-button:not([disabled])') expect(page).to have_css('.js-cluster-application-install-button:not([disabled])')
end end
end end
...@@ -226,14 +226,14 @@ describe 'Clusters Applications', :js do ...@@ -226,14 +226,14 @@ describe 'Clusters Applications', :js do
expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installed') expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installed')
expect(page).to have_css('.js-cluster-application-install-button[disabled]') expect(page).to have_css('.js-cluster-application-install-button[disabled]')
expect(page).to have_selector('.js-no-ip-message') expect(page).to have_selector('.js-no-endpoint-message')
expect(page.find('.js-ip-address').value).to eq('?') expect(page.find('.js-endpoint').value).to eq('?')
# We receive the external IP address and display # We receive the external IP address and display
Clusters::Cluster.last.application_ingress.update!(external_ip: '192.168.1.100') Clusters::Cluster.last.application_ingress.update!(external_ip: '192.168.1.100')
expect(page).not_to have_selector('.js-no-ip-message') expect(page).not_to have_selector('.js-no-endpoint-message')
expect(page.find('.js-ip-address').value).to eq('192.168.1.100') expect(page.find('.js-endpoint').value).to eq('192.168.1.100')
end end
expect(page).to have_content('Ingress was successfully installed on your Kubernetes cluster') expect(page).to have_content('Ingress was successfully installed on your Kubernetes cluster')
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
"version": { "type": "string" }, "version": { "type": "string" },
"status_reason": { "type": ["string", "null"] }, "status_reason": { "type": ["string", "null"] },
"external_ip": { "type": ["string", "null"] }, "external_ip": { "type": ["string", "null"] },
"external_hostname": { "type": ["string", "null"] },
"hostname": { "type": ["string", "null"] }, "hostname": { "type": ["string", "null"] },
"email": { "type": ["string", "null"] }, "email": { "type": ["string", "null"] },
"update_available": { "type": ["boolean", "null"] } "update_available": { "type": ["boolean", "null"] }
......
...@@ -106,7 +106,7 @@ describe('Applications', () => { ...@@ -106,7 +106,7 @@ describe('Applications', () => {
}, },
}); });
expect(vm.$el.querySelector('.js-ip-address').value).toEqual('0.0.0.0'); expect(vm.$el.querySelector('.js-endpoint').value).toEqual('0.0.0.0');
expect( expect(
vm.$el.querySelector('.js-clipboard-btn').getAttribute('data-clipboard-text'), vm.$el.querySelector('.js-clipboard-btn').getAttribute('data-clipboard-text'),
...@@ -114,6 +114,32 @@ describe('Applications', () => { ...@@ -114,6 +114,32 @@ describe('Applications', () => {
}); });
}); });
describe('with hostname', () => {
it('renders hostname with a clipboard button', () => {
vm = mountComponent(Applications, {
applications: {
ingress: {
title: 'Ingress',
status: 'installed',
externalHostname: 'localhost.localdomain',
},
helm: { title: 'Helm Tiller' },
cert_manager: { title: 'Cert-Manager' },
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '' },
knative: { title: 'Knative', hostname: '' },
},
});
expect(vm.$el.querySelector('.js-endpoint').value).toEqual('localhost.localdomain');
expect(
vm.$el.querySelector('.js-clipboard-btn').getAttribute('data-clipboard-text'),
).toEqual('localhost.localdomain');
});
});
describe('without ip address', () => { describe('without ip address', () => {
it('renders an input text with a question mark and an alert text', () => { it('renders an input text with a question mark and an alert text', () => {
vm = mountComponent(Applications, { vm = mountComponent(Applications, {
...@@ -126,9 +152,9 @@ describe('Applications', () => { ...@@ -126,9 +152,9 @@ describe('Applications', () => {
}, },
}); });
expect(vm.$el.querySelector('.js-ip-address').value).toEqual('?'); expect(vm.$el.querySelector('.js-endpoint').value).toEqual('?');
expect(vm.$el.querySelector('.js-no-ip-message')).not.toBe(null); expect(vm.$el.querySelector('.js-no-endpoint-message')).not.toBe(null);
}); });
}); });
}); });
...@@ -140,7 +166,7 @@ describe('Applications', () => { ...@@ -140,7 +166,7 @@ describe('Applications', () => {
}); });
expect(vm.$el.textContent).not.toContain('Ingress IP Address'); expect(vm.$el.textContent).not.toContain('Ingress IP Address');
expect(vm.$el.querySelector('.js-ip-address')).toBe(null); expect(vm.$el.querySelector('.js-endpoint')).toBe(null);
}); });
}); });
...@@ -268,11 +294,11 @@ describe('Applications', () => { ...@@ -268,11 +294,11 @@ describe('Applications', () => {
it('renders ip address with a clipboard button', () => { it('renders ip address with a clipboard button', () => {
vm = mountComponent(Applications, props); vm = mountComponent(Applications, props);
expect(vm.$el.querySelector('.js-knative-ip-address').value).toEqual('1.1.1.1'); expect(vm.$el.querySelector('.js-knative-endpoint').value).toEqual('1.1.1.1');
expect( expect(
vm.$el vm.$el
.querySelector('.js-knative-ip-clipboard-btn') .querySelector('.js-knative-endpoint-clipboard-btn')
.getAttribute('data-clipboard-text'), .getAttribute('data-clipboard-text'),
).toEqual('1.1.1.1'); ).toEqual('1.1.1.1');
}); });
...@@ -316,9 +342,9 @@ describe('Applications', () => { ...@@ -316,9 +342,9 @@ describe('Applications', () => {
}, },
}); });
expect(vm.$el.querySelector('.js-knative-ip-address').value).toEqual('?'); expect(vm.$el.querySelector('.js-knative-endpoint').value).toEqual('?');
expect(vm.$el.querySelector('.js-no-knative-ip-message')).not.toBe(null); expect(vm.$el.querySelector('.js-no-knative-endpoint-message')).not.toBe(null);
}); });
}); });
}); });
......
...@@ -17,6 +17,7 @@ const CLUSTERS_MOCK_DATA = { ...@@ -17,6 +17,7 @@ const CLUSTERS_MOCK_DATA = {
status: APPLICATION_STATUS.ERROR, status: APPLICATION_STATUS.ERROR,
status_reason: 'Cannot connect', status_reason: 'Cannot connect',
external_ip: null, external_ip: null,
external_hostname: null,
}, },
{ {
name: 'runner', name: 'runner',
...@@ -62,6 +63,7 @@ const CLUSTERS_MOCK_DATA = { ...@@ -62,6 +63,7 @@ const CLUSTERS_MOCK_DATA = {
status: APPLICATION_STATUS.INSTALLED, status: APPLICATION_STATUS.INSTALLED,
status_reason: 'Cannot connect', status_reason: 'Cannot connect',
external_ip: '1.1.1.1', external_ip: '1.1.1.1',
external_hostname: null,
}, },
{ {
name: 'runner', name: 'runner',
......
...@@ -78,6 +78,7 @@ describe('Clusters Store', () => { ...@@ -78,6 +78,7 @@ describe('Clusters Store', () => {
requestStatus: null, requestStatus: null,
requestReason: null, requestReason: null,
externalIp: null, externalIp: null,
externalHostname: null,
}, },
runner: { runner: {
title: 'GitLab Runner', title: 'GitLab Runner',
...@@ -113,6 +114,7 @@ describe('Clusters Store', () => { ...@@ -113,6 +114,7 @@ describe('Clusters Store', () => {
hostname: null, hostname: null,
isEditingHostName: false, isEditingHostName: false,
externalIp: null, externalIp: null,
externalHostname: null,
}, },
cert_manager: { cert_manager: {
title: 'Cert-Manager', title: 'Cert-Manager',
......
...@@ -56,6 +56,14 @@ describe Clusters::Applications::Ingress do ...@@ -56,6 +56,14 @@ describe Clusters::Applications::Ingress do
expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in) expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in)
end end
end end
context 'when there is already an external_hostname' do
let(:application) { create(:clusters_applications_ingress, :installed, external_hostname: 'localhost.localdomain') }
it 'does not schedule a ClusterWaitForIngressIpAddressWorker' do
expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in)
end
end
end end
describe '#install_command' do describe '#install_command' do
......
...@@ -26,6 +26,13 @@ describe Clusters::Applications::Jupyter do ...@@ -26,6 +26,13 @@ describe Clusters::Applications::Jupyter do
it { expect(jupyter).to be_installable } it { expect(jupyter).to be_installable }
end end
context 'when ingress is installed and external_hostname is assigned' do
let(:ingress) { create(:clusters_applications_ingress, :installed, external_hostname: 'localhost.localdomain') }
let(:jupyter) { create(:clusters_applications_jupyter, cluster: ingress.cluster) }
it { expect(jupyter).to be_installable }
end
end end
describe '#install_command' do describe '#install_command' do
......
...@@ -64,6 +64,14 @@ describe Clusters::Applications::Knative do ...@@ -64,6 +64,14 @@ describe Clusters::Applications::Knative do
expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in) expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in)
end end
end end
context 'when there is already an external_hostname' do
let(:application) { create(:clusters_applications_knative, :installed, external_hostname: 'localhost.localdomain') }
it 'does not schedule a ClusterWaitForIngressIpAddressWorker' do
expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in)
end
end
end end
shared_examples 'a command' do shared_examples 'a command' do
......
...@@ -31,6 +31,7 @@ describe Clusters::Cluster do ...@@ -31,6 +31,7 @@ describe Clusters::Cluster do
it { is_expected.to delegate_method(:available?).to(:application_prometheus).with_prefix } it { is_expected.to delegate_method(:available?).to(:application_prometheus).with_prefix }
it { is_expected.to delegate_method(:available?).to(:application_knative).with_prefix } it { is_expected.to delegate_method(:available?).to(:application_knative).with_prefix }
it { is_expected.to delegate_method(:external_ip).to(:application_ingress).with_prefix } it { is_expected.to delegate_method(:external_ip).to(:application_ingress).with_prefix }
it { is_expected.to delegate_method(:external_hostname).to(:application_ingress).with_prefix }
it { is_expected.to respond_to :project } it { is_expected.to respond_to :project }
......
...@@ -6,9 +6,17 @@ describe Clusters::Applications::CheckIngressIpAddressService do ...@@ -6,9 +6,17 @@ describe Clusters::Applications::CheckIngressIpAddressService do
let(:application) { create(:clusters_applications_ingress, :installed) } let(:application) { create(:clusters_applications_ingress, :installed) }
let(:service) { described_class.new(application) } let(:service) { described_class.new(application) }
let(:kubeclient) { double(::Kubeclient::Client, get_service: kube_service) } let(:kubeclient) { double(::Kubeclient::Client, get_service: kube_service) }
let(:ingress) { [{ ip: '111.222.111.222' }] }
let(:lease_key) { "check_ingress_ip_address_service:#{application.id}" } let(:lease_key) { "check_ingress_ip_address_service:#{application.id}" }
let(:ingress) do
[
{
ip: '111.222.111.222',
hostname: 'localhost.localdomain'
}
]
end
let(:kube_service) do let(:kube_service) do
::Kubeclient::Resource.new( ::Kubeclient::Resource.new(
{ {
......
...@@ -12,6 +12,14 @@ shared_examples 'check ingress ip executions' do |app_name| ...@@ -12,6 +12,14 @@ shared_examples 'check ingress ip executions' do |app_name|
end end
end end
context 'when the ingress external hostname is available' do
it 'updates the external_hostname for the app' do
subject
expect(application.external_hostname).to eq('localhost.localdomain')
end
end
context 'when the ingress ip address is not available' do context 'when the ingress ip address is not available' do
let(:ingress) { nil } let(:ingress) { nil }
......
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