summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
authorDouwe Maan <douwe@selenight.nl>2017-03-07 16:39:52 -0600
committerDouwe Maan <douwe@selenight.nl>2017-03-07 16:39:52 -0600
commit3420c6cc4ef53d78db276bde06dbd9ab47165fb3 (patch)
tree2e34fd77be6424157243b67911f5c53d3a585692 /app/models
parent9895d6707d51140b3cc75e925cfd775c6bd93f83 (diff)
parent7f2819b778b055278a7fafe9c782d12d09dbd2ea (diff)
downloadgitlab-ce-3420c6cc4ef53d78db276bde06dbd9ab47165fb3.tar.gz
Merge branch 'master' into orderable-issues
Diffstat (limited to 'app/models')
-rw-r--r--app/models/chat_team.rb1
-rw-r--r--app/models/ci/build.rb58
-rw-r--r--app/models/ci/trigger.rb8
-rw-r--r--app/models/concerns/has_status.rb2
-rw-r--r--app/models/environment.rb8
-rw-r--r--app/models/oauth_access_grant.rb4
-rw-r--r--app/models/oauth_access_token.rb2
-rw-r--r--app/models/personal_access_token.rb26
-rw-r--r--app/models/project.rb11
-rw-r--r--app/models/project_services/monitoring_service.rb16
-rw-r--r--app/models/project_services/prometheus_service.rb93
-rw-r--r--app/models/repository.rb4
-rw-r--r--app/models/service.rb1
-rw-r--r--app/models/user.rb3
14 files changed, 213 insertions, 24 deletions
diff --git a/app/models/chat_team.rb b/app/models/chat_team.rb
index 7952141a0d6..c52b6f15913 100644
--- a/app/models/chat_team.rb
+++ b/app/models/chat_team.rb
@@ -1,5 +1,6 @@
class ChatTeam < ActiveRecord::Base
validates :team_id, presence: true
+ validates :namespace, uniqueness: true
belongs_to :namespace
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index d69643967a1..3722047251d 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -517,6 +517,27 @@ module Ci
]
end
+ def steps
+ [Gitlab::Ci::Build::Step.from_commands(self),
+ Gitlab::Ci::Build::Step.from_after_script(self)].compact
+ end
+
+ def image
+ Gitlab::Ci::Build::Image.from_image(self)
+ end
+
+ def services
+ Gitlab::Ci::Build::Image.from_services(self)
+ end
+
+ def artifacts
+ [options[:artifacts]]
+ end
+
+ def cache
+ [options[:cache]]
+ end
+
def credentials
Gitlab::Ci::Build::Credentials::Factory.new(self).create!
end
@@ -543,10 +564,35 @@ module Ci
@unscoped_project ||= Project.unscoped.find_by(id: gl_project_id)
end
+ CI_REGISTRY_USER = 'gitlab-ci-token'.freeze
+
def predefined_variables
variables = [
{ key: 'CI', value: 'true', public: true },
{ key: 'GITLAB_CI', value: 'true', public: true },
+ { key: 'CI_SERVER_NAME', value: 'GitLab', public: true },
+ { key: 'CI_SERVER_VERSION', value: Gitlab::VERSION, public: true },
+ { key: 'CI_SERVER_REVISION', value: Gitlab::REVISION, public: true },
+ { key: 'CI_JOB_ID', value: id.to_s, public: true },
+ { key: 'CI_JOB_NAME', value: name, public: true },
+ { key: 'CI_JOB_STAGE', value: stage, public: true },
+ { key: 'CI_JOB_TOKEN', value: token, public: false },
+ { key: 'CI_COMMIT_SHA', value: sha, public: true },
+ { key: 'CI_COMMIT_REF_NAME', value: ref, public: true },
+ { key: 'CI_COMMIT_REF_SLUG', value: ref_slug, public: true },
+ { key: 'CI_REGISTRY_USER', value: CI_REGISTRY_USER, public: true },
+ { key: 'CI_REGISTRY_PASSWORD', value: token, public: false },
+ { key: 'CI_REPOSITORY_URL', value: repo_url, public: false }
+ ]
+
+ variables << { key: "CI_COMMIT_TAG", value: ref, public: true } if tag?
+ variables << { key: "CI_PIPELINE_TRIGGERED", value: 'true', public: true } if trigger_request
+ variables << { key: "CI_JOB_MANUAL", value: 'true', public: true } if action?
+ variables.concat(legacy_variables)
+ end
+
+ def legacy_variables
+ variables = [
{ key: 'CI_BUILD_ID', value: id.to_s, public: true },
{ key: 'CI_BUILD_TOKEN', value: token, public: false },
{ key: 'CI_BUILD_REF', value: sha, public: true },
@@ -554,14 +600,12 @@ module Ci
{ key: 'CI_BUILD_REF_NAME', value: ref, public: true },
{ key: 'CI_BUILD_REF_SLUG', value: ref_slug, public: true },
{ key: 'CI_BUILD_NAME', value: name, public: true },
- { key: 'CI_BUILD_STAGE', value: stage, public: true },
- { key: 'CI_SERVER_NAME', value: 'GitLab', public: true },
- { key: 'CI_SERVER_VERSION', value: Gitlab::VERSION, public: true },
- { key: 'CI_SERVER_REVISION', value: Gitlab::REVISION, public: true }
+ { key: 'CI_BUILD_STAGE', value: stage, public: true }
]
- variables << { key: 'CI_BUILD_TAG', value: ref, public: true } if tag?
- variables << { key: 'CI_BUILD_TRIGGERED', value: 'true', public: true } if trigger_request
- variables << { key: 'CI_BUILD_MANUAL', value: 'true', public: true } if action?
+
+ variables << { key: "CI_BUILD_TAG", value: ref, public: true } if tag?
+ variables << { key: "CI_BUILD_TRIGGERED", value: 'true', public: true } if trigger_request
+ variables << { key: "CI_BUILD_MANUAL", value: 'true', public: true } if action?
variables
end
diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb
index 8aa45b2f02e..90473d41c04 100644
--- a/app/models/ci/trigger.rb
+++ b/app/models/ci/trigger.rb
@@ -29,8 +29,12 @@ module Ci
token[0...4]
end
- def can_show_token?(user)
- owner.blank? || owner == user
+ def legacy?
+ self.owner_id.blank?
+ end
+
+ def can_access_project?
+ self.owner_id.blank? || Ability.allowed?(self.owner, :create_build, project)
end
end
end
diff --git a/app/models/concerns/has_status.rb b/app/models/concerns/has_status.rb
index b819947c9e6..5101cc7e687 100644
--- a/app/models/concerns/has_status.rb
+++ b/app/models/concerns/has_status.rb
@@ -7,7 +7,7 @@ module HasStatus
STARTED_STATUSES = %w[running success failed skipped manual].freeze
ACTIVE_STATUSES = %w[pending running].freeze
COMPLETED_STATUSES = %w[success failed canceled skipped].freeze
- ORDERED_STATUSES = %w[manual failed pending running canceled success skipped].freeze
+ ORDERED_STATUSES = %w[failed pending running manual canceled success skipped created].freeze
class_methods do
def status_sql
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 1a21b5e52b5..bf33010fd21 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -145,6 +145,14 @@ class Environment < ActiveRecord::Base
project.deployment_service.terminals(self) if has_terminals?
end
+ def has_metrics?
+ project.monitoring_service.present? && available? && last_deployment.present?
+ end
+
+ def metrics
+ project.monitoring_service.metrics(self) if has_metrics?
+ end
+
# An environment name is not necessarily suitable for use in URLs, DNS
# or other third-party contexts, so provide a slugified version. A slug has
# the following properties:
diff --git a/app/models/oauth_access_grant.rb b/app/models/oauth_access_grant.rb
new file mode 100644
index 00000000000..3a997406565
--- /dev/null
+++ b/app/models/oauth_access_grant.rb
@@ -0,0 +1,4 @@
+class OauthAccessGrant < Doorkeeper::AccessGrant
+ belongs_to :resource_owner, class_name: 'User'
+ belongs_to :application, class_name: 'Doorkeeper::Application'
+end
diff --git a/app/models/oauth_access_token.rb b/app/models/oauth_access_token.rb
index 116fb71ac08..b85f5dbaf2e 100644
--- a/app/models/oauth_access_token.rb
+++ b/app/models/oauth_access_token.rb
@@ -1,4 +1,4 @@
-class OauthAccessToken < ActiveRecord::Base
+class OauthAccessToken < Doorkeeper::AccessToken
belongs_to :resource_owner, class_name: 'User'
belongs_to :application, class_name: 'Doorkeeper::Application'
end
diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb
index 10a34c42fd8..e8b000ddad6 100644
--- a/app/models/personal_access_token.rb
+++ b/app/models/personal_access_token.rb
@@ -1,4 +1,5 @@
class PersonalAccessToken < ActiveRecord::Base
+ include Expirable
include TokenAuthenticatable
add_authentication_token_field :token
@@ -6,17 +7,30 @@ class PersonalAccessToken < ActiveRecord::Base
belongs_to :user
- scope :active, -> { where(revoked: false).where("expires_at >= NOW() OR expires_at IS NULL") }
+ before_save :ensure_token
+
+ scope :active, -> { where("revoked = false AND (expires_at >= NOW() OR expires_at IS NULL)") }
scope :inactive, -> { where("revoked = true OR expires_at < NOW()") }
+ scope :with_impersonation, -> { where(impersonation: true) }
+ scope :without_impersonation, -> { where(impersonation: false) }
- def self.generate(params)
- personal_access_token = self.new(params)
- personal_access_token.ensure_token
- personal_access_token
- end
+ validates :scopes, presence: true
+ validate :validate_api_scopes
def revoke!
self.revoked = true
self.save
end
+
+ def active?
+ !revoked? && !expired?
+ end
+
+ protected
+
+ def validate_api_scopes
+ unless scopes.all? { |scope| Gitlab::Auth::API_SCOPES.include?(scope.to_sym) }
+ errors.add :scopes, "can only contain API scopes"
+ end
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 7d211784c3c..8c2dadf4659 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -113,6 +113,7 @@ class Project < ActiveRecord::Base
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 :prometheus_service, dependent: :destroy, inverse_of: :project
has_one :mock_ci_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
@@ -392,7 +393,7 @@ class Project < ActiveRecord::Base
end
def repository_storage_path
- Gitlab.config.repositories.storages[repository_storage]
+ Gitlab.config.repositories.storages[repository_storage]['path']
end
def team
@@ -771,6 +772,14 @@ class Project < ActiveRecord::Base
@deployment_service ||= deployment_services.reorder(nil).find_by(active: true)
end
+ def monitoring_services
+ services.where(category: :monitoring)
+ end
+
+ def monitoring_service
+ @monitoring_service ||= monitoring_services.reorder(nil).find_by(active: true)
+ end
+
def jira_tracker?
issues_tracker.to_param == 'jira'
end
diff --git a/app/models/project_services/monitoring_service.rb b/app/models/project_services/monitoring_service.rb
new file mode 100644
index 00000000000..ea585721e8f
--- /dev/null
+++ b/app/models/project_services/monitoring_service.rb
@@ -0,0 +1,16 @@
+# Base class for monitoring services
+#
+# These services integrate with a deployment solution like Prometheus
+# to provide additional features for environments.
+class MonitoringService < Service
+ default_value_for :category, 'monitoring'
+
+ def self.supported_events
+ %w()
+ end
+
+ # Environments have a number of metrics
+ def metrics(environment)
+ raise NotImplementedError
+ end
+end
diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb
new file mode 100644
index 00000000000..375966b9efc
--- /dev/null
+++ b/app/models/project_services/prometheus_service.rb
@@ -0,0 +1,93 @@
+class PrometheusService < MonitoringService
+ include ReactiveCaching
+
+ self.reactive_cache_key = ->(service) { [service.class.model_name.singular, service.project_id] }
+ self.reactive_cache_lease_timeout = 30.seconds
+ self.reactive_cache_refresh_interval = 30.seconds
+ self.reactive_cache_lifetime = 1.minute
+
+ # Access to prometheus is directly through the API
+ prop_accessor :api_url
+
+ with_options presence: true, if: :activated? do
+ validates :api_url, url: true
+ end
+
+ after_save :clear_reactive_cache!
+
+ def initialize_properties
+ if properties.nil?
+ self.properties = {}
+ end
+ end
+
+ def title
+ 'Prometheus'
+ end
+
+ def description
+ 'Prometheus monitoring'
+ end
+
+ def help
+ 'Retrieves `container_cpu_usage_seconds_total` and `container_memory_usage_bytes` from the configured Prometheus server. An `environment` label is required on each metric to identify the Environment.'
+ end
+
+ def self.to_param
+ 'prometheus'
+ end
+
+ def fields
+ [
+ {
+ type: 'text',
+ name: 'api_url',
+ title: 'API URL',
+ placeholder: 'Prometheus API Base URL, like http://prometheus.example.com/'
+ }
+ ]
+ end
+
+ # Check we can connect to the Prometheus API
+ def test(*args)
+ client.ping
+
+ { success: true, result: 'Checked API endpoint' }
+ rescue Gitlab::PrometheusError => err
+ { success: false, result: err }
+ end
+
+ def metrics(environment)
+ with_reactive_cache(environment.slug) do |data|
+ data
+ end
+ end
+
+ # Cache metrics for specific environment
+ def calculate_reactive_cache(environment_slug)
+ return unless active? && project && !project.pending_delete?
+
+ memory_query = %{sum(container_memory_usage_bytes{container_name="app",environment="#{environment_slug}"})/1024/1024}
+ cpu_query = %{sum(rate(container_cpu_usage_seconds_total{container_name="app",environment="#{environment_slug}"}[2m]))}
+
+ {
+ success: true,
+ metrics: {
+ # Memory used in MB
+ memory_values: client.query_range(memory_query, start: 8.hours.ago),
+ memory_current: client.query(memory_query),
+ # CPU Usage rate in cores.
+ cpu_values: client.query_range(cpu_query, start: 8.hours.ago),
+ cpu_current: client.query(cpu_query)
+ },
+ last_update: Time.now.utc
+ }
+
+ rescue Gitlab::PrometheusError => err
+ { success: false, result: err.message }
+ end
+
+ def client
+ @prometheus ||= Gitlab::Prometheus.new(api_url: api_url)
+ end
+end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index e7cc8d6e083..2a12b36a84d 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -50,10 +50,6 @@ class Repository
end
end
- def self.storages
- Gitlab.config.repositories.storages
- end
-
def initialize(path_with_namespace, project)
@path_with_namespace = path_with_namespace
@project = project
diff --git a/app/models/service.rb b/app/models/service.rb
index 3ef4cbead10..2f75a2e4e7f 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -232,6 +232,7 @@ class Service < ActiveRecord::Base
mattermost
pipelines_email
pivotaltracker
+ prometheus
pushover
redmine
slack_slash_commands
diff --git a/app/models/user.rb b/app/models/user.rb
index bd57904a2cd..76fb4cd470e 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -325,8 +325,7 @@ class User < ActiveRecord::Base
end
def find_by_personal_access_token(token_string)
- personal_access_token = PersonalAccessToken.active.find_by_token(token_string) if token_string
- personal_access_token&.user
+ PersonalAccessTokensFinder.new(state: 'active').find_by(token: token_string)&.user
end
# Returns a user for the given SSH key.