diff options
author | Francisco Javier López <fjlopez@gitlab.com> | 2019-04-03 12:50:54 +0300 |
---|---|---|
committer | Kamil Trzciński <ayufan@ayufan.eu> | 2019-04-03 12:50:54 +0300 |
commit | 6ee1d8cf7778ecef0997c10f22b18ab4b61e9b3b (patch) | |
tree | c3c33ae8baff308b7c3334829a804d532658c1b1 /lib/gitlab/config | |
parent | a7d3a5e43957185dc6193d1b97c57fc4eb02e9ea (diff) |
Add port section to CI Image object
In order to implement https://gitlab.com/gitlab-org/gitlab-ee/issues/10179
we need several modifications on the CI config file. We are
adding a new ports section in the default Image object.
Each of these ports will accept: number, protocol and name.
By default this new configuration will be only enabled in
the Web IDE config file.
Diffstat (limited to 'lib/gitlab/config')
-rw-r--r-- | lib/gitlab/config/entry/configurable.rb | 10 | ||||
-rw-r--r-- | lib/gitlab/config/entry/factory.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/config/entry/node.rb | 20 | ||||
-rw-r--r-- | lib/gitlab/config/entry/simplifiable.rb | 5 | ||||
-rw-r--r-- | lib/gitlab/config/entry/validators.rb | 102 |
5 files changed, 136 insertions, 3 deletions
diff --git a/lib/gitlab/config/entry/configurable.rb b/lib/gitlab/config/entry/configurable.rb index 37ba16dba25..6667a5d3d33 100644 --- a/lib/gitlab/config/entry/configurable.rb +++ b/lib/gitlab/config/entry/configurable.rb @@ -21,7 +21,7 @@ module Gitlab include Validatable validations do - validates :config, type: Hash + validates :config, type: Hash, unless: :skip_config_hash_validation? end end @@ -30,6 +30,10 @@ module Gitlab return unless valid? self.class.nodes.each do |key, factory| + # If we override the config type validation + # we can end with different config types like String + next unless config.is_a?(Hash) + factory .value(config[key]) .with(key: key, parent: self) @@ -45,6 +49,10 @@ module Gitlab end # rubocop: enable CodeReuse/ActiveRecord + def skip_config_hash_validation? + false + end + class_methods do def nodes Hash[(@nodes || {}).map { |key, factory| [key, factory.dup] }] diff --git a/lib/gitlab/config/entry/factory.rb b/lib/gitlab/config/entry/factory.rb index 79f9ff32514..3c06b1e0d24 100644 --- a/lib/gitlab/config/entry/factory.rb +++ b/lib/gitlab/config/entry/factory.rb @@ -61,7 +61,7 @@ module Gitlab end def fabricate(entry, value = nil) - entry.new(value, @metadata).tap do |node| + entry.new(value, @metadata) do |node| node.key = @attributes[:key] node.parent = @attributes[:parent] node.default = @attributes[:default] diff --git a/lib/gitlab/config/entry/node.rb b/lib/gitlab/config/entry/node.rb index 9999ab4ff95..e014f15fbd8 100644 --- a/lib/gitlab/config/entry/node.rb +++ b/lib/gitlab/config/entry/node.rb @@ -17,6 +17,8 @@ module Gitlab @metadata = metadata @entries = {} + yield(self) if block_given? + self.class.aspects.to_a.each do |aspect| instance_exec(&aspect) end @@ -44,6 +46,12 @@ module Gitlab @parent ? @parent.ancestors + [@parent] : [] end + def opt(key) + opt = metadata[key] + opt = @parent.opt(key) if opt.nil? && @parent + opt + end + def valid? errors.none? end @@ -85,6 +93,18 @@ module Gitlab "#<#{self.class.name} #{unspecified}{#{key}: #{val.inspect}}>" end + def hash? + @config.is_a?(Hash) + end + + def string? + @config.is_a?(String) + end + + def integer? + @config.is_a?(Integer) + end + def self.default(**) end diff --git a/lib/gitlab/config/entry/simplifiable.rb b/lib/gitlab/config/entry/simplifiable.rb index 5fbf7565e2a..a56a89adb35 100644 --- a/lib/gitlab/config/entry/simplifiable.rb +++ b/lib/gitlab/config/entry/simplifiable.rb @@ -19,7 +19,10 @@ module Gitlab entry = self.class.entry_class(strategy) - super(@subject = entry.new(config, metadata)) + @subject = entry.new(config, metadata) + + yield(@subject) if block_given? + super(@subject) end def self.strategy(name, **opts) diff --git a/lib/gitlab/config/entry/validators.rb b/lib/gitlab/config/entry/validators.rb index d348e11b753..d0ee94370ba 100644 --- a/lib/gitlab/config/entry/validators.rb +++ b/lib/gitlab/config/entry/validators.rb @@ -15,6 +15,17 @@ module Gitlab end end + class DisallowedKeysValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + present_keys = value.try(:keys).to_a & options[:in] + + if present_keys.any? + record.errors.add(attribute, "contains disallowed keys: " + + present_keys.join(', ')) + end + end + end + class AllowedValuesValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) unless options[:in].include?(value.to_s) @@ -186,6 +197,97 @@ module Gitlab end end end + + class PortNamePresentAndUniqueValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + return unless value.is_a?(Array) + + ports_size = value.count + return if ports_size <= 1 + + named_ports = value.select { |e| e.is_a?(Hash) }.map { |e| e[:name] }.compact.map(&:downcase) + + if ports_size != named_ports.size + record.errors.add(attribute, 'when there is more than one port, a unique name should be added') + end + + if ports_size != named_ports.uniq.size + record.errors.add(attribute, 'each port name must be different') + end + end + end + + class PortUniqueValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + value = ports(value) + return unless value.is_a?(Array) + + ports_size = value.count + return if ports_size <= 1 + + if transform_ports(value).size != ports_size + record.errors.add(attribute, 'each port number can only be referenced once') + end + end + + private + + def ports(current_data) + current_data + end + + def transform_ports(raw_ports) + raw_ports.map do |port| + case port + when Integer + port + when Hash + port[:number] + end + end.uniq + end + end + + class JobPortUniqueValidator < PortUniqueValidator + private + + def ports(current_data) + return unless current_data.is_a?(Hash) + + (image_ports(current_data) + services_ports(current_data)).compact + end + + def image_ports(current_data) + return [] unless current_data[:image].is_a?(Hash) + + current_data.dig(:image, :ports).to_a + end + + def services_ports(current_data) + current_data.dig(:services).to_a.flat_map { |service| service.is_a?(Hash) ? service[:ports] : nil } + end + end + + class ServicesWithPortsAliasUniqueValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + current_aliases = aliases(value) + return if current_aliases.empty? + + unless aliases_unique?(current_aliases) + record.errors.add(:config, 'alias must be unique in services with ports') + end + end + + private + + def aliases(value) + value.select { |s| s.is_a?(Hash) && s[:ports] }.pluck(:alias) # rubocop:disable CodeReuse/ActiveRecord + end + + def aliases_unique?(aliases) + aliases.size == aliases.uniq.size + end + end end end end |