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 =
%i( services errors volumes networks variables stack version data description expose depends labels )
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, #dependency_schema, #optional, #validate_dependencies, #validate_options, #validate_volume_options, #volume_schema
Constructor Details
#initialize ⇒ ValidatorV3
Returns a new instance of ValidatorV3.
24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/kontena/cli/stacks/yaml/validator_v3.rb', line 24 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.kind_of?(Hash) }) }) Validations::CustomValidators.load end |
Instance Method Details
#parse_volume(vol) ⇒ Object
borrowed from server/app/helpers/volumes_helpers.rb
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/kontena/cli/stacks/yaml/validator_v3.rb', line 37 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.
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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/kontena/cli/stacks/yaml/validator_v3.rb', line 58 def validate(yaml) result = { errors: [], notifications: [] } yaml.keys.each do |key| unless KNOWN_TOP_LEVEL_KEYS.include?(key) || KNOWN_TOP_LEVEL_KEYS.include?(key.to_sym) result[:notifications] << { key.to_s => "unknown top level key" } end end if yaml.key?('stack') unless yaml['stack'] =~ /\A(?:.+?\/)?(?!-)[a-z0-9\-]+\z/ result[:notifications] << { 'stack' => 'A stack name should only include a-z, 0-9 and - characters and not start with the - character' } end end if yaml.key?('services') if yaml['services'].kind_of?(Hash) yaml['services'].each do |service, | unless service =~ /\A(?!-)[a-z0-9\-]+\z/ result[:notifications] << { 'services' => { service => { 'name' => 'A service name should only include a-z, 0-9 and - characters and not start with the - character' } } } end unless .kind_of?(Hash) result[:errors] << { 'services' => { service => { 'options' => "must be a mapping not a #{.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'].kind_of?(Hash) yaml['volumes'].each do |volume, | if .kind_of?(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 #{.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 if yaml.key?('depends') unless yaml['depends'].kind_of?(Hash) result[:errors] << { 'depends' => "Must be a mapping, not #{yaml['depends'].class}" } end yaml['depends'].each do |name, | validator = validate_dependencies() result[:errors] << { 'depends' => { name => validator.errors } } unless validator.valid? if yaml.key?('services') && yaml['services'][name] result[:errors] << { 'depends' => { name => 'is defined both as service and dependency name' } } end end end result end |