Commit 1cdcf402 authored by Amit Rathi's avatar Amit Rathi

Allows user to override default issuer email for cert manager

parent a445aa0a
...@@ -84,6 +84,9 @@ export default { ...@@ -84,6 +84,9 @@ export default {
ingressExternalIp() { ingressExternalIp() {
return this.applications.ingress.externalIp; return this.applications.ingress.externalIp;
}, },
certManagerInstalled() {
return this.applications.cert_manager.status === APPLICATION_STATUS.INSTALLED;
},
ingressDescription() { ingressDescription() {
const extraCostParagraph = sprintf( const extraCostParagraph = sprintf(
_.escape( _.escape(
...@@ -130,9 +133,9 @@ export default { ...@@ -130,9 +133,9 @@ export default {
return sprintf( return sprintf(
_.escape( _.escape(
s__( s__(
`ClusterIntegration|cert-manager is a native Kubernetes certificate management controller that helps with issuing certificates. `ClusterIntegration|Cert-Manager is a native Kubernetes certificate management controller that helps with issuing certificates.
Installing cert-manager on your cluster will issue a certificate by %{letsEncrypt} and ensure that certificates Installing Cert-Manager on your cluster will issue a certificate by %{letsEncrypt} and ensure that certificates
are valid and up to date.`, are valid and up-to-date.`,
), ),
), ),
{ {
...@@ -259,6 +262,16 @@ export default { ...@@ -259,6 +262,16 @@ export default {
</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-ip-address" readonly value="?" />
<p class="form-text text-muted">
{{
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>
</div> </div>
<p v-if="!ingressExternalIp" class="settings-message js-no-ip-message"> <p v-if="!ingressExternalIp" class="settings-message js-no-ip-message">
...@@ -272,17 +285,6 @@ export default { ...@@ -272,17 +285,6 @@ export default {
{{ __('More information') }} {{ __('More information') }}
</a> </a>
</p> </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> </template>
<div v-html="ingressDescription"></div> <div v-html="ingressDescription"></div>
</div> </div>
...@@ -295,11 +297,42 @@ export default { ...@@ -295,11 +297,42 @@ export default {
:status-reason="applications.cert_manager.statusReason" :status-reason="applications.cert_manager.statusReason"
:request-status="applications.cert_manager.requestStatus" :request-status="applications.cert_manager.requestStatus"
:request-reason="applications.cert_manager.requestReason" :request-reason="applications.cert_manager.requestReason"
:install-application-request-params="{ email: applications.cert_manager.email }"
:disabled="!helmInstalled" :disabled="!helmInstalled"
class="hide-bottom-border rounded-bottom" class="hide-bottom-border rounded-bottom"
title-link="https://cert-manager.readthedocs.io/en/latest/#" title-link="https://cert-manager.readthedocs.io/en/latest/#"
> >
<div slot="description" v-html="certManagerDescription"></div> <template>
<div slot="description">
<p v-html="certManagerDescription"></p>
<div class="form-group">
<label for="cert-manager-issuer-email">
{{ s__('ClusterIntegration|Issuer Email') }}
</label>
<div class="input-group">
<input
v-model="applications.cert_manager.email"
:readonly="certManagerInstalled"
type="text"
class="form-control js-email"
/>
</div>
<p class="form-text text-muted">
{{
s__(`ClusterIntegration|Issuers represent a certificate authority.
You must provide an email address for your Issuer. `)
}}
<a
href="http://docs.cert-manager.io/en/latest/reference/issuers.html?highlight=email"
target="_blank"
rel="noopener noreferrer"
>
{{ __('More information') }}
</a>
</p>
</div>
</div>
</template>
</application-row> </application-row>
<application-row <application-row
v-if="isProjectCluster" v-if="isProjectCluster"
...@@ -382,16 +415,17 @@ export default { ...@@ -382,16 +415,17 @@ export default {
/> />
</span> </span>
</div> </div>
<p v-if="ingressInstalled" class="form-text text-muted">
{{
s__(`ClusterIntegration|Replace this with your own hostname if you want.
If you do so, point hostname to Ingress IP Address from above.`)
}}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }}
</a>
</p>
</div> </div>
<p v-if="ingressInstalled">
{{
s__(`ClusterIntegration|Replace this with your own hostname if you want.
If you do so, point hostname to Ingress IP Address from above.`)
}}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }}
</a>
</p>
</template> </template>
</div> </div>
</application-row> </application-row>
......
...@@ -24,3 +24,4 @@ export const REQUEST_FAILURE = 'request-failure'; ...@@ -24,3 +24,4 @@ export const REQUEST_FAILURE = 'request-failure';
export const INGRESS = 'ingress'; export const INGRESS = 'ingress';
export const JUPYTER = 'jupyter'; export const JUPYTER = 'jupyter';
export const KNATIVE = 'knative'; export const KNATIVE = 'knative';
export const CERT_MANAGER = 'cert_manager';
import { s__ } from '../../locale'; import { s__ } from '../../locale';
import { INGRESS, JUPYTER, KNATIVE } from '../constants'; import { INGRESS, JUPYTER, KNATIVE, CERT_MANAGER } from '../constants';
export default class ClusterStore { export default class ClusterStore {
constructor() { constructor() {
...@@ -30,6 +30,7 @@ export default class ClusterStore { ...@@ -30,6 +30,7 @@ export default class ClusterStore {
statusReason: null, statusReason: null,
requestStatus: null, requestStatus: null,
requestReason: null, requestReason: null,
email: null,
}, },
runner: { runner: {
title: s__('ClusterIntegration|GitLab Runner'), title: s__('ClusterIntegration|GitLab Runner'),
...@@ -103,6 +104,9 @@ export default class ClusterStore { ...@@ -103,6 +104,9 @@ 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;
} else if (appId === CERT_MANAGER) {
this.state.applications.cert_manager.email =
this.state.applications.cert_manager.email || serverAppEntry.email;
} else if (appId === JUPYTER) { } else if (appId === JUPYTER) {
this.state.applications.jupyter.hostname = this.state.applications.jupyter.hostname =
serverAppEntry.hostname || serverAppEntry.hostname ||
......
...@@ -23,6 +23,6 @@ class Clusters::ApplicationsController < Clusters::BaseController ...@@ -23,6 +23,6 @@ class Clusters::ApplicationsController < Clusters::BaseController
end end
def create_cluster_application_params def create_cluster_application_params
params.permit(:application, :hostname) params.permit(:application, :hostname, :email)
end end
end end
...@@ -14,6 +14,10 @@ module Clusters ...@@ -14,6 +14,10 @@ module Clusters
default_value_for :version, VERSION default_value_for :version, VERSION
default_value_for :email do |cert_manager|
cert_manager.cluster&.user&.email
end
validates :email, presence: true validates :email, presence: true
def chart def chart
......
...@@ -6,4 +6,5 @@ class ClusterApplicationEntity < Grape::Entity ...@@ -6,4 +6,5 @@ class ClusterApplicationEntity < Grape::Entity
expose :status_reason expose :status_reason
expose :external_ip, if: -> (e, _) { e.respond_to?(:external_ip) } expose :external_ip, if: -> (e, _) { e.respond_to?(:external_ip) }
expose :hostname, if: -> (e, _) { e.respond_to?(:hostname) } expose :hostname, if: -> (e, _) { e.respond_to?(:hostname) }
expose :email, if: -> (e, _) { e.respond_to?(:email) }
end end
...@@ -20,7 +20,7 @@ module Clusters ...@@ -20,7 +20,7 @@ module Clusters
end end
if application.has_attribute?(:email) if application.has_attribute?(:email)
application.email = current_user.email application.email = params[:email]
end end
if application.respond_to?(:oauth_application) if application.respond_to?(:oauth_application)
......
---
title: Ability to override email for cert-manager
merge_request: 23503
author: Amit Rathi
type: added
...@@ -260,7 +260,7 @@ twice, which can lead to confusion during deployments. ...@@ -260,7 +260,7 @@ twice, which can lead to confusion during deployments.
| ----------- | :------------: | ----------- | --------------- | | ----------- | :------------: | ----------- | --------------- |
| [Helm Tiller](https://docs.helm.sh/) | 10.2+ | Helm is a package manager for Kubernetes and is required to install all the other applications. It is installed in its own pod inside the cluster which can run the `helm` CLI in a safe environment. | n/a | | [Helm Tiller](https://docs.helm.sh/) | 10.2+ | Helm is a package manager for Kubernetes and is required to install all the other applications. It is installed in its own pod inside the cluster which can run the `helm` CLI in a safe environment. | n/a |
| [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps] or deploy your own web apps. | [stable/nginx-ingress](https://github.com/helm/charts/tree/master/stable/nginx-ingress) | | [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps] or deploy your own web apps. | [stable/nginx-ingress](https://github.com/helm/charts/tree/master/stable/nginx-ingress) |
| [Cert Manager](http://docs.cert-manager.io/en/latest/) | 11.6+ | Cert Manager is a native Kubernetes certificate management controller that helps with issuing certificates. Installing Cert Manager on your cluster will issue a certificate by [Let's Encrypt](https://letsencrypt.org/) and ensure that certificates are valid and up to date. The email address used by Let's Encrypt registration will be taken from the GitLab user that installed Cert Manager on the cluster. | [stable/cert-manager](https://github.com/helm/charts/tree/master/stable/cert-manager) | | [Cert Manager](http://docs.cert-manager.io/en/latest/) | 11.6+ | Cert Manager is a native Kubernetes certificate management controller that helps with issuing certificates. Installing Cert Manager on your cluster will issue a certificate by [Let's Encrypt](https://letsencrypt.org/) and ensure that certificates are valid and up to date. | [stable/cert-manager](https://github.com/helm/charts/tree/master/stable/cert-manager) |
| [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications. | [stable/prometheus](https://github.com/helm/charts/tree/master/stable/prometheus) | | [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications. | [stable/prometheus](https://github.com/helm/charts/tree/master/stable/prometheus) |
| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. | [runner/gitlab-runner](https://gitlab.com/charts/gitlab-runner) | | [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. | [runner/gitlab-runner](https://gitlab.com/charts/gitlab-runner) |
| [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use [this](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) custom Jupyter image that installs additional useful packages on top of the base Jupyter. You will also see ready-to-use DevOps Runbooks built with Nurtch's [Rubix library](https://github.com/amit1rrr/rubix). More information on creating executable runbooks can be found at [Nurtch Documentation](http://docs.nurtch.com/en/latest). **Note**: Authentication will be enabled for any user of the GitLab server via OAuth2. HTTPS will be supported in a future release. | [jupyter/jupyterhub](https://jupyterhub.github.io/helm-chart/) | | [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use [this](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) custom Jupyter image that installs additional useful packages on top of the base Jupyter. You will also see ready-to-use DevOps Runbooks built with Nurtch's [Rubix library](https://github.com/amit1rrr/rubix). More information on creating executable runbooks can be found at [Nurtch Documentation](http://docs.nurtch.com/en/latest). **Note**: Authentication will be enabled for any user of the GitLab server via OAuth2. HTTPS will be supported in a future release. | [jupyter/jupyterhub](https://jupyterhub.github.io/helm-chart/) |
......
...@@ -1445,6 +1445,9 @@ msgstr "" ...@@ -1445,6 +1445,9 @@ msgstr ""
msgid "ClusterIntegration|Cert-Manager" msgid "ClusterIntegration|Cert-Manager"
msgstr "" msgstr ""
msgid "ClusterIntegration|Cert-Manager is a native Kubernetes certificate management controller that helps with issuing certificates. Installing Cert-Manager on your cluster will issue a certificate by %{letsEncrypt} and ensure that certificates are valid and up-to-date."
msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "" msgstr ""
...@@ -1559,6 +1562,12 @@ msgstr "" ...@@ -1559,6 +1562,12 @@ msgstr ""
msgid "ClusterIntegration|Integration status" msgid "ClusterIntegration|Integration status"
msgstr "" msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr ""
msgid "ClusterIntegration|Issuers represent a certificate authority. You must provide an email address for your Issuer. "
msgstr ""
msgid "ClusterIntegration|Jupyter Hostname" msgid "ClusterIntegration|Jupyter Hostname"
msgstr "" msgstr ""
...@@ -1778,9 +1787,6 @@ msgstr "" ...@@ -1778,9 +1787,6 @@ msgstr ""
msgid "ClusterIntegration|access to Google Kubernetes Engine" msgid "ClusterIntegration|access to Google Kubernetes Engine"
msgstr "" msgstr ""
msgid "ClusterIntegration|cert-manager is a native Kubernetes certificate management controller that helps with issuing certificates. Installing cert-manager on your cluster will issue a certificate by %{letsEncrypt} and ensure that certificates are valid and up to date."
msgstr ""
msgid "ClusterIntegration|check the pricing here" msgid "ClusterIntegration|check the pricing here"
msgstr "" msgstr ""
......
...@@ -70,6 +70,44 @@ describe 'Clusters Applications', :js do ...@@ -70,6 +70,44 @@ describe 'Clusters Applications', :js do
end end
end end
context 'when user installs Cert Manager' do
before do
allow(ClusterInstallAppWorker).to receive(:perform_async)
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in)
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async)
create(:clusters_applications_helm, :installed, cluster: cluster)
page.within('.js-cluster-application-row-cert_manager') do
click_button 'Install'
end
end
it 'shows status transition' do
def email_form_value
page.find('.js-email').value
end
page.within('.js-cluster-application-row-cert_manager') do
expect(email_form_value).to eq(cluster.user.email)
expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Install')
page.find('.js-email').set("new_email@example.org")
Clusters::Cluster.last.application_cert_manager.make_installing!
expect(email_form_value).to eq('new_email@example.org')
expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing')
Clusters::Cluster.last.application_cert_manager.make_installed!
expect(email_form_value).to eq('new_email@example.org')
expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installed')
end
expect(page).to have_content('Cert-Manager was successfully installed on your Kubernetes cluster')
end
end
context 'when user installs Ingress' do context 'when user installs Ingress' do
context 'when user installs application: Ingress' do context 'when user installs application: Ingress' do
before do before do
......
...@@ -32,7 +32,8 @@ ...@@ -32,7 +32,8 @@
}, },
"status_reason": { "type": ["string", "null"] }, "status_reason": { "type": ["string", "null"] },
"external_ip": { "type": ["string", "null"] }, "external_ip": { "type": ["string", "null"] },
"hostname": { "type": ["string", "null"] } "hostname": { "type": ["string", "null"] },
"email": { "type": ["string", "null"] }
}, },
"required" : [ "name", "status" ] "required" : [ "name", "status" ]
} }
......
...@@ -129,6 +129,54 @@ describe('Applications', () => { ...@@ -129,6 +129,54 @@ describe('Applications', () => {
}); });
}); });
describe('Cert-Manager application', () => {
describe('when not installed', () => {
it('renders email & allows editing', () => {
vm = mountComponent(Applications, {
applications: {
helm: { title: 'Helm Tiller', status: 'installed' },
ingress: { title: 'Ingress', status: 'installed', externalIp: '1.1.1.1' },
cert_manager: {
title: 'Cert-Manager',
email: 'before@example.com',
status: 'installable',
},
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '', status: 'installable' },
knative: { title: 'Knative', hostname: '', status: 'installable' },
},
});
expect(vm.$el.querySelector('.js-email').value).toEqual('before@example.com');
expect(vm.$el.querySelector('.js-email').getAttribute('readonly')).toBe(null);
});
});
describe('when installed', () => {
it('renders email in readonly', () => {
vm = mountComponent(Applications, {
applications: {
helm: { title: 'Helm Tiller', status: 'installed' },
ingress: { title: 'Ingress', status: 'installed', externalIp: '1.1.1.1' },
cert_manager: {
title: 'Cert-Manager',
email: 'after@example.com',
status: 'installed',
},
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '', status: 'installable' },
knative: { title: 'Knative', hostname: '', status: 'installable' },
},
});
expect(vm.$el.querySelector('.js-email').value).toEqual('after@example.com');
expect(vm.$el.querySelector('.js-email').getAttribute('readonly')).toEqual('readonly');
});
});
});
describe('Jupyter application', () => { describe('Jupyter application', () => {
describe('with ingress installed with ip & jupyter installable', () => { describe('with ingress installed with ip & jupyter installable', () => {
it('renders hostname active input', () => { it('renders hostname active input', () => {
......
...@@ -42,6 +42,7 @@ const CLUSTERS_MOCK_DATA = { ...@@ -42,6 +42,7 @@ const CLUSTERS_MOCK_DATA = {
name: 'cert_manager', name: 'cert_manager',
status: APPLICATION_STATUS.ERROR, status: APPLICATION_STATUS.ERROR,
status_reason: 'Cannot connect', status_reason: 'Cannot connect',
email: 'test@example.com',
}, },
], ],
}, },
...@@ -86,6 +87,7 @@ const CLUSTERS_MOCK_DATA = { ...@@ -86,6 +87,7 @@ const CLUSTERS_MOCK_DATA = {
name: 'cert_manager', name: 'cert_manager',
status: APPLICATION_STATUS.ERROR, status: APPLICATION_STATUS.ERROR,
status_reason: 'Cannot connect', status_reason: 'Cannot connect',
email: 'test@example.com',
}, },
], ],
}, },
......
...@@ -115,6 +115,7 @@ describe('Clusters Store', () => { ...@@ -115,6 +115,7 @@ describe('Clusters Store', () => {
statusReason: mockResponseData.applications[6].status_reason, statusReason: mockResponseData.applications[6].status_reason,
requestStatus: null, requestStatus: null,
requestReason: null, requestReason: null,
email: mockResponseData.applications[6].email,
}, },
}, },
}); });
......
...@@ -31,6 +31,31 @@ describe Clusters::Applications::CreateService do ...@@ -31,6 +31,31 @@ describe Clusters::Applications::CreateService do
subject subject
end end
context 'cert manager application' do
let(:params) do
{
application: 'cert_manager',
email: 'test@example.com'
}
end
before do
allow_any_instance_of(Clusters::Applications::ScheduleInstallationService).to receive(:execute)
end
it 'creates the application' do
expect do
subject
cluster.reload
end.to change(cluster, :application_cert_manager)
end
it 'sets the email' do
expect(subject.email).to eq('test@example.com')
end
end
context 'jupyter application' do context 'jupyter application' do
let(:params) do let(:params) do
{ {
......
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