c66-copper 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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