Commit b5155b90 authored by Chris Baumbauer's avatar Chris Baumbauer

Knative support

parent 661fd213
......@@ -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);
......
......@@ -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="{ domainname: applications.knative.domainname}"
: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.domainname"
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.domainname"
type="text"
class="form-control js-domainname"
/>
</div>
</template>
</div>
</application-row>
</div>
</section>
</template>
......@@ -9,6 +9,7 @@ export default class ClusterService {
runner: this.options.installRunnerEndpoint,
prometheus: this.options.installPrometheusEndpoint,
jupyter: this.options.installJupyterEndpoint,
knative: this.options.installKnativeEndpoint,
};
}
......
......@@ -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,
domainname: ''
},
},
};
}
......
......@@ -25,5 +25,6 @@ class Projects::Clusters::ApplicationsController < Projects::ApplicationControll
def create_cluster_application_params
params.permit(:application, :hostname)
params.permit(:application, :domainname)
end
end
# frozen_string_literal: true
module Clusters
module Applications
class Knative < ActiveRecord::Base
VERSION = '0.1.2'.freeze
REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze
self.table_name = 'clusters_applications_knative'
include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus
include ::Clusters::Concerns::ApplicationVersion
include ::Clusters::Concerns::ApplicationData
include AfterCommitQueue
default_value_for :version, VERSION
default_value_for :domainname, ''
def set_initial_status
return unless not_installable?
self.status = 'installable' if cluster&.platform_kubernetes_active?
end
def chart
'knative/knative'
end
def install_command
args = []
if !domainname.nil? && !domainname.eql?('')
args = ["domain=" + domainname]
end
Gitlab::Kubernetes::Helm::InstallCommand.new(
name: name,
version: VERSION,
rbac: cluster.platform_kubernetes_rbac?,
chart: chart,
files: files,
repository: REPOSITORY,
setargs: args
)
end
def client
cluster&.platform_kubernetes&.kubeclient&.core_client
end
end
end
end
......@@ -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
......@@ -30,6 +31,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'
......@@ -85,7 +87,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
......
......@@ -6,4 +6,5 @@ class ClusterApplicationEntity < Grape::Entity
expose :status_reason
expose :external_ip, if: -> (e, _) { e.respond_to?(:external_ip) }
expose :hostname, if: -> (e, _) { e.respond_to?(:hostname) }
expose :domainname, if: -> (e, _) { e.respond_to?(:domainname) }
end
......@@ -19,6 +19,10 @@ module Clusters
application.hostname = params[:hostname]
end
if application.has_attribute?(:domainname)
application.domainname = params[:domainname]
end
if application.respond_to?(:oauth_application)
application.oauth_application = create_oauth_application(application, request)
end
......@@ -45,7 +49,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
......
......@@ -12,6 +12,7 @@
install_prometheus_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :prometheus),
install_runner_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :runner),
install_jupyter_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :jupyter),
install_knative_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :knative),
toggle_status: @cluster.enabled? ? 'true': 'false',
cluster_status: @cluster.status_name,
cluster_status_reason: @cluster.status_reason,
......
---
title: Update Helm version to 2.11.0
title: Update Helm version to 2.11.0 and introduce Knative support
author: Chris Baumbauer
type: changed
type: added
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddKnativeApplication < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
# When a migration requires downtime you **must** uncomment the following
# constant and define a short and easy to understand explanation as to why the
# migration requires downtime.
# DOWNTIME_REASON = ''
# When using the methods "add_concurrent_index", "remove_concurrent_index" or
# "add_column_with_default" you must disable the use of transactions
# as these methods can not run in an existing transaction.
# When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
# that either of them is the _only_ method called in the migration,
# any other changes should go in a separate migration.
# This ensures that upon failure _only_ the index creation or removing fails
# and can be retried or reverted easily.
#
# To disable transactions uncomment the following line and remove these
# comments:
# disable_ddl_transaction!
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 "domainname", null: false
t.text "status_reason"
end
end
end
......@@ -668,6 +668,16 @@ ActiveRecord::Schema.define(version: 20181013005024) 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 "domainname", 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
......@@ -1805,6 +1815,7 @@ ActiveRecord::Schema.define(version: 20181013005024) do
end
add_index "redirect_routes", ["path"], name: "index_redirect_routes_on_path", unique: true, using: :btree
add_index "redirect_routes", ["path"], name: "index_redirect_routes_on_path_text_pattern_ops", using: :btree, opclasses: {"path"=>"varchar_pattern_ops"}
add_index "redirect_routes", ["source_type", "source_id"], name: "index_redirect_routes_on_source_type_and_source_id", using: :btree
create_table "releases", force: :cascade do |t|
......@@ -2349,6 +2360,7 @@ ActiveRecord::Schema.define(version: 20181013005024) 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
......
......@@ -203,7 +203,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
......@@ -216,6 +216,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 available as. 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
......@@ -224,6 +225,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.
......@@ -254,6 +259,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
......
......@@ -79,6 +79,7 @@ module Gitlab
setargs.each do |s|
args.push("--set", s)
end
args
end
def optional_version_flag
......
......@@ -1493,6 +1493,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 ""
......@@ -1709,6 +1715,9 @@ msgstr ""
msgid "ClusterIntegration|sign up"
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 "Cohorts"
msgstr ""
......
......@@ -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)
......
......@@ -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', domainname: '' },
},
});
......@@ -86,6 +92,7 @@ describe('Applications', () => {
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '' },
knative: { title: 'Knative', domainname: '' },
},
});
......@@ -105,6 +112,7 @@ describe('Applications', () => {
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '' },
knative: { title: 'Knative', domainname: '' },
},
});
......@@ -123,6 +131,7 @@ describe('Applications', () => {
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '', status: 'installable' },
knative: { title: 'Knative', domainname: '', status: 'installable' },
},
});
......@@ -139,6 +148,7 @@ describe('Applications', () => {
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '', status: 'installable' },
knative: { title: 'Knative', domainname: '', 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', domainname: '' },
},
});
......@@ -171,6 +182,7 @@ describe('Applications', () => {
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', status: 'not_installable' },
knative: { title: 'Knative' },
},
});
});
......
......@@ -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': {},
},
};
......
......@@ -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,
domainname: '',
},
},
});
});
......
......@@ -246,9 +246,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
......
......@@ -80,7 +80,7 @@ describe Clusters::Gcp::FinalizeCreationService do
expect(provider.endpoint).to eq(endpoint)
expect(platform.api_url).to eq(api_url)
expect(platform.ca_cert).to eq(Base64.decode64(load_sample_cert))
expect(platform.ca_cert).to eq(Base64.decode64(load_sample_cert).chomp)
expect(platform.username).to eq(username)
expect(platform.password).to eq(password)
expect(platform).to be_abac
......@@ -110,7 +110,7 @@ describe Clusters::Gcp::FinalizeCreationService do
expect(provider.endpoint).to eq(endpoint)
expect(platform.api_url).to eq(api_url)
expect(platform.ca_cert).to eq(Base64.decode64(load_sample_cert))
expect(platform.ca_cert).to eq(Base64.decode64(load_sample_cert).chomp)
expect(platform.username).to eq(username)
expect(platform.password).to eq(password)
expect(platform).to be_rbac
......
domain: example.com
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