c66-copper 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bb48cc101f266912993eabc1c9836ca74d693afb
4
- data.tar.gz: b13bfa681af1d729ca5185ddff419940e5921713
3
+ metadata.gz: c59a38c72a716fdcb3c7515ac9c5f54d527856e6
4
+ data.tar.gz: 1726521089a78f5678090c7dc218cccfd279502d
5
5
  SHA512:
6
- metadata.gz: b1137fb18f6e4f9ce9772056fad87741df3ecf9a47f9b61110038021bfc2b1551840644ae957e28b44b2d7fe060f543f9c35f650954806d7decdfd100412fb9c
7
- data.tar.gz: a69ea15d41f510779d435b9eb74bfad4752396d551dcbd5ee513c7b40ab0fd9263d02d35a0d745e02b195a655035c5c74a28c8b73a8d85e30e248a91ef67375f
6
+ metadata.gz: 774adf64bb740dc8974c354536912394e089144631d83d4636f9688e4bce24ddd8bf6b7f4eae3d6234dc7d31320520e16b2b4b80f9fafcb61717d3e2dd88ffc4
7
+ data.tar.gz: 17caf2de157df7ae3c7e6bb6c7dc24b35577bf76c2eba996a4542373532008f11795d0c08532a2430f224b0a8ee32d827cdac502553051a71fe7b99058b8b0b3
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Build status](https://badge.buildkite.com/94513f14bb3671f2a6cec93ea3752d1a580ca0a2cb1193e07e.svg)](https://buildkite.com/cloud-66/copper)
2
+
1
3
  # Copper
2
4
 
3
5
  ### Copper is a configuration validator for Kubernetes by Cloud 66
data/bin/copper CHANGED
@@ -18,9 +18,9 @@ module Copper
18
18
  def update
19
19
  say "Updating Copper..."
20
20
  unless options[:version]
21
- say `gem install copper --no-ri --no-rdoc`
21
+ say `gem install c66-copper --no-ri --no-rdoc`
22
22
  else
23
- say `gem install copper -v #{options[:version]} --no-ri --no-rdoc`
23
+ say `gem install c66-copper -v #{options[:version]} --no-ri --no-rdoc`
24
24
  end
25
25
  end
26
26
 
@@ -51,24 +51,28 @@ module Copper
51
51
  raise ::NotImplementedError if options[:format] != 'yaml'
52
52
  # load the yaml file and split them into separate yamls
53
53
 
54
+ failed = false
54
55
  content = File.read(content_file)
55
56
  content.split('---').each_with_index do |part, idx|
56
57
  puts "Validating part #{idx}"
57
58
  file = YAML::load(part)
58
- validate(rules, file)
59
+ failed = validate(rules, file, content_file)
59
60
  end
61
+
62
+ exit(1) if failed
60
63
  end
61
64
 
62
65
  no_commands {
63
- def validate(rules, file)
64
- ccop = ::Copper::Copper.new(rules, { context: file })
66
+ def validate(rules, file, filename)
67
+ ccop = ::Copper::Copper.new(rules, { context: file, filename: filename })
65
68
  results = ccop.execute
66
69
 
67
70
  if results.nil?
68
71
  puts "Aborting"
69
- exit
72
+ exit(2)
70
73
  end
71
74
 
75
+ failed = false
72
76
  results.each do |rule|
73
77
  action = rule[:action]
74
78
  outcome = rule[:outcome]
@@ -76,6 +80,7 @@ module Copper
76
80
  if action == :warn
77
81
  outcome_text = 'WARN'.yellow
78
82
  else
83
+ failed = true
79
84
  outcome_text = 'FAIL'.red
80
85
  end
81
86
  else
@@ -83,11 +88,15 @@ module Copper
83
88
  end
84
89
  puts "\t#{rule[:name]} - #{outcome_text}"
85
90
  end
91
+ return failed
86
92
  rescue ::Copper::ParseError => exc
87
93
  puts "Syntax error: #{exc.message} at line #{ccop.parser.failure_line}, column: #{ccop.parser.failure_column}"
94
+ return true
88
95
  rescue ::Copper::RuntimeError => exc
89
96
  puts "Runtime error: #{exc.message}"
97
+ return true
90
98
  end
99
+
91
100
  }
92
101
 
93
102
  end
@@ -1,7 +1,6 @@
1
1
  module Copper
2
2
  class AttributesRightAssociated < CopperNode
3
3
  def value(vars = {})
4
- byebug
5
4
  rhs = self.parent.elements[0].value(vars)
6
5
  lhs = self.elements[1].value(vars)
7
6
 
@@ -8,6 +8,7 @@ module Copper
8
8
 
9
9
  raise ParseError, "cannot compare nil" if rhs.nil? || lhs.nil?
10
10
 
11
+ puts "[DEBUG] Comparing #{lhs} (#{lhs.class.name}) #{comp_op} #{rhs} (#{rhs.class.name})" if $debug
11
12
  begin
12
13
  case comp_op
13
14
  when '='
@@ -46,7 +47,7 @@ module Copper
46
47
  private
47
48
 
48
49
  def equality(lhs, rhs)
49
- if lhs.is_a?(Array) && rhs.is_a?(Array)
50
+ if lhs.is_a?(::Array) && rhs.is_a?(::Array)
50
51
  return lhs.sort == rhs.sort
51
52
  else
52
53
  return lhs == rhs
data/lib/copper/copper.rb CHANGED
@@ -4,8 +4,6 @@ module Copper
4
4
  @content = content
5
5
  @vars = vars
6
6
 
7
- # add the resevered ones
8
- @vars[:variables] = ::Copper::DataTypes::DataType::RESEVERED_TYPES
9
7
  @parser = Parser.new
10
8
  end
11
9
 
@@ -5,6 +5,7 @@ module Copper
5
5
  protected
6
6
 
7
7
  def console(text)
8
+ text = text.to_s if text.respond_to?(:to_s)
8
9
  puts "[DEBUG] #{self.class.name} ==> #{text} (#{text.class.name})" if $debug
9
10
  end
10
11
 
@@ -31,6 +31,7 @@ module Copper
31
31
 
32
32
  # map the items into the given class
33
33
  def as(clazz)
34
+ clazz = clazz.capitalize
34
35
  found_class = ::Copper::DataTypes::DataType.get_class(clazz)
35
36
  return @value.map { |x| found_class.new(x).value }
36
37
  end
@@ -48,6 +49,16 @@ module Copper
48
49
  return result
49
50
  end
50
51
 
52
+ def pick(attribute)
53
+ return @value.map do |x|
54
+ if x.respond_to?(attribute.to_sym)
55
+ x.send(attribute.to_sym)
56
+ else
57
+ raise ParseError, "#{attribute} is not a valid attribute on #{x.class.name}"
58
+ end
59
+ end
60
+ end
61
+
51
62
  def unique
52
63
  @value.uniq
53
64
  end
@@ -10,15 +10,12 @@ module Copper
10
10
  "Range" => "::Copper::DataTypes::Range",
11
11
  "IPAddress" => "::Copper::DataTypes::IPAddress",
12
12
  "IPAddress::IPv4" => "::Copper::DataTypes::IPAddress",
13
- "IPAddress::IPv6" => "::Copper::DataTypes::IPAddress"
14
- }
15
-
16
- RESEVERED_TYPES = {
17
- semver: "Semver",
18
- array: "Array",
19
- string: "String",
20
- range: "Range",
21
- ipaddr: "IPAddress"
13
+ "IPAddress::IPv6" => "::Copper::DataTypes::IPAddress",
14
+ "Copper::DataTypes::Image" => "::Copper::DataTypes::Image",
15
+ "Image" => "::Copper::DataTypes::Image",
16
+ "Copper::DataTypes::ImageClass" => "::Copper::DataTypes::Image",
17
+ "Copper::DataTypes::FilenameClass" => "::Copper::DataTypes::Filename",
18
+ "Copper::DataTypes::Filename" => "::Copper::DataTypes::Filename"
22
19
  }
23
20
 
24
21
  def initialize(value)
@@ -30,6 +27,7 @@ module Copper
30
27
  end
31
28
 
32
29
  def as(clazz)
30
+ clazz = clazz.capitalize
33
31
  found_class = ::Copper::DataTypes::DataType.get_class(clazz)
34
32
  return found_class.new(@value).value
35
33
  end
@@ -44,7 +42,7 @@ module Copper
44
42
  end
45
43
 
46
44
  def self.get_class(class_name)
47
- raise RuntimeError, "unknown return value #{class_name}" unless ::Copper::DataTypes::DataType::CLASS_MAP.has_key?(class_name)
45
+ raise RuntimeError, "unknown class #{class_name}" unless ::Copper::DataTypes::DataType::CLASS_MAP.has_key?(class_name)
48
46
  return Module.const_get(::Copper::DataTypes::DataType::CLASS_MAP[class_name])
49
47
  rescue NameError => exc
50
48
  raise ::Copper::RuntimeError, "invalid return type #{class_name}"
@@ -0,0 +1,52 @@
1
+ module Copper
2
+ module DataTypes
3
+ class Filename < DataType
4
+
5
+ def initialize(value)
6
+ if value.is_a?(::String)
7
+ @value = FilenameClass.new(value)
8
+ else
9
+ @value = value
10
+ end
11
+ end
12
+
13
+ def path
14
+ @value.path
15
+ end
16
+
17
+ def name
18
+ @value.name
19
+ end
20
+
21
+ def ext
22
+ @value.ext
23
+ end
24
+
25
+ def full_name
26
+ "#{@value.path}/#{@value.name}#{@value.ext}"
27
+ end
28
+
29
+ def expanded_path
30
+ @value.expanded_path
31
+ end
32
+ end
33
+
34
+ class FilenameClass
35
+ attr_accessor :ext
36
+ attr_accessor :name
37
+ attr_accessor :path
38
+ attr_accessor :expanded_path
39
+
40
+ def initialize(filename)
41
+ @expanded_path = File.expand_path(filename)
42
+ @ext = File.extname(filename)
43
+ @name = File.basename(filename, @ext)
44
+ @path = File.dirname(filename)
45
+ end
46
+
47
+ def to_s
48
+ "path:#{@paht}, name:#{@name}, ext:#{@ext}"
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,109 @@
1
+ module Copper
2
+ module DataTypes
3
+ class Image < DataType
4
+
5
+ def initialize(value)
6
+ if value.is_a?(::String)
7
+ @value = deconstruct_image(value)
8
+ else
9
+ @value = value
10
+ end
11
+ end
12
+
13
+ def to_s
14
+ @value.to_s
15
+ end
16
+
17
+ def registry
18
+ @value[:registry]
19
+ end
20
+
21
+ def name
22
+ @value[:name]
23
+ end
24
+
25
+ def tag
26
+ @value[:tag]
27
+ end
28
+
29
+ def registry_url
30
+ @value[:registry_url]
31
+ end
32
+
33
+ def fqin
34
+ @value[:fqin]
35
+ end
36
+
37
+ private
38
+
39
+ def deconstruct_image(source_image)
40
+ full_image = source_image.strip
41
+ full_name = "library/#{full_image}" unless full_image.include?('/')
42
+ full_image = "library/#{full_image}" unless full_image.include?('/')
43
+ full_image = "#{full_image}:latest" unless full_image.include?(':')
44
+
45
+ # default
46
+ proto = 'https://'
47
+ if full_image =~ /^https/
48
+ proto = 'https://'
49
+ full_image = full_image.gsub(/https:\/\//, '')
50
+ elsif full_image =~ /^http/
51
+ proto = 'http://'
52
+ full_image = full_image.gsub(/http:\/\//, '')
53
+ end
54
+
55
+ # trim / from front and back
56
+ full_image = full_image.gsub(/^\//, '').gsub(/\/$/, '')
57
+
58
+ # figure out registry
59
+ if full_image =~ /^library\// || full_image.split('/').count < 3
60
+ # its docker io
61
+ registry = 'index.docker.io'
62
+ else
63
+ registry = full_image.gsub(/\/.*/, '')
64
+ end
65
+
66
+ # figure out image name
67
+ full_image = full_image.gsub(/#{registry}(\/(v|V)(1|2)|)/i,'').gsub(/^\//, '').gsub(/\/$/, '')
68
+ image_parts = full_image.split(':')
69
+ image_name = image_parts[0]
70
+ image_tag = image_parts[1]
71
+
72
+ # recombine for registry
73
+ registry_url = "#{proto}#{registry}"
74
+
75
+ fqin = "#{registry_url}/#{full_image}"
76
+
77
+ # return information
78
+ return ImageClass.new({
79
+ fqin: fqin,
80
+ registry: registry,
81
+ registry_url: registry_url,
82
+ name: image_name,
83
+ tag: image_tag
84
+ })
85
+ end
86
+
87
+ end
88
+
89
+ class ImageClass
90
+ attr_accessor :fqin
91
+ attr_accessor :registry
92
+ attr_accessor :registry_url
93
+ attr_accessor :name
94
+ attr_accessor :tag
95
+
96
+ def initialize(hash)
97
+ @fqin = hash[:fqin]
98
+ @registry = hash[:registry]
99
+ @registry_url = hash[:registry_url]
100
+ @name = hash[:name]
101
+ @tag = hash[:tag]
102
+ end
103
+
104
+ def to_s
105
+ "fqin:#{fqin}, registry:#{registry}, registry_url:#{registry_url}, name:#{name}, tag:#{tag}"
106
+ end
107
+ end
108
+ end
109
+ end
@@ -10,6 +10,10 @@ module Copper
10
10
  return @value.gsub(pattern, replacement)
11
11
  end
12
12
 
13
+ def split(separator)
14
+ return @value.split(separator)
15
+ end
16
+
13
17
  def at(index)
14
18
  if index >= @value.size
15
19
  raise ParseError, "index #{index} out of bound [0..#{@result.size - 1}]"
@@ -0,0 +1,16 @@
1
+ module Copper
2
+ module Functions
3
+ class Filename < CopperNode
4
+
5
+ include ::Copper::ExpressionUtils
6
+
7
+ def value(vars = {})
8
+ filename = vars[:filename]
9
+ result = ::Copper::DataTypes::Filename.new(filename)
10
+
11
+ return handle_attributes(result, vars)
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ require 'ipaddress'
2
+
3
+ module Copper
4
+ module Functions
5
+ class Image < CopperNode
6
+
7
+ include ::Copper::ExpressionUtils
8
+
9
+ def value(vars = {})
10
+ image = elements[0].value(vars)
11
+ result = ::Copper::DataTypes::Image.new(image)
12
+
13
+ return handle_attributes(result, vars)
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -11,6 +11,8 @@ module Copper
11
11
  result = ::IPAddress.parse(ipaddress)
12
12
 
13
13
  return handle_attributes(result, vars)
14
+ rescue ArgumentError => exc
15
+ raise RuntimeError, exc.message
14
16
  end
15
17
 
16
18
  end
@@ -0,0 +1,18 @@
1
+ require 'ipaddress'
2
+
3
+ module Copper
4
+ module Functions
5
+ class Semver < CopperNode
6
+
7
+ include ::Copper::ExpressionUtils
8
+
9
+ def value(vars = {})
10
+ semver = elements[0].value(vars)
11
+ result = ::Semantic::Version.new(semver)
12
+
13
+ return handle_attributes(result, vars)
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -37,7 +37,7 @@ grammar Copper
37
37
  end
38
38
 
39
39
  rule expression
40
- s (string / number / boolean / func / variable / set / range) <Expression>
40
+ s (string / number / boolean / func / variable / set / range / symbol) <Expression>
41
41
  end
42
42
 
43
43
  rule logic_right_associated
@@ -65,7 +65,7 @@ grammar Copper
65
65
  end
66
66
 
67
67
  rule func
68
- (fetch_func / func_ipaddress)
68
+ (fetch_func / func_ipaddress / func_semver / func_image / func_filename)
69
69
  end
70
70
 
71
71
  rule fetch_func
@@ -76,6 +76,18 @@ grammar Copper
76
76
  'ipaddress' s '(' (string / variable) s ')' (attributes)? <Functions::IPAddress>
77
77
  end
78
78
 
79
+ rule func_semver
80
+ 'semver' s '(' (string / variable) s ')' (attributes)? <Functions::Semver>
81
+ end
82
+
83
+ rule func_image
84
+ 'image' s '(' (string / variable) s ')' (attributes)? <Functions::Image>
85
+ end
86
+
87
+ rule func_filename
88
+ 'filename' (attributes)? <Functions::Filename>
89
+ end
90
+
79
91
  rule attributes
80
92
  sn '.' attribute (attributes_right_associated)? <Attributes>
81
93
  end
@@ -120,6 +132,10 @@ grammar Copper
120
132
  [0-9]+ <Number>
121
133
  end
122
134
 
135
+ rule symbol
136
+ ':' ([a-z] [a-z0-9_]*) <Symbol>
137
+ end
138
+
123
139
  rule comp_op
124
140
  '<=' <CompOp>
125
141
  / '>=' <CompOp>
@@ -0,0 +1,7 @@
1
+ module Copper
2
+ class Symbol < CopperNode
3
+ def value(vars = {})
4
+ return text_value[1..-1]
5
+ end
6
+ end
7
+ end
@@ -1,5 +1,5 @@
1
1
  module Copper
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  COPYRIGHT_MESSAGE = "(c) 2018 Cloud66 Inc."
4
4
  APP_NAME = 'Copper'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: c66-copper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Khash Sajadi
@@ -191,6 +191,8 @@ files:
191
191
  - lib/copper/copper_node.rb
192
192
  - lib/copper/data_types/array.rb
193
193
  - lib/copper/data_types/data_type.rb
194
+ - lib/copper/data_types/filename.rb
195
+ - lib/copper/data_types/image.rb
194
196
  - lib/copper/data_types/ip_addr.rb
195
197
  - lib/copper/data_types/range.rb
196
198
  - lib/copper/data_types/semver.rb
@@ -199,7 +201,10 @@ files:
199
201
  - lib/copper/expression.rb
200
202
  - lib/copper/expression_utils.rb
201
203
  - lib/copper/functions/fetch.rb
204
+ - lib/copper/functions/filename.rb
205
+ - lib/copper/functions/image.rb
202
206
  - lib/copper/functions/ip_address.rb
207
+ - lib/copper/functions/semver.rb
203
208
  - lib/copper/grammar/copper.treetop
204
209
  - lib/copper/identifier.rb
205
210
  - lib/copper/loader.rb
@@ -216,6 +221,7 @@ files:
216
221
  - lib/copper/set.rb
217
222
  - lib/copper/single_var_definition.rb
218
223
  - lib/copper/string.rb
224
+ - lib/copper/symbol.rb
219
225
  - lib/copper/var_definition.rb
220
226
  - lib/copper/variable.rb
221
227
  - lib/copper/variable_identifier.rb