Class: Kontena::Cli::Stacks::YAML::ValidatorV3
- Inherits:
-
Object
- Object
- Kontena::Cli::Stacks::YAML::ValidatorV3
- Includes:
- Validations
- Defined in:
- lib/kontena/cli/stacks/yaml/validator_v3.rb
Constant Summary collapse
- KNOWN_TOP_LEVEL_KEYS =
%w( services errors volumes networks variables stack version data description expose )
Instance Method Summary collapse
-
#initialize ⇒ ValidatorV3
constructor
A new instance of ValidatorV3.
-
#parse_volume(vol) ⇒ Object
borrowed from server/app/helpers/volumes_helpers.rb.
-
#validate(yaml) ⇒ Array
Validation_errors.
Methods included from Validations
#common_validations, #optional, #validate_options, #validate_volume_options, #volume_schema
Constructor Details
#initialize ⇒ ValidatorV3
Returns a new instance of ValidatorV3.
22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/kontena/cli/stacks/yaml/validator_v3.rb', line 22 def initialize @schema = common_validations @schema['build'] = optional('stacks_valid_build') @schema['depends_on'] = optional('array') @schema['network_mode'] = optional(%w(host bridge)) @schema['logging'] = optional({ 'driver' => optional('string'), 'options' => optional(-> (value) { value.is_a?(Hash) }) }) Validations::CustomValidators.load end |
Instance Method Details
#parse_volume(vol) ⇒ Object
borrowed from server/app/helpers/volumes_helpers.rb
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/kontena/cli/stacks/yaml/validator_v3.rb', line 35 def parse_volume(vol) elements = vol.split(':') if elements.size >= 2 # Bind mount or volume used if elements[0].start_with?('/') && elements[1] && elements[1].start_with?('/') # Bind mount {bind_mount: elements[0], path: elements[1], flags: elements[2..-1].join(',')} elsif !elements[0].start_with?('/') && elements[1].start_with?('/') # Real volume {volume: elements[0], path: elements[1], flags: elements[2..-1].join(',')} else {error: "volume definition not in right format: #{vol}" } end elsif elements.size == 1 && elements[0].start_with?('/') # anon volume {bind_mount: nil, path: elements[0], flags: nil} # anon vols do not support flags else {error: "volume definition not in right format: #{vol}" } end end |
#validate(yaml) ⇒ Array
Returns validation_errors.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/kontena/cli/stacks/yaml/validator_v3.rb', line 56 def validate(yaml) result = { errors: [], notifications: [] } result[:notifications] += (yaml.keys - KNOWN_TOP_LEVEL_KEYS).map do |key| { key => "unknown top level key" } end if yaml.key?('services') if yaml['services'].is_a?(Hash) yaml['services'].each do |service, | unless .is_a?(Hash) result[:errors] << { 'services' => { service => { 'options' => "must be a mapping not a #{options.class}"} } } next end option_errors = () result[:errors] << { 'services' => { service => option_errors.errors } } unless option_errors.valid? if ['volumes'] mount_path_occurences = Hash.new(0) ['volumes'].each do |volume| parsed = parse_volume(volume) if parsed[:error] result[:errors] << { 'services' => { service => { 'volumes' => { volume => parsed[:error] } } } } elsif parsed[:path] mount_path_occurences[parsed[:path]] += 1 volume_name = parsed[:volume] if volume_name && !volume_name.start_with?('/') if yaml.key?('volumes') unless yaml['volumes'][volume_name] result[:errors] << { 'services' => { service => { 'volumes' => { volume_name => 'not found in top level volumes list' } } } } end else result[:errors] << { 'services' => { service => { 'volumes' => { volume => 'defines volume name, but file does not contain volumes definitions' } } } } end end else result[:errors] << { 'services' => { service => { 'volumes' => { volume => 'mount point missing' } } } } end end mount_path_occurences.select {|path, occurences| occurences > 1 }.each do |path, occurences| result[:errors] << { 'services' => { service => { 'volumes' => { path => "mount point defined #{occurences} times" } } } } end end end else result[:errors] << { 'services' => "must be a mapping, not #{yaml['services'].class}" } end else result[:notifications] << { 'file' => 'does not define any services' } end if yaml.key?('volumes') if yaml['volumes'].is_a?(Hash) yaml['volumes'].each do |volume, | if .is_a?(Hash) option_errors = () unless option_errors.valid? result[:errors] << { 'volumes' => { volume => option_errors.errors } } end else result[:errors] << { 'volumes' => { volume => { 'options' => "must be a mapping, not #{options.class}" } } } end end else result[:errors] << { 'volumes' => "must be a mapping, not #{yaml['volumes'].class}" } end end if yaml.key?('networks') result[:notifications] << { 'networks' => 'Kontena does not support multiple networks yet. You can reference services with Kontena\'s internal DNS (service_name.kontena.local)' } end if (yaml['volumes'].nil? || yaml['volumes'].empty?) && (yaml['services'].nil? || yaml['services'].empty?) result[:errors] << { 'file' => 'does not list any services or volumes' } end result end |