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 {
ingressInstalled() {
return this.applications.ingress.status === APPLICATION_STATUS.INSTALLED;
},
ingressExternalIp() {
return this.applications.ingress.externalIp;
ingressExternalEndpoint() {
return this.applications.ingress.externalIp || this.applications.ingress.externalHostname;
},
certManagerInstalled() {
return this.applications.cert_manager.status === APPLICATION_STATUS.INSTALLED;
},
ingressDescription() {
const extraCostParagraph = 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(
return sprintf(
_.escape(
s__(
`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}`,
`ClusterIntegration|Installing Ingress may incur additional costs. Learn more about %{pricingLink}.`,
),
),
{
ingressHelpLink: `<a href="${this.ingressHelpPath}">
${_.escape(s__('ClusterIntegration|More information'))}
</a>`,
pricingLink: `<strong><a href="https://cloud.google.com/compute/pricing#lb"
target="_blank" rel="noopener noreferrer">
${_.escape(s__('ClusterIntegration|pricing'))}</a></strong>`,
},
false,
);
return `
<p>
${extraCostParagraph}
</p>
<p class="settings-message append-bottom-0">
${externalIpParagraph}
</p>
`;
},
certManagerDescription() {
return sprintf(
......@@ -196,11 +169,26 @@ export default {
knativeUpgradeFailed() {
return this.knative.status === APPLICATION_STATUS.UPDATE_ERRORED;
},
knativeExternalIp() {
return this.knative.externalIp;
knativeExternalEndpoint() {
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() {
return this.knativeExternalIp && !this.knativeUpgradeFailed && !this.knativeUpgrading;
return this.knativeExternalEndpoint && !this.knativeUpgradeFailed && !this.knativeUpgrading;
},
knativeHostname: {
get() {
......@@ -289,30 +277,30 @@ export default {
<template v-if="ingressInstalled">
<div class="form-group">
<label for="ingress-ip-address">
{{ s__('ClusterIntegration|Ingress IP Address') }}
<label for="ingress-endpoint">
{{ s__('ClusterIntegration|Ingress Endpoint') }}
</label>
<div v-if="ingressExternalIp" class="input-group">
<div v-if="ingressExternalEndpoint" class="input-group">
<input
id="ingress-ip-address"
:value="ingressExternalIp"
id="ingress-endpoint"
:value="ingressExternalEndpoint"
type="text"
class="form-control js-ip-address"
class="form-control js-endpoint"
readonly
/>
<span class="input-group-append">
<clipboard-button
:text="ingressExternalIp"
:title="s__('ClusterIntegration|Copy Ingress IP Address to clipboard')"
:text="ingressExternalEndpoint"
:title="s__('ClusterIntegration|Copy Ingress Endpoint to clipboard')"
class="input-group-text js-clipboard-btn"
/>
</span>
</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">
{{
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.`)
}}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
......@@ -321,19 +309,21 @@ export default {
</p>
</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
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') }}
</a>
</p>
</template>
<div v-html="ingressDescription"></div>
<template v-if="!ingressInstalled">
<div class="bs-callout bs-callout-info" v-html="ingressDescription"></div>
</template>
</div>
</application-row>
<application-row
......@@ -443,7 +433,7 @@ export default {
}}
</p>
<template v-if="ingressExternalIp">
<template v-if="ingressExternalEndpoint">
<div class="form-group">
<label for="jupyter-hostname">
{{ s__('ClusterIntegration|Jupyter Hostname') }}
......@@ -493,7 +483,7 @@ export default {
>
<div slot="description">
<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
to install Knative.`)
......@@ -534,31 +524,31 @@ export default {
</template>
<template v-if="knativeInstalled">
<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>
{{ s__('ClusterIntegration|Knative Endpoint:') }}
</strong>
</label>
<div v-if="knativeExternalIp" class="input-group">
<div v-if="knativeExternalEndpoint" class="input-group">
<input
id="knative-ip-address"
:value="knativeExternalIp"
id="knative-endpoint"
:value="knativeExternalEndpoint"
type="text"
class="form-control js-knative-ip-address"
class="form-control js-knative-endpoint"
readonly
/>
<span class="input-group-append">
<clipboard-button
:text="knativeExternalIp"
:text="knativeExternalEndpoint"
: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>
</div>
<input
v-else
type="text"
class="form-control js-knative-ip-address"
class="form-control js-knative-endpoint"
readonly
value="?"
/>
......@@ -576,11 +566,11 @@ export default {
</p>
<p
v-if="!knativeExternalIp"
class="settings-message js-no-knative-ip-message mt-2 mr-3 mb-0 ml-3 "
v-if="!knativeExternalEndpoint"
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
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
}}
......
......@@ -25,6 +25,7 @@ export default class ClusterStore {
requestStatus: null,
requestReason: null,
externalIp: null,
externalHostname: null,
},
cert_manager: {
title: s__('ClusterIntegration|Cert-Manager'),
......@@ -68,6 +69,7 @@ export default class ClusterStore {
hostname: null,
isEditingHostName: false,
externalIp: null,
externalHostname: null,
},
},
};
......@@ -120,6 +122,7 @@ export default class ClusterStore {
if (appId === INGRESS) {
this.state.applications.ingress.externalIp = serverAppEntry.external_ip;
this.state.applications.ingress.externalHostname = serverAppEntry.external_hostname;
} else if (appId === CERT_MANAGER) {
this.state.applications.cert_manager.email =
this.state.applications.cert_manager.email || serverAppEntry.email;
......@@ -136,6 +139,8 @@ export default class ClusterStore {
}
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) {
this.state.applications.runner.version = version;
this.state.applications.runner.upgradeAvailable = upgradeAvailable;
......
......@@ -48,6 +48,7 @@ module Clusters
def schedule_status_update
return unless installed?
return if external_ip
return if external_hostname
ClusterWaitForIngressIpAddressWorker.perform_async(name, id)
end
......
......@@ -18,8 +18,10 @@ module Clusters
def set_initial_status
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'
end
end
......
......@@ -66,6 +66,7 @@ module Clusters
def schedule_status_update
return unless installed?
return if external_ip
return if external_hostname
ClusterWaitForIngressIpAddressWorker.perform_async(name, id)
end
......
......@@ -67,6 +67,7 @@ module Clusters
delegate :available?, to: :application_prometheus, 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_hostname, to: :application_ingress, prefix: true, allow_nil: true
alias_attribute :base_domain, :domain
......
......@@ -6,6 +6,7 @@ class ClusterApplicationEntity < Grape::Entity
expose :status_reason
expose :version
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 :email, if: -> (e, _) { e.respond_to?(:email) }
expose :update_available?, as: :update_available, if: -> (e, _) { e.respond_to?(:update_available?) }
......
......@@ -11,9 +11,13 @@ module Clusters
def execute
return if app.external_ip
return if app.external_hostname
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
private
......@@ -25,12 +29,16 @@ module Clusters
end
def ingress_ip
service.status.loadBalancer.ingress&.first&.ip
ingress_service&.ip
end
def ingress_hostname
ingress_service&.hostname
end
def service
def ingress_service
strong_memoize(:ingress_service) do
app.ingress_service
app.ingress_service.status.loadBalancer.ingress&.first
end
end
end
......
......@@ -37,7 +37,7 @@
= s_('ClusterIntegration|Alternatively')
%code #{@cluster.application_ingress_external_ip}.nip.io
= 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 }
= 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 @@
cluster_status: @cluster.status_name,
cluster_status_reason: @cluster.status_reason,
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_dns_help_path: help_page_path('topics/autodevops/quick_start_guide.md', anchor: 'point-dns-at-cluster-ip'),
ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-endpoint'),
ingress_dns_help_path: help_page_path('user/project/clusters/index.md', anchor: 'manually-determining-the-external-endpoint'),
manage_prometheus_path: manage_prometheus_path } }
.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 @@
#
# 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
enable_extension "plpgsql"
......@@ -708,6 +708,7 @@ ActiveRecord::Schema.define(version: 20190301081611) do
t.string "cluster_ip"
t.text "status_reason"
t.string "external_ip"
t.string "external_hostname"
t.index ["cluster_id"], name: "index_clusters_applications_ingress_on_cluster_id", unique: true, using: :btree
end
......@@ -733,6 +734,7 @@ ActiveRecord::Schema.define(version: 20190301081611) do
t.string "hostname"
t.text "status_reason"
t.string "external_ip"
t.string "external_hostname"
t.index ["cluster_id"], name: "index_clusters_applications_knative_on_cluster_id", unique: true, using: :btree
end
......
......@@ -387,27 +387,27 @@ Upgrades will reset values back to the values built into the `runner`
chart plus the values set by
[`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:**
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
([Istio](https://istio.io)) if using [Knative](#installing-applications).
In order to publish your web application, you first need to find the external IP
address associated to your load balancer.
In order to publish your web application, you first need to find the endpoint which will be either an IP
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.
If you [installed Ingress or Knative](#installing-applications),
you should see the Ingress IP address 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
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 external endpoint of
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
**Advanced settings**, or go directly to the
......@@ -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
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
rules that allow external access to your deployed applications.
......@@ -425,19 +425,19 @@ If you installed the Ingress [via the **Applications**](#installing-applications
run the following command:
```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
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
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:
......@@ -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).
### 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
record](https://en.wikipedia.org/wiki/Wildcard_DNS_record), in order to be able
to reach your apps. This heavily depends on your domain provider, but in case
you aren't sure, just create an A record with a wildcard host like
`*.example.com.`.
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) such as `*.example.com.`
in order to be able to reach your apps. If your external endpoint is an IP address,
use an A record. If your external endpoint is a hostname, use a CNAME record.
## Multiple Kubernetes clusters **[PREMIUM]**
......
......@@ -37,9 +37,9 @@ To run Knative on Gitlab, you will need:
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.
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
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)
to build the application and the [TriggerMesh CLI](https://github.com/triggermesh/tm) to simplify the
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.
![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
**Knative IP Address** field (takes up to 5 minutes) or retrieve the Istio Ingress IP address by running the following command:
```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$
```
1. After the Knative installation has finished, you can wait for the IP address or hostname to be displayed in the
**Knative Endpoint** field or [retrieve the Istio Ingress Endpoint manually](../#manually-determining-the-external-endpoint).
NOTE: **Note:**
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.
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,
if your Knative base domain is `example.com` then you need to create an A record with domain `*.example.com`
pointing the ip address of the ingress.
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 or hostname of the ingress.
![dns entry](img/dns-entry.png)
......
......@@ -30,7 +30,7 @@ For other deployments, there is [some configuration](#manually-setting-up-nginx-
### 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:
......
......@@ -30,7 +30,7 @@ For other deployments, there is [some configuration](#manually-setting-up-nginx-
### 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:
......
......@@ -1614,9 +1614,6 @@ msgstr ""
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
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."
msgstr ""
......@@ -1638,9 +1635,6 @@ msgstr ""
msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration"
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"
msgstr ""
......@@ -1695,7 +1689,7 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
msgid "ClusterIntegration|Copy Ingress Endpoint to clipboard"
msgstr ""
msgid "ClusterIntegration|Copy Jupyter Hostname to clipboard"
......@@ -1782,7 +1776,7 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
msgid "ClusterIntegration|Ingress IP Address"
msgid "ClusterIntegration|Ingress Endpoint"
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."
......@@ -1797,6 +1791,12 @@ msgstr ""
msgid "ClusterIntegration|Installing"
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"
msgstr ""
......@@ -1878,9 +1878,6 @@ msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}"
msgstr ""
msgid "ClusterIntegration|More information"
msgstr ""
msgid "ClusterIntegration|No machine types matched your search"
msgstr ""
......@@ -1893,9 +1890,6 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
msgid "ClusterIntegration|Note:"
msgstr ""
msgid "ClusterIntegration|Number of nodes"
msgstr ""
......@@ -1905,7 +1899,7 @@ msgstr ""
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
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 ""
msgid "ClusterIntegration|Project cluster"
......@@ -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."
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 ""
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 ""
msgid "ClusterIntegration|access to Google Kubernetes Engine"
msgstr ""
msgid "ClusterIntegration|check the pricing here"
msgstr ""
msgid "ClusterIntegration|documentation"
msgstr ""
......@@ -2070,6 +2061,9 @@ msgstr ""
msgid "ClusterIntegration|meets the requirements"
msgstr ""
msgid "ClusterIntegration|pricing"
msgstr ""
msgid "ClusterIntegration|properly configured"
msgstr ""
......
......@@ -11,7 +11,7 @@ module QA
end
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
view 'app/views/clusters/clusters/_form.html.haml' do
......@@ -35,7 +35,7 @@ module QA
def ingress_ip
# We need to wait longer since it can take some time before the
# ip address is assigned for the ingress controller
page.find('#ingress-ip-address', wait: 1200).value
page.find('#ingress-endpoint', wait: 1200).value
end
def set_domain(domain)
......
......@@ -82,7 +82,7 @@ describe 'Clusters Applications', :js do
it 'should show info block and not be installable' 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')
end
end
......@@ -93,7 +93,7 @@ describe 'Clusters Applications', :js do
it 'should not show callout block and be installable' 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])')
end
end
......@@ -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[disabled]')
expect(page).to have_selector('.js-no-ip-message')
expect(page.find('.js-ip-address').value).to eq('?')
expect(page).to have_selector('.js-no-endpoint-message')
expect(page.find('.js-endpoint').value).to eq('?')
# We receive the external IP address and display
Clusters::Cluster.last.application_ingress.update!(external_ip: '192.168.1.100')
expect(page).not_to have_selector('.js-no-ip-message')
expect(page.find('.js-ip-address').value).to eq('192.168.1.100')
expect(page).not_to have_selector('.js-no-endpoint-message')
expect(page.find('.js-endpoint').value).to eq('192.168.1.100')
end
expect(page).to have_content('Ingress was successfully installed on your Kubernetes cluster')
......
......@@ -33,6 +33,7 @@
"version": { "type": "string" },
"status_reason": { "type": ["string", "null"] },
"external_ip": { "type": ["string", "null"] },
"external_hostname": { "type": ["string", "null"] },
"hostname": { "type": ["string", "null"] },
"email": { "type": ["string", "null"] },
"update_available": { "type": ["boolean", "null"] }
......
......@@ -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(
vm.$el.querySelector('.js-clipboard-btn').getAttribute('data-clipboard-text'),
......@@ -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', () => {
it('renders an input text with a question mark and an alert text', () => {
vm = mountComponent(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', () => {
});
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', () => {
it('renders ip address with a clipboard button', () => {
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(
vm.$el
.querySelector('.js-knative-ip-clipboard-btn')
.querySelector('.js-knative-endpoint-clipboard-btn')
.getAttribute('data-clipboard-text'),
).toEqual('1.1.1.1');
});
......@@ -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 = {
status: APPLICATION_STATUS.ERROR,
status_reason: 'Cannot connect',
external_ip: null,
external_hostname: null,
},
{
name: 'runner',
......@@ -62,6 +63,7 @@ const CLUSTERS_MOCK_DATA = {
status: APPLICATION_STATUS.INSTALLED,
status_reason: 'Cannot connect',
external_ip: '1.1.1.1',
external_hostname: null,
},
{
name: 'runner',
......
......@@ -78,6 +78,7 @@ describe('Clusters Store', () => {
requestStatus: null,
requestReason: null,
externalIp: null,
externalHostname: null,
},
runner: {
title: 'GitLab Runner',
......@@ -113,6 +114,7 @@ describe('Clusters Store', () => {
hostname: null,
isEditingHostName: false,
externalIp: null,
externalHostname: null,
},
cert_manager: {
title: 'Cert-Manager',
......
......@@ -56,6 +56,14 @@ describe Clusters::Applications::Ingress do
expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in)
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
describe '#install_command' do
......
......@@ -26,6 +26,13 @@ describe Clusters::Applications::Jupyter do
it { expect(jupyter).to be_installable }
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
describe '#install_command' do
......
......@@ -64,6 +64,14 @@ describe Clusters::Applications::Knative do
expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in)
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
shared_examples 'a command' 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_knative).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 }
......
......@@ -6,9 +6,17 @@ describe Clusters::Applications::CheckIngressIpAddressService do
let(:application) { create(:clusters_applications_ingress, :installed) }
let(:service) { described_class.new(application) }
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(:ingress) do
[
{
ip: '111.222.111.222',
hostname: 'localhost.localdomain'
}
]
end
let(:kube_service) do
::Kubeclient::Resource.new(
{
......
......@@ -12,6 +12,14 @@ shared_examples 'check ingress ip executions' do |app_name|
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
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