diff options
27 files changed, 376 insertions, 12 deletions
diff --git a/app/assets/images/cluster_app_logos/knative.png b/app/assets/images/cluster_app_logos/knative.png Binary files differnew file mode 100644 index 00000000000..0a2510c8549 --- /dev/null +++ b/app/assets/images/cluster_app_logos/knative.png diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index ebf76af5966..02dfe1c7d6f 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -28,6 +28,7 @@ export default class Clusters { installIngressPath, installRunnerPath, installJupyterPath, + installKnativePath, installPrometheusPath, managePrometheusPath, clusterStatus, @@ -49,6 +50,7 @@ export default class Clusters { installRunnerEndpoint: installRunnerPath, installPrometheusEndpoint: installPrometheusPath, installJupyterEndpoint: installJupyterPath, + installKnativeEndpoint: installKnativePath, }); this.installApplication = this.installApplication.bind(this); diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index 6d7f45a35d8..c7ffb470d4d 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -7,6 +7,7 @@ import helmLogo from 'images/cluster_app_logos/helm.png'; import jeagerLogo from 'images/cluster_app_logos/jeager.png'; import jupyterhubLogo from 'images/cluster_app_logos/jupyterhub.png'; import kubernetesLogo from 'images/cluster_app_logos/kubernetes.png'; +import knativeLogo from 'images/cluster_app_logos/knative.png'; import meltanoLogo from 'images/cluster_app_logos/meltano.png'; import prometheusLogo from 'images/cluster_app_logos/prometheus.png'; import { s__, sprintf } from '../../locale'; @@ -53,6 +54,7 @@ export default { jeagerLogo, jupyterhubLogo, kubernetesLogo, + knativeLogo, meltanoLogo, prometheusLogo, }), @@ -136,6 +138,9 @@ export default { jupyterHostname() { return this.applications.jupyter.hostname; }, + knativeInstalled() { + return this.applications.knative.status === APPLICATION_STATUS.INSTALLED; + }, }, created() { this.helmInstallIllustration = helmInstallIllustration; @@ -321,7 +326,6 @@ export default { :request-reason="applications.jupyter.requestReason" :install-application-request-params="{ hostname: applications.jupyter.hostname }" :disabled="!helmInstalled" - class="hide-bottom-border rounded-bottom" title-link="https://jupyterhub.readthedocs.io/en/stable/" > <div slot="description"> @@ -371,6 +375,58 @@ export default { </template> </div> </application-row> + <application-row + id="knative" + :logo-url="knativeLogo" + :title="applications.knative.title" + :status="applications.knative.status" + :status-reason="applications.knative.statusReason" + :request-status="applications.knative.requestStatus" + :request-reason="applications.knative.requestReason" + :install-application-request-params="{ hostname: applications.knative.hostname}" + :disabled="!helmInstalled" + class="hide-bottom-border rounded-bottom" + title-link="https://github.com/knative/docs" + > + <div slot="description"> + <p> + {{ s__(`ClusterIntegration|A Knative build extends Kubernetes + and utilizes existing Kubernetes primitives to provide you with + the ability to run on-cluster container builds from source. + For example, you can write a build that uses Kubernetes-native + resources to obtain your source code from a repository, + build it into container a image, and then run that image.`) }} + </p> + + <template v-if="knativeInstalled"> + <div class="form-group"> + <label for="knative-domainname"> + {{ s__('ClusterIntegration|Knative Domain Name:') }} + </label> + <input + id="knative-domainname" + v-model="applications.knative.hostname" + type="text" + class="form-control js-domainname" + readonly + /> + </div> + </template> + <template v-else> + <div class="form-group"> + <label for="knative-domainname"> + {{ s__('ClusterIntegration|Knative Domain Name:') }} + </label> + <input + id="knative-domainname" + v-model="applications.knative.hostname" + type="text" + class="form-control js-domainname" + /> + </div> + </template> + </div> + </application-row> </div> </section> </template> diff --git a/app/assets/javascripts/clusters/constants.js b/app/assets/javascripts/clusters/constants.js index 24a49624583..d707420c845 100644 --- a/app/assets/javascripts/clusters/constants.js +++ b/app/assets/javascripts/clusters/constants.js @@ -16,3 +16,4 @@ export const REQUEST_SUCCESS = 'request-success'; export const REQUEST_FAILURE = 'request-failure'; export const INGRESS = 'ingress'; export const JUPYTER = 'jupyter'; +export const KNATIVE = 'knative'; diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js index a7d82292ba9..da562b09ee5 100644 --- a/app/assets/javascripts/clusters/services/clusters_service.js +++ b/app/assets/javascripts/clusters/services/clusters_service.js @@ -9,6 +9,7 @@ export default class ClusterService { runner: this.options.installRunnerEndpoint, prometheus: this.options.installPrometheusEndpoint, jupyter: this.options.installJupyterEndpoint, + knative: this.options.installKnativeEndpoint, }; } diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js index 106ac3cb516..e9c580c5dfa 100644 --- a/app/assets/javascripts/clusters/stores/clusters_store.js +++ b/app/assets/javascripts/clusters/stores/clusters_store.js @@ -1,5 +1,5 @@ import { s__ } from '../../locale'; -import { INGRESS, JUPYTER } from '../constants'; +import { INGRESS, JUPYTER, KNATIVE } from '../constants'; export default class ClusterStore { constructor() { @@ -46,6 +46,14 @@ export default class ClusterStore { requestReason: null, hostname: null, }, + knative: { + title: s__('ClusterIntegration|Knative'), + status: null, + statusReason: null, + requestStatus: null, + requestReason: null, + hostname: '' + }, }, }; } @@ -93,6 +101,8 @@ export default class ClusterStore { (this.state.applications.ingress.externalIp ? `jupyter.${this.state.applications.ingress.externalIp}.nip.io` : ''); + } else if (appId === KNATIVE) { + this.state.applications.knative.hostname = serverAppEntry.hostname ? serverAppEntry.hostname : ''; } }); } diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb new file mode 100644 index 00000000000..76d23870f4c --- /dev/null +++ b/app/models/clusters/applications/knative.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Clusters + module Applications + class Knative < ActiveRecord::Base + VERSION = '0.1.3'.freeze + REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze + + # This is required for helm version <= 2.10.x in order to support + # Setting up CRDs + ISTIO_CRDS = 'https://storage.googleapis.com/triggermesh-charts/istio-crds.yaml'.freeze + + self.table_name = 'clusters_applications_knative' + + include ::Clusters::Concerns::ApplicationCore + include ::Clusters::Concerns::ApplicationStatus + include ::Clusters::Concerns::ApplicationVersion + include ::Clusters::Concerns::ApplicationData + + default_value_for :version, VERSION + default_value_for :hostname, '' + + def chart + 'knative/knative' + end + + def install_command + args = [] + if !hostname.nil? && !hostname.eql?('') + args = ["domain=" + hostname] + end + + Gitlab::Kubernetes::Helm::InstallCommand.new( + name: name, + version: VERSION, + rbac: cluster.platform_kubernetes_rbac?, + chart: chart, + files: files, + repository: REPOSITORY, + setargs: args, + script: install_script + ) + end + + def install_script + ['/usr/bin/kubectl', 'apply', '-f', ISTIO_CRDS] + end + + def client + cluster&.platform_kubernetes&.kubeclient&.core_client + end + end + end +end diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 2bd373e0950..7b219ec8267 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -11,7 +11,8 @@ module Clusters Applications::Ingress.application_name => Applications::Ingress, Applications::Prometheus.application_name => Applications::Prometheus, Applications::Runner.application_name => Applications::Runner, - Applications::Jupyter.application_name => Applications::Jupyter + Applications::Jupyter.application_name => Applications::Jupyter, + Applications::Knative.application_name => Applications::Knative }.freeze DEFAULT_ENVIRONMENT = '*'.freeze @@ -37,6 +38,7 @@ module Clusters has_one :application_prometheus, class_name: 'Clusters::Applications::Prometheus' has_one :application_runner, class_name: 'Clusters::Applications::Runner' has_one :application_jupyter, class_name: 'Clusters::Applications::Jupyter' + has_one :application_knative, class_name: 'Clusters::Applications::Knative' has_many :kubernetes_namespaces has_one :kubernetes_namespace, -> { order(id: :desc) }, class_name: 'Clusters::KubernetesNamespace' @@ -102,7 +104,8 @@ module Clusters application_ingress || build_application_ingress, application_prometheus || build_application_prometheus, application_runner || build_application_runner, - application_jupyter || build_application_jupyter + application_jupyter || build_application_jupyter, + application_knative || build_application_knative ] end diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb index 008e08d9914..d69038be532 100644 --- a/app/models/clusters/platforms/kubernetes.rb +++ b/app/models/clusters/platforms/kubernetes.rb @@ -26,6 +26,7 @@ module Clusters algorithm: 'aes-256-cbc' before_validation :enforce_namespace_to_lower_case + before_validation :enforce_ca_whitespace_trimming validates :namespace, allow_blank: true, @@ -201,6 +202,11 @@ module Clusters self.namespace = self.namespace&.downcase end + def enforce_ca_whitespace_trimming + self.ca_pem = self.ca_pem&.strip + self.token = self.token&.strip + end + def prevent_modification return unless managed? diff --git a/app/services/clusters/applications/create_service.rb b/app/services/clusters/applications/create_service.rb index 55f917798de..c348cad4803 100644 --- a/app/services/clusters/applications/create_service.rb +++ b/app/services/clusters/applications/create_service.rb @@ -45,7 +45,8 @@ module Clusters "ingress" => -> (cluster) { cluster.application_ingress || cluster.build_application_ingress }, "prometheus" => -> (cluster) { cluster.application_prometheus || cluster.build_application_prometheus }, "runner" => -> (cluster) { cluster.application_runner || cluster.build_application_runner }, - "jupyter" => -> (cluster) { cluster.application_jupyter || cluster.build_application_jupyter } + "jupyter" => -> (cluster) { cluster.application_jupyter || cluster.build_application_jupyter }, + "knative" => -> (cluster) { cluster.application_knative || cluster.build_application_knative } } end diff --git a/app/views/clusters/clusters/show.html.haml b/app/views/clusters/clusters/show.html.haml index 1e1157c34bd..7ea85fe43d6 100644 --- a/app/views/clusters/clusters/show.html.haml +++ b/app/views/clusters/clusters/show.html.haml @@ -13,6 +13,7 @@ install_prometheus_path: clusterable.install_applications_cluster_path(@cluster, :prometheus), install_runner_path: clusterable.install_applications_cluster_path(@cluster, :runner), install_jupyter_path: clusterable.install_applications_cluster_path(@cluster, :jupyter), + install_knative_path: clusterable.install_applications_cluster_path(@cluster, :knative), toggle_status: @cluster.enabled? ? 'true': 'false', cluster_status: @cluster.status_name, cluster_status_reason: @cluster.status_reason, diff --git a/changelogs/unreleased/introduce-knative-support.yml b/changelogs/unreleased/introduce-knative-support.yml new file mode 100644 index 00000000000..53290d71977 --- /dev/null +++ b/changelogs/unreleased/introduce-knative-support.yml @@ -0,0 +1,5 @@ +--- +title: Introduce Knative support +author: Chris Baumbauer +merge_request: 43959 +type: added diff --git a/db/migrate/20180912111628_add_knative_application.rb b/db/migrate/20180912111628_add_knative_application.rb new file mode 100644 index 00000000000..cbebc58c1e1 --- /dev/null +++ b/db/migrate/20180912111628_add_knative_application.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class AddKnativeApplication < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + create_table "clusters_applications_knative" do |t| + t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade } + + t.datetime_with_timezone "created_at", null: false + t.datetime_with_timezone "updated_at", null: false + t.integer "status", null: false + t.string "version", null: false + t.string "hostname", null: false + t.text "status_reason" + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 1a8b556228d..8c7b9d929db 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -703,6 +703,16 @@ ActiveRecord::Schema.define(version: 20181101144347) do t.text "status_reason" end + create_table "clusters_applications_knative", force: :cascade do |t| + t.integer "cluster_id", null: false + t.datetime_with_timezone "created_at", null: false + t.datetime_with_timezone "updated_at", null: false + t.integer "status", null: false + t.string "version", null: false + t.string "hostname", null: false + t.text "status_reason" + end + create_table "clusters_applications_prometheus", force: :cascade do |t| t.integer "cluster_id", null: false t.integer "status", null: false @@ -2367,6 +2377,7 @@ ActiveRecord::Schema.define(version: 20181101144347) do add_foreign_key "clusters_applications_ingress", "clusters", name: "fk_753a7b41c1", on_delete: :cascade add_foreign_key "clusters_applications_jupyter", "clusters", on_delete: :cascade add_foreign_key "clusters_applications_jupyter", "oauth_applications", on_delete: :nullify + add_foreign_key "clusters_applications_knative", "clusters", on_delete: :cascade add_foreign_key "clusters_applications_prometheus", "clusters", name: "fk_557e773639", on_delete: :cascade add_foreign_key "clusters_applications_runners", "ci_runners", column: "runner_id", name: "fk_02de2ded36", on_delete: :nullify add_foreign_key "clusters_applications_runners", "clusters", on_delete: :cascade diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index 762d254d6cc..94744cf8500 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -211,7 +211,7 @@ added directly to your configured cluster. Those applications are needed for [Review Apps](../../../ci/review_apps/index.md) and [deployments](../../../ci/environments.md). NOTE: **Note:** -The applications will be installed in a dedicated namespace called +With the exception of Knative, the applications will be installed in a dedicated namespace called `gitlab-managed-apps`. In case you have added an existing Kubernetes cluster with Tiller already installed, you should be careful as GitLab cannot detect it. By installing it via the applications will result into having it @@ -224,6 +224,7 @@ twice, which can lead to confusion during deployments. | [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) | | [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/) | +| [Knative](https://cloud.google.com/knative) | 0.1.2 | Knative provides a platform to create, deploy, and manage serverless workloads from a Kubernetes cluster. It is used in conjunction with, and includes [Istio](https://istio.io) to provide an external IP address for all programs hosted by Knative. You will be prompted to enter a wildcard domain where your applications will be exposed. Configure your DNS server to use the external IP address for that domain. For any application created and installed, they will be accessible as <program_name>.<kubernetes_namespace>.<domain_name>. **Note**: This will require your kubernetes cluster to have RBAC enabled. | [knative/knative](https://storage.googleapis.com/triggermesh-charts) ## Getting the external IP address @@ -232,6 +233,10 @@ You need a load balancer installed in your cluster in order to obtain the external IP address with the following procedure. It can be deployed using the [**Ingress** application](#installing-applications). +NOTE: **Note:** +Knative will include its own load balancer in the form of [Istio](https://istio.io). +At this time, to determine the external IP address, you will need to follow the manual approach. + In order to publish your web application, you first need to find the external IP address associated to your load balancer. @@ -262,6 +267,12 @@ run the following command: kubectl get svc --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip} ' ``` +NOTE: **Note:** +For Istio/Knative, the command will be different: +```bash +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: ```bash diff --git a/lib/gitlab/kubernetes/helm/install_command.rb b/lib/gitlab/kubernetes/helm/install_command.rb index 1be7924d6ac..aa5fddf1b44 100644 --- a/lib/gitlab/kubernetes/helm/install_command.rb +++ b/lib/gitlab/kubernetes/helm/install_command.rb @@ -4,22 +4,26 @@ module Gitlab class InstallCommand include BaseCommand - attr_reader :name, :files, :chart, :version, :repository + attr_reader :name, :files, :chart, :version, :repository, :setargs, :script - def initialize(name:, chart:, files:, rbac:, version: nil, repository: nil) + def initialize(name:, chart:, files:, rbac:, version: nil, repository: nil, setargs: nil, script: nil) @name = name @chart = chart @version = version @rbac = rbac @files = files @repository = repository + @setargs = setargs + @script = script end def generate_script super + [ init_command, repository_command, - script_command + repository_update_command, + script_command, + install_command ].compact.join("\n") end @@ -37,23 +41,35 @@ module Gitlab ['helm', 'repo', 'add', name, repository].shelljoin if repository end - def script_command + def repository_update_command + 'helm repo update >/dev/null' if repository + end + + def install_command command = ['helm', 'install', chart] + install_command_flags command.shelljoin + " >/dev/null\n" end + def script_command + unless script.nil? + script.shelljoin + " >/dev/null\n" + end + end + def install_command_flags name_flag = ['--name', name] namespace_flag = ['--namespace', Gitlab::Kubernetes::Helm::NAMESPACE] value_flag = ['-f', "/data/helm/#{name}/config/values.yaml"] + args_flag = optional_install_set_args_flag name_flag + optional_tls_flags + optional_version_flag + optional_rbac_create_flag + namespace_flag + - value_flag + value_flag + + args_flag end def optional_rbac_create_flag @@ -64,6 +80,16 @@ module Gitlab %w[--set rbac.create=true,rbac.enabled=true] end + def optional_install_set_args_flag + return [] unless setargs + + args = [] + setargs.each do |s| + args.push("--set", s) + end + args + end + def optional_version_flag return [] unless version diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index cc0817bdcd2..4e2c6f7b2c2 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -62,6 +62,7 @@ module Gitlab clusters_applications_ingress: count(::Clusters::Applications::Ingress.installed), clusters_applications_prometheus: count(::Clusters::Applications::Prometheus.installed), clusters_applications_runner: count(::Clusters::Applications::Runner.installed), + clusters_applications_knative: count(::Clusters::Applications::Knative.installed), in_review_folder: count(::Environment.in_review_folder), groups: count(Group), issues: count(Issue), diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 324e5315821..19cb4fa7305 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1346,6 +1346,9 @@ 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|A Knative build extends Kubernetes and utilizes existing Kubernetes primitives to provide you with the ability to run on-cluster container builds from source. For example, you can write a build that uses Kubernetes-native resources to obtain your source code from a repository, build it into container a image, and then run that image." +msgstr "" + msgid "ClusterIntegration|API URL" msgstr "" @@ -1496,6 +1499,12 @@ msgstr "" msgid "ClusterIntegration|JupyterHub, a multi-user Hub, spawns, manages, and proxies multiple instances of the single-user Jupyter notebook server. JupyterHub can be used to serve notebooks to a class of students, a corporate data science group, or a scientific research group." msgstr "" +msgid "ClusterIntegration|Knative" +msgstr "" + +msgid "ClusterIntegration|Knative Domain Name:" +msgstr "" + msgid "ClusterIntegration|Kubernetes cluster" msgstr "" diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb index 3c9ca22a051..3fe088d47cc 100644 --- a/spec/factories/clusters/applications/helm.rb +++ b/spec/factories/clusters/applications/helm.rb @@ -57,6 +57,10 @@ FactoryBot.define do cluster factory: %i(cluster with_installed_helm provided_by_gcp) end + factory :clusters_applications_knative, class: Clusters::Applications::Knative do + cluster factory: %i(cluster with_installed_helm provided_by_gcp) + end + factory :clusters_applications_jupyter, class: Clusters::Applications::Jupyter do oauth_application factory: :oauth_application cluster factory: %i(cluster with_installed_helm provided_by_gcp project) diff --git a/spec/javascripts/clusters/components/applications_spec.js b/spec/javascripts/clusters/components/applications_spec.js index a70138c7eee..0e2cc13fa52 100644 --- a/spec/javascripts/clusters/components/applications_spec.js +++ b/spec/javascripts/clusters/components/applications_spec.js @@ -23,6 +23,7 @@ describe('Applications', () => { runner: { title: 'GitLab Runner' }, prometheus: { title: 'Prometheus' }, jupyter: { title: 'JupyterHub' }, + knative: { title: 'Knative' }, }, }); }); @@ -46,6 +47,10 @@ describe('Applications', () => { it('renders a row for Jupyter', () => { expect(vm.$el.querySelector('.js-cluster-application-row-jupyter')).not.toBe(null); }); + + it('renders a row for Knative', () => { + expect(vm.$el.querySelector('.js-cluster-application-row-knative')).not.toBe(null); + }); }); describe('Ingress application', () => { @@ -63,6 +68,7 @@ describe('Applications', () => { runner: { title: 'GitLab Runner' }, prometheus: { title: 'Prometheus' }, jupyter: { title: 'JupyterHub', hostname: '' }, + knative: { title: 'Knative', hostname: '' }, }, }); @@ -86,6 +92,7 @@ describe('Applications', () => { runner: { title: 'GitLab Runner' }, prometheus: { title: 'Prometheus' }, jupyter: { title: 'JupyterHub', hostname: '' }, + knative: { title: 'Knative', hostname: '' }, }, }); @@ -105,6 +112,7 @@ describe('Applications', () => { runner: { title: 'GitLab Runner' }, prometheus: { title: 'Prometheus' }, jupyter: { title: 'JupyterHub', hostname: '' }, + knative: { title: 'Knative', hostname: '' }, }, }); @@ -123,6 +131,7 @@ describe('Applications', () => { runner: { title: 'GitLab Runner' }, prometheus: { title: 'Prometheus' }, jupyter: { title: 'JupyterHub', hostname: '', status: 'installable' }, + knative: { title: 'Knative', hostname: '', status: 'installable' }, }, }); @@ -139,6 +148,7 @@ describe('Applications', () => { runner: { title: 'GitLab Runner' }, prometheus: { title: 'Prometheus' }, jupyter: { title: 'JupyterHub', hostname: '', status: 'installable' }, + knative: { title: 'Knative', hostname: '', status: 'installable' }, }, }); @@ -155,6 +165,7 @@ describe('Applications', () => { runner: { title: 'GitLab Runner' }, prometheus: { title: 'Prometheus' }, jupyter: { title: 'JupyterHub', status: 'installed', hostname: '' }, + knative: { title: 'Knative', status: 'installed', hostname: '' }, }, }); @@ -171,6 +182,7 @@ describe('Applications', () => { runner: { title: 'GitLab Runner' }, prometheus: { title: 'Prometheus' }, jupyter: { title: 'JupyterHub', status: 'not_installable' }, + knative: { title: 'Knative' }, }, }); }); diff --git a/spec/javascripts/clusters/services/mock_data.js b/spec/javascripts/clusters/services/mock_data.js index 4e6ad11cd92..73abf6504c0 100644 --- a/spec/javascripts/clusters/services/mock_data.js +++ b/spec/javascripts/clusters/services/mock_data.js @@ -33,6 +33,11 @@ const CLUSTERS_MOCK_DATA = { status: APPLICATION_STATUS.INSTALLING, status_reason: 'Cannot connect', }, + { + name: 'knative', + status: APPLICATION_STATUS.INSTALLING, + status_reason: 'Cannot connect', + }, ], }, }, @@ -67,6 +72,11 @@ const CLUSTERS_MOCK_DATA = { status: APPLICATION_STATUS.INSTALLABLE, status_reason: 'Cannot connect', }, + { + name: 'knative', + status: APPLICATION_STATUS.INSTALLABLE, + status_reason: 'Cannot connect', + }, ], }, }, @@ -77,6 +87,7 @@ const CLUSTERS_MOCK_DATA = { '/gitlab-org/gitlab-shell/clusters/1/applications/runner': {}, '/gitlab-org/gitlab-shell/clusters/1/applications/prometheus': {}, '/gitlab-org/gitlab-shell/clusters/1/applications/jupyter': {}, + '/gitlab-org/gitlab-shell/clusters/1/applications/knative': {}, }, }; diff --git a/spec/javascripts/clusters/stores/clusters_store_spec.js b/spec/javascripts/clusters/stores/clusters_store_spec.js index e0f55a12fca..0586724d451 100644 --- a/spec/javascripts/clusters/stores/clusters_store_spec.js +++ b/spec/javascripts/clusters/stores/clusters_store_spec.js @@ -100,6 +100,14 @@ describe('Clusters Store', () => { requestReason: null, hostname: '', }, + knative: { + title: 'Knative', + status: mockResponseData.applications[5].status, + statusReason: mockResponseData.applications[5].status_reason, + requestStatus: null, + requestReason: null, + hostname: '', + }, }, }); }); diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb index f28941ce58f..bbe7cbe05c5 100644 --- a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb @@ -24,6 +24,7 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do <<~EOS helm init --client-only >/dev/null helm repo add app-name https://repository.example.com + helm repo update >/dev/null #{helm_install_comand} EOS end @@ -51,6 +52,7 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do <<~EOS helm init --client-only >/dev/null helm repo add app-name https://repository.example.com + helm repo update >/dev/null #{helm_install_command} EOS end @@ -107,6 +109,7 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do <<~EOS helm init --client-only >/dev/null helm repo add app-name https://repository.example.com + helm repo update >/dev/null #{helm_install_command} EOS end @@ -131,6 +134,7 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do <<~EOS helm init --client-only >/dev/null helm repo add app-name https://repository.example.com + helm repo update >/dev/null #{helm_install_command} EOS end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 69ee5ff4bcd..76dec4a44fd 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -20,6 +20,7 @@ describe Gitlab::UsageData do create(:clusters_applications_ingress, :installed, cluster: gcp_cluster) create(:clusters_applications_prometheus, :installed, cluster: gcp_cluster) create(:clusters_applications_runner, :installed, cluster: gcp_cluster) + create(:clusters_applications_knative, :installed, cluster: gcp_cluster) end subject { described_class.data } @@ -81,6 +82,7 @@ describe Gitlab::UsageData do clusters_applications_ingress clusters_applications_prometheus clusters_applications_runner + clusters_applications_knative in_review_folder groups issues @@ -126,6 +128,7 @@ describe Gitlab::UsageData do expect(count_data[:clusters_applications_ingress]).to eq(1) expect(count_data[:clusters_applications_prometheus]).to eq(1) expect(count_data[:clusters_applications_runner]).to eq(1) + expect(count_data[:clusters_applications_knative]).to eq(1) end it 'works when queries time out' do diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb new file mode 100644 index 00000000000..78124c13be9 --- /dev/null +++ b/spec/models/clusters/applications/knative_spec.rb @@ -0,0 +1,102 @@ +require 'rails_helper' + +describe Clusters::Applications::Knative do + let(:knative) { create(:clusters_applications_knative) } + + include_examples 'cluster application core specs', :clusters_applications_knative + include_examples 'cluster application status specs', :clusters_applications_knative + + describe '.installed' do + subject { described_class.installed } + + let!(:cluster) { create(:clusters_applications_knative, :installed) } + + before do + create(:clusters_applications_knative, :errored) + end + + it { is_expected.to contain_exactly(cluster) } + end + + describe '#make_installing!' do + before do + application.make_installing! + end + + context 'application install previously errored with older version' do + let(:application) { create(:clusters_applications_knative, :scheduled, version: '0.1.3') } + + it 'updates the application version' do + expect(application.reload.version).to eq('0.1.3') + end + end + end + + describe '#make_installed' do + subject { described_class.installed } + + let!(:cluster) { create(:clusters_applications_knative, :installed) } + + before do + create(:clusters_applications_knative, :errored) + end + + it { is_expected.to contain_exactly(cluster) } + end + + describe '#install_command' do + subject { knative.install_command } + + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + + it 'should be initialized with knative arguments' do + expect(subject.name).to eq('knative') + expect(subject.chart).to eq('knative/knative') + expect(subject.version).to eq('0.1.3') + expect(subject.files).to eq(knative.files) + expect(subject.setargs).to eq([]) + end + + context 'application failed to install previously' do + let(:knative) { create(:clusters_applications_knative, :errored, version: 'knative') } + + it 'should be initialized with the locked version' do + expect(subject.version).to eq('0.1.3') + end + end + end + + describe '#files' do + let(:application) { knative } + let(:values) { subject[:'values.yaml'] } + + subject { application.files } + + it 'should include knative valid keys in values' do + expect(values).to include('domain') + end + + context 'when the helm application does not have a ca_cert' do + before do + application.cluster.application_helm.ca_cert = nil + end + + it 'should not include cert files' do + expect(subject[:'ca.pem']).not_to be_present + expect(subject[:'cert.pem']).not_to be_present + expect(subject[:'key.pem']).not_to be_present + end + end + + it 'should include cert files' do + expect(subject[:'ca.pem']).to be_present + expect(subject[:'ca.pem']).to eq(application.cluster.application_helm.ca_cert) + + expect(subject[:'cert.pem']).to be_present + expect(subject[:'key.pem']).to be_present + + cert = OpenSSL::X509::Certificate.new(subject[:'cert.pem']) + expect(cert.not_after).to be < 60.minutes.from_now + end + end +end diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 19b76ca8cfb..10b9ca1a778 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -314,9 +314,10 @@ describe Clusters::Cluster do let!(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) } let!(:runner) { create(:clusters_applications_runner, cluster: cluster) } let!(:jupyter) { create(:clusters_applications_jupyter, cluster: cluster) } + let!(:knative) { create(:clusters_applications_knative, cluster: cluster) } it 'returns a list of created applications' do - is_expected.to contain_exactly(helm, ingress, prometheus, runner, jupyter) + is_expected.to contain_exactly(helm, ingress, prometheus, runner, jupyter, knative) end end end diff --git a/vendor/knative/values.yaml b/vendor/knative/values.yaml new file mode 100644 index 00000000000..b3472660fb0 --- /dev/null +++ b/vendor/knative/values.yaml @@ -0,0 +1 @@ +domain: example.com |