summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzciński <ayufan@ayufan.eu>2018-09-12 20:26:19 +0200
committerKamil Trzciński <ayufan@ayufan.eu>2018-09-12 20:26:19 +0200
commitca2046167da10e583d27dd5d94ff6930fb44be5f (patch)
tree2a4a0c29ee5fba1a8d72127eaeebcd07c3d11b7e
parent88225ea3085d01f083a0ce693c4b87a7f9514f8d (diff)
downloadgitlab-ce-knative-first-class-support.tar.gz
Add functions runtimeknative-first-class-support
-rw-r--r--app/controllers/projects/knative_controller.rb61
-rw-r--r--app/models/project.rb2
-rw-r--r--app/models/serverless/functions.rb101
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml4
-rw-r--r--app/views/projects/knative/_form.html.haml26
-rw-r--r--app/views/projects/knative/_functions.html.haml13
-rw-r--r--app/views/projects/knative/_triggers.html.haml (renamed from app/views/projects/knative/_list.html.haml)25
-rw-r--r--app/views/projects/knative/_use.html.haml2
-rw-r--r--app/views/projects/knative/edit.html.haml11
-rw-r--r--app/views/projects/knative/index.html.haml12
-rw-r--r--app/views/projects/knative/new.html.haml12
-rw-r--r--db/migrate/20180912161550_add_serverless_functions.rb42
12 files changed, 287 insertions, 24 deletions
diff --git a/app/controllers/projects/knative_controller.rb b/app/controllers/projects/knative_controller.rb
index 3785788c0a8..f1f1bb84f75 100644
--- a/app/controllers/projects/knative_controller.rb
+++ b/app/controllers/projects/knative_controller.rb
@@ -1,6 +1,67 @@
class Projects::KnativeController < Projects::ApplicationController
respond_to :html
+ before_action :authorize_read_cluster!
+ before_action :serverless_function, only: [:edit, :update, :destroy]
+
+ def index
+ end
+
def index
+ @serverless_functions = project.serverless_functions
+ end
+
+ def new
+ @serverless_function = project.serverless_functions.new
+ end
+
+ def create
+ @serverless_function = project.serverless_functions.create(create_params)
+
+ if @serverless_function.persisted?
+ flash[:notice] = 'Function was successfully created.'
+ redirect_to project_knative_index_path(@project)
+ else
+ render :new
+ end
+ end
+
+ def edit
end
+
+ def update
+ if serverless_function.update(update_params)
+ flash[:notice] = 'Function was successfully updated.'
+ redirect_to project_knative_index_path(@project)
+ else
+ render :edit
+ end
+ end
+
+ def destroy
+ if serverless_function.destroy
+ flash[:notice] = 'Function was successfully updated.'
+ redirect_to project_knative_index_path(@project)
+ else
+ flash[:notice] = 'Function was not removed.'
+ redirect_to project_knative_index_path(@project)
+ end
+ end
+
+ protected
+
+ def serverless_function
+ @serverless_function ||= project.serverless_functions.find(params[:id])
+ end
+
+ def create_params
+ params.require(:serverless_functions)
+ .permit(:name, :function_code, :runtime_image, :active)
+ end
+
+ def update_params
+ params.require(:serverless_functions)
+ .permit(:name, :function_code, :runtime_image)
+ end
+
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 8928bffd36c..8e091c31712 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -268,6 +268,8 @@ class Project < ActiveRecord::Base
has_many :remote_mirrors, inverse_of: :project
+ has_many :serverless_functions, class_name: 'Serverless::Functions'
+
accepts_nested_attributes_for :variables, allow_destroy: true
accepts_nested_attributes_for :project_feature, update_only: true
accepts_nested_attributes_for :import_data
diff --git a/app/models/serverless/functions.rb b/app/models/serverless/functions.rb
new file mode 100644
index 00000000000..2c9d7ac52aa
--- /dev/null
+++ b/app/models/serverless/functions.rb
@@ -0,0 +1,101 @@
+module Serverless
+ class Functions < ActiveRecord::Base
+ self.table_name = 'serverless_functions'
+
+ belongs_to :project
+
+ validates :project, presence: true
+ validates :runtime_image,
+ presence: true,
+ length: 2..255
+
+ validates :function_code,
+ presence: true
+
+ after_save :create_or_update_function
+ after_destroy :destroy_function
+
+ private
+
+ def knative_client
+ @knative_client ||= project.clusters&.first&.application_knative&.client
+ end
+
+ def create_or_update_function
+ raise ArgumentError, "knative is not installed" unless knative_client
+
+ @existing_service = knative_client.get_service(name, function_namespace)
+
+ knative_client.update_service(create_metadata)
+ rescue ::Kubeclient::HttpError => e
+ raise e unless e.error_code == 404
+
+ knative_client.create_service(create_metadata)
+ end
+
+ def destroy_function
+ return unless knative_client
+
+ knative_client.delete_service(name, function_namespace)
+ rescue ::Kubeclient::HttpError => e
+ raise e unless e.error_code == 404
+
+ false
+ end
+
+ def update_metadata
+ ::Kubeclient::Resource.new.tap do |r|
+ r.metadata = {
+ #labels: { project_id: project_id.to_s, function_id: id.to_s }
+ }
+ r.spec = {
+ generation: (@existing_service&.spec || {})[:generation],
+ runLatest: {
+ configuration: {
+ revisionTemplate: {
+ spec: {
+ container: {
+ image: runtime_image,
+ env: [
+ { name: 'FUNCTION', value: function_code.to_s }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ end
+ end
+
+ def create_metadata
+ update_metadata.tap do |r|
+ r.apiVersion = 'serving.knative.dev/v1alpha1'
+ r.kind = 'Service'
+ r.metadata[:name] = name
+ r.metadata[:namespace] = function_namespace
+ r.metadata[:resourceVersion] = (@existing_service&.metadata || {})[:resourceVersion]
+ end
+ end
+
+ def function_namespace
+ 'default'
+ end
+
+ # apiVersion: serving.knative.dev/v1alpha1 # Current version of Knative
+ # kind: Service
+ # metadata:
+ # name: helloworld-go # The name of the app
+ # namespace: default # The namespace the app will use
+ # spec:
+ # runLatest:
+ # configuration:
+ # revisionTemplate:
+ # spec:
+ # container:
+ # image: gcr.io/knative-samples/helloworld-go # The URL to the image of the app
+ # env:
+ # - name: TARGET # The environment variable printed out by the sample app
+ # value: "Go Sample v1"
+ end
+end
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 8173225f34d..531682724e5 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -217,9 +217,9 @@
- if project_nav_tab? :knative
= nav_link(controller: :knative) do
- = link_to project_knative_index_path(@project), title: _('Knative'), class: 'shortcuts-metrics' do
+ = link_to project_knative_index_path(@project), title: _('Functions'), class: 'shortcuts-metrics' do
%span
- = _('Knative')
+ = _('Functions')
= nav_link(controller: :environments, action: [:index, :folder, :show, :new, :edit, :create, :update, :stop, :terminal]) do
= link_to project_environments_path(@project), title: _('Environments'), class: 'shortcuts-environments' do
diff --git a/app/views/projects/knative/_form.html.haml b/app/views/projects/knative/_form.html.haml
new file mode 100644
index 00000000000..a97fb78028b
--- /dev/null
+++ b/app/views/projects/knative/_form.html.haml
@@ -0,0 +1,26 @@
+- if @serverless_function.errors.any?
+ #error_explanation
+ .alert.alert-danger
+ - @serverless_function.errors.full_messages.each do |msg|
+ %p= msg
+
+.form-group.row
+ = f.label :name, class: 'col-form-label col-sm-2' do
+ Name
+ .col-sm-10
+ = f.text_field :name, required: true, autocomplete: 'off', class: 'form-control'
+
+.form-group.row
+ = f.label :runtime_image, class: 'col-form-label col-sm-2' do
+ Runtime
+ .col-sm-10
+ - options = ["registry.gitlab.com/ayufan/serverless-functions/functions/go:1.11.0", "gcr.io/knative-samples/helloworld-go"]
+ = f.select :runtime_image, options, multiple: false, class: 'form-control'
+ // = f.text_field :runtime_image, required: true, autocomplete: 'off', class: 'form-control'
+
+.form-group.row
+ = f.label :runtime, class: 'col-form-label col-sm-2' do
+ Code
+ .col-sm-10
+ = f.text_area :function_code, rows: 5, class: 'form-control'
+ %span.help-inline Write a function code
diff --git a/app/views/projects/knative/_functions.html.haml b/app/views/projects/knative/_functions.html.haml
new file mode 100644
index 00000000000..d4f405b7d86
--- /dev/null
+++ b/app/views/projects/knative/_functions.html.haml
@@ -0,0 +1,13 @@
+.card
+ .card-header
+ Functions (#{@serverless_functions.count})
+
+ %ul.content-list.pages-domain-list
+ - @serverless_functions.each do |serverless_function|
+ %li.pages-domain-list-item.unstyled
+ = serverless_function.name
+
+ %div.controls.d-none.d-md-block
+ = link_to 'Edit', edit_project_knative_path(@project, serverless_function), class: "btn btn-sm btn-grouped"
+ = link_to 'Remove', project_knative_path(@project, serverless_function), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-sm btn-grouped"
+
diff --git a/app/views/projects/knative/_list.html.haml b/app/views/projects/knative/_triggers.html.haml
index 785f053bcbd..082701d10a0 100644
--- a/app/views/projects/knative/_list.html.haml
+++ b/app/views/projects/knative/_triggers.html.haml
@@ -2,27 +2,20 @@
- services = cluster_client.get_services
.card
.card-header
- Knative Services (#{services.count})
+ Services (#{services.count})
+
%ul.content-list.pages-domain-list
- services.each do |service|
%li.pages-domain-list-item.unstyled
= service.metadata.name
- %p
- = service.status.domain
-
- - if traffic = service.status&.trafic&.first
- %p
- Traffic configuration:
- = traffic.configurationName
- Percent:
- = traffic.percent
- Revision:
- = traffic.revisionName
-
%div.controls.d-none.d-md-block
- %p
- - if service.status.conditions.all? { |condition| condition.status }
+ - if service.status.conditions.all? { |condition| condition.status == "True" }
%span.badge.badge-success Ready
- else
- %span.badge.badge-danger NotReady
+ %span.badge.badge-danger Not ready
+
+ %p
+ %span.badge.badge-primary
+ = service.status.domain
+ \ No newline at end of file
diff --git a/app/views/projects/knative/_use.html.haml b/app/views/projects/knative/_use.html.haml
index 73d1319511d..867307f6fba 100644
--- a/app/views/projects/knative/_use.html.haml
+++ b/app/views/projects/knative/_use.html.haml
@@ -3,7 +3,7 @@
Configure Knative...
.card-body
%p
- Learn how to enable knative functions.
+ Learn how to enable use Knative Triggers functions.
%ol
%li
diff --git a/app/views/projects/knative/edit.html.haml b/app/views/projects/knative/edit.html.haml
new file mode 100644
index 00000000000..2c0df47054e
--- /dev/null
+++ b/app/views/projects/knative/edit.html.haml
@@ -0,0 +1,11 @@
+- add_to_breadcrumbs "Functions", project_knative_index_path(@project)
+- breadcrumb_title @serverless_function.name
+- page_title @serverless_function.name
+%h3.page-title
+ = @serverless_function.name
+%hr.clearfix
+%div
+ = form_for [@project, @serverless_function], url: project_knative_path(@project, @serverless_function), html: { class: 'fieldset-form' } do |f|
+ = render 'form', { f: f }
+ .form-actions
+ = f.submit 'Save Changes', class: "btn btn-save"
diff --git a/app/views/projects/knative/index.html.haml b/app/views/projects/knative/index.html.haml
index 4cd94ab1061..d1361dd6040 100644
--- a/app/views/projects/knative/index.html.haml
+++ b/app/views/projects/knative/index.html.haml
@@ -3,12 +3,14 @@
%h3.page-title.with-button
Knative
-%p.light
- With GitLab Knative
+ - if can?(current_user, :create_cluster, @project)
+ = link_to new_project_knative_path(@project), class: 'btn btn-new float-right', title: 'New Function' do
+ New Function
%hr.clearfix
+= render 'functions'
+
- if cluster_client = @project.clusters.first.application_knative.client
- = render 'list', locals: { cluster_client: cluster_client }
-- else
- = render 'use'
+ = render 'triggers', locals: { cluster_client: cluster_client }
+
diff --git a/app/views/projects/knative/new.html.haml b/app/views/projects/knative/new.html.haml
new file mode 100644
index 00000000000..a42479c4951
--- /dev/null
+++ b/app/views/projects/knative/new.html.haml
@@ -0,0 +1,12 @@
+- add_to_breadcrumbs "Functions", project_knative_index_path(@project)
+- page_title 'New Function'
+%h3.page-title
+ New Function
+%hr.clearfix
+%div
+ = form_for [@project, @serverless_function], url: project_knative_index_path(@project), html: { class: 'fieldset-form' } do |f|
+ = render 'form', { f: f }
+ .form-actions
+ = f.submit 'Create New Function', class: "btn btn-save"
+ .float-right
+ = link_to _('Cancel'), project_knative_index_path(@project), class: 'btn btn-cancel'
diff --git a/db/migrate/20180912161550_add_serverless_functions.rb b/db/migrate/20180912161550_add_serverless_functions.rb
new file mode 100644
index 00000000000..8514a7c7f0c
--- /dev/null
+++ b/db/migrate/20180912161550_add_serverless_functions.rb
@@ -0,0 +1,42 @@
+# 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 AddServerlessFunctions < 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 "serverless_functions" do |t|
+ t.integer "project_id", null: false, index: true
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.string "name"
+ t.string "runtime_image"
+ t.text "function_code"
+ end
+
+ add_index :serverless_functions, [:project_id, :name], unique: true
+ end
+end