summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorNick Thomas <nick@gitlab.com>2016-12-08 16:36:26 +0000
committerNick Thomas <nick@gitlab.com>2016-12-14 21:06:26 +0000
commitb7b83fe0c9368fa6f04dcb6eb8cd247978bba76b (patch)
tree9e2a6a71c20b8c379cfc7031903df93456c3cb10 /app
parent3e90aa1119fc4c77e92e6492f1906f252d90b64e (diff)
downloadgitlab-ce-b7b83fe0c9368fa6f04dcb6eb8cd247978bba76b.tar.gz
Introduce deployment services, starting with a KubernetesService
Diffstat (limited to 'app')
-rw-r--r--app/controllers/concerns/service_params.rb2
-rw-r--r--app/models/project.rb9
-rw-r--r--app/models/project_services/deployment_service.rb11
-rw-r--r--app/models/project_services/kubernetes_service.rb118
-rw-r--r--app/models/service.rb1
5 files changed, 140 insertions, 1 deletions
diff --git a/app/controllers/concerns/service_params.rb b/app/controllers/concerns/service_params.rb
index c33d7eecb9f..549a8526715 100644
--- a/app/controllers/concerns/service_params.rb
+++ b/app/controllers/concerns/service_params.rb
@@ -18,7 +18,7 @@ module ServiceParams
:add_pusher, :send_from_committer_email, :disable_diffs,
:external_wiki_url, :notify, :color,
:server_host, :server_port, :default_irc_uri, :enable_ssl_verification,
- :jira_issue_transition_id, :url, :project_key]
+ :jira_issue_transition_id, :url, :project_key, :ca_pem, :namespace]
# Parameters to ignore if no value is specified
FILTER_BLANK_PARAMS = [:password]
diff --git a/app/models/project.rb b/app/models/project.rb
index 77d740081c6..2c726cfc5df 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -106,6 +106,7 @@ class Project < ActiveRecord::Base
has_one :bugzilla_service, dependent: :destroy
has_one :gitlab_issue_tracker_service, dependent: :destroy, inverse_of: :project
has_one :external_wiki_service, dependent: :destroy
+ has_one :kubernetes_service, dependent: :destroy, inverse_of: :project
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link
@@ -742,6 +743,14 @@ class Project < ActiveRecord::Base
@ci_service ||= ci_services.reorder(nil).find_by(active: true)
end
+ def deployment_services
+ services.where(category: :deployment)
+ end
+
+ def deployment_service
+ @deployment_service ||= deployment_services.reorder(nil).find_by(active: true)
+ end
+
def jira_tracker?
issues_tracker.to_param == 'jira'
end
diff --git a/app/models/project_services/deployment_service.rb b/app/models/project_services/deployment_service.rb
new file mode 100644
index 00000000000..55e98c31251
--- /dev/null
+++ b/app/models/project_services/deployment_service.rb
@@ -0,0 +1,11 @@
+# Base class for deployment services
+#
+# These services integrate with a deployment solution like Kubernetes/OpenShift,
+# Mesosphere, etc, to provide additional features to environments.
+class DeploymentService < Service
+ default_value_for :category, 'deployment'
+
+ def supported_events
+ []
+ end
+end
diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb
new file mode 100644
index 00000000000..80ae1191108
--- /dev/null
+++ b/app/models/project_services/kubernetes_service.rb
@@ -0,0 +1,118 @@
+class KubernetesService < DeploymentService
+ # Namespace defaults to the project path, but can be overridden in case that
+ # is an invalid or inappropriate name
+ prop_accessor :namespace
+
+ # Access to kubernetes is directly through the API
+ prop_accessor :api_url
+
+ # Bearer authentication
+ # TODO: user/password auth, client certificates
+ prop_accessor :token
+
+ # Provide a custom CA bundle for self-signed deployments
+ prop_accessor :ca_pem
+
+ with_options presence: true, if: :activated? do
+ validates :api_url, url: true
+ validates :token
+
+ validates :namespace,
+ format: {
+ with: Gitlab::Regex.kubernetes_namespace_regex,
+ message: Gitlab::Regex.kubernetes_namespace_regex_message,
+ },
+ length: 1..63
+ end
+
+ def initialize_properties
+ if properties.nil?
+ self.properties = {}
+ self.namespace = project.path if project.present?
+ end
+ end
+
+ def title
+ 'Kubernetes'
+ end
+
+ def description
+ 'Kubernetes / Openshift integration'
+ end
+
+ def help
+ ''
+ end
+
+ def to_param
+ 'kubernetes'
+ end
+
+ def fields
+ [
+ { type: 'text',
+ name: 'namespace',
+ title: 'Kubernetes namespace',
+ placeholder: 'Kubernetes namespace',
+ },
+ { type: 'text',
+ name: 'api_url',
+ title: 'API URL',
+ placeholder: 'Kubernetes API URL, like https://kube.example.com/',
+ },
+ { type: 'text',
+ name: 'token',
+ title: 'Service token',
+ placeholder: 'Service token',
+ },
+ { type: 'textarea',
+ name: 'ca_pem',
+ title: 'Custom CA bundle',
+ placeholder: 'Certificate Authority bundle (PEM format)',
+ },
+ ]
+ end
+
+ # Check we can connect to the Kubernetes API
+ def test(*args)
+ kubeclient = build_kubeclient
+ kubeclient.discover
+
+ { success: kubeclient.discovered, result: "Checked API discovery endpoint" }
+ rescue => err
+ { success: false, result: err }
+ end
+
+ private
+
+ def build_kubeclient(api_path = '/api', api_version = 'v1')
+ return nil unless api_url && namespace && token
+
+ url = URI.parse(api_url)
+ url.path = url.path[0..-2] if url.path[-1] == "/"
+ url.path += api_path
+
+ ::Kubeclient::Client.new(
+ url,
+ api_version,
+ ssl_options: kubeclient_ssl_options,
+ auth_options: kubeclient_auth_options,
+ http_proxy_uri: ENV['http_proxy']
+ )
+ end
+
+ def kubeclient_ssl_options
+ opts = { verify_ssl: OpenSSL::SSL::VERIFY_PEER }
+
+ if ca_pem.present?
+ opts[:cert_store] = OpenSSL::X509::Store.new
+ opts[:cert_store].add_cert(OpenSSL::X509::Certificate.new(ca_pem))
+ end
+
+ opts
+ end
+
+ def kubeclient_auth_options
+ { bearer_token: token }
+ end
+end
diff --git a/app/models/service.rb b/app/models/service.rb
index 0c36acfc1b7..e49a8fa2904 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -214,6 +214,7 @@ class Service < ActiveRecord::Base
hipchat
irker
jira
+ kubernetes
mattermost_slash_commands
pipelines_email
pivotaltracker