skull_island 1.2.0 → 1.2.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
  SHA256:
3
- metadata.gz: 67a8f014f5c284c8fe9a8201fa1296130abb88a08b52e8f512e935eb178bb337
4
- data.tar.gz: ed28d0b9011b978e0939ae7ba73b8934d147f77df0ebee8f6a38464f6ed12440
3
+ metadata.gz: 782471de2e1ce1e974ac22f0420d33ce0903f909b4286094537c7169caa872f5
4
+ data.tar.gz: 7edb2bcdb5094f27932c2a3e13f6865e969ba6f43e78f34d6a26c7416cb01bc9
5
5
  SHA512:
6
- metadata.gz: e63e8b8e203f408df32846e4aec20cbbcea5ac7688ef2ec06db386c9e1f7f88a13094706dcb2b12dba98639c25d9488209ff6b6ce6b9ce60af3c2237bd39f1b0
7
- data.tar.gz: e150792100e0b64286c7dee6338bf723aa0f2e88487bc9f5846485e410e57207504c974b7e861dc366082e849bea1b845a20d00cf9250951db46da62cc05ce5d
6
+ metadata.gz: 6a83f0d13f17f858332882836b22be450c9974283c9e1a8fe0db20b007f13b080a73d4c9fe43bc3516a2a2a5768821f1a4b7494bf9262874774a63c9feb78068
7
+ data.tar.gz: 7dc758ebad1c39cbaa8b64789ac0ff7db061349cd0a086a2d50cfedf2cf822e6d8745d92a1a976d63f7398b810f7ca634bf46b7f2408709c33b8cbf2a18131d0
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
12
  *.gem
13
+ .DS_Store
@@ -8,7 +8,7 @@ Metrics/LineLength:
8
8
  Max: 100
9
9
 
10
10
  Metrics/ClassLength:
11
- Max: 175
11
+ Max: 190
12
12
 
13
13
  Metrics/ModuleLength:
14
14
  Max: 175
@@ -23,7 +23,7 @@ Metrics/PerceivedComplexity:
23
23
  - 'lib/skull_island/cli.rb'
24
24
 
25
25
  Metrics/AbcSize:
26
- Max: 27
26
+ Max: 28
27
27
 
28
28
  Metrics/BlockLength:
29
29
  Max: 35
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- skull_island (1.2.0)
4
+ skull_island (1.2.2)
5
5
  deepsort (~> 0.4)
6
6
  erubi (~> 1.8)
7
7
  json (~> 2.1)
@@ -15,11 +15,11 @@ GEM
15
15
  specs:
16
16
  addressable (2.4.0)
17
17
  ast (2.4.0)
18
- backports (3.12.0)
19
- deepsort (0.4.1)
18
+ backports (3.15.0)
19
+ deepsort (0.4.2)
20
20
  diff-lcs (1.3)
21
- docile (1.3.1)
22
- domain_name (0.5.20180417)
21
+ docile (1.3.2)
22
+ domain_name (0.5.20190701)
23
23
  unf (>= 0.0.5, < 1.0.0)
24
24
  erubi (1.8.0)
25
25
  ethon (0.12.0)
@@ -28,7 +28,7 @@ GEM
28
28
  multipart-post (>= 1.2, < 3)
29
29
  faraday_middleware (0.13.1)
30
30
  faraday (>= 0.7.4, < 1.0)
31
- ffi (1.10.0)
31
+ ffi (1.11.1)
32
32
  gh (0.15.1)
33
33
  addressable (~> 2.4.0)
34
34
  backports
@@ -39,7 +39,7 @@ GEM
39
39
  highline (1.7.10)
40
40
  http-cookie (1.0.3)
41
41
  domain_name (~> 0.5)
42
- jaro_winkler (1.5.2)
42
+ jaro_winkler (1.5.3)
43
43
  json (2.2.0)
44
44
  launchy (2.4.3)
45
45
  addressable (~> 2.3)
@@ -50,15 +50,13 @@ GEM
50
50
  mime-types-data (~> 3.2015)
51
51
  mime-types-data (3.2019.0331)
52
52
  multi_json (1.13.1)
53
- multipart-post (2.0.0)
53
+ multipart-post (2.1.1)
54
54
  net-http-persistent (2.9.4)
55
55
  net-http-pipeline (1.0.1)
56
56
  netrc (0.11.0)
57
- parallel (1.14.0)
58
- parser (2.6.0.0)
57
+ parallel (1.17.0)
58
+ parser (2.6.3.0)
59
59
  ast (~> 2.4.0)
60
- powerpack (0.1.2)
61
- psych (3.1.0)
62
60
  pusher-client (0.6.2)
63
61
  json
64
62
  websocket (~> 1.0)
@@ -72,32 +70,30 @@ GEM
72
70
  rspec-core (~> 3.8.0)
73
71
  rspec-expectations (~> 3.8.0)
74
72
  rspec-mocks (~> 3.8.0)
75
- rspec-core (3.8.0)
73
+ rspec-core (3.8.2)
76
74
  rspec-support (~> 3.8.0)
77
- rspec-expectations (3.8.2)
75
+ rspec-expectations (3.8.4)
78
76
  diff-lcs (>= 1.2.0, < 2.0)
79
77
  rspec-support (~> 3.8.0)
80
- rspec-mocks (3.8.0)
78
+ rspec-mocks (3.8.1)
81
79
  diff-lcs (>= 1.2.0, < 2.0)
82
80
  rspec-support (~> 3.8.0)
83
- rspec-support (3.8.0)
84
- rubocop (0.65.0)
81
+ rspec-support (3.8.2)
82
+ rubocop (0.74.0)
85
83
  jaro_winkler (~> 1.5.1)
86
84
  parallel (~> 1.10)
87
- parser (>= 2.5, != 2.5.1.1)
88
- powerpack (~> 0.1)
89
- psych (>= 3.1.0)
85
+ parser (>= 2.6)
90
86
  rainbow (>= 2.2.2, < 4.0)
91
87
  ruby-progressbar (~> 1.7)
92
- unicode-display_width (~> 1.4.0)
93
- ruby-progressbar (1.10.0)
94
- simplecov (0.16.1)
88
+ unicode-display_width (>= 1.4.0, < 1.7)
89
+ ruby-progressbar (1.10.1)
90
+ simplecov (0.17.0)
95
91
  docile (~> 1.1)
96
92
  json (>= 1.8, < 3)
97
93
  simplecov-html (~> 0.10.0)
98
94
  simplecov-html (0.10.2)
99
95
  thor (0.20.3)
100
- travis (1.8.9)
96
+ travis (1.8.10)
101
97
  backports
102
98
  faraday (~> 0.9)
103
99
  faraday_middleware (~> 0.9, >= 0.9.1)
@@ -110,11 +106,11 @@ GEM
110
106
  ethon (>= 0.8.0)
111
107
  unf (0.1.4)
112
108
  unf_ext
113
- unf_ext (0.0.7.5)
114
- unicode-display_width (1.4.1)
109
+ unf_ext (0.0.7.6)
110
+ unicode-display_width (1.6.0)
115
111
  websocket (1.2.8)
116
112
  will_paginate (3.1.7)
117
- yard (0.9.18)
113
+ yard (0.9.20)
118
114
 
119
115
  PLATFORMS
120
116
  ruby
@@ -127,7 +123,7 @@ DEPENDENCIES
127
123
  simplecov (~> 0.15)
128
124
  skull_island!
129
125
  travis (~> 1.8)
130
- yard (~> 0.9)
126
+ yard (~> 0.9.20)
131
127
 
132
128
  BUNDLED WITH
133
129
  2.0.1
data/README.md CHANGED
@@ -81,6 +81,8 @@ KONG_ADMIN_URL='https://api-admin.mydomain.com' \
81
81
  skull_island export --verbose /path/to/export.yml
82
82
  ```
83
83
 
84
+ Exporting, by default, exports the entire configuration of a Kong gateway, but will strip out special meta-data tags added by Skull Island to track projects. If, instead, you'd like to export **only** the configuration for a specific project, you can add `--project foo` (where `foo` is the name of your project) to export only those resources associated with it and maintain the special key in the exported YAML.
85
+
84
86
  ### Importing
85
87
 
86
88
  Skull Island also supports importing configurations (both partial and full) from a YAML + ERB document:
@@ -112,6 +114,16 @@ KONG_ADMIN_URL='https://api-admin.mydomain.com' \
112
114
  skull_island import --verbose --test /path/to/export.yml
113
115
  ```
114
116
 
117
+ Note that `--test` has a high likelihood of generating errors with a complicated import if required/dependent resources do not exist.
118
+
119
+ #### Importing with Projects
120
+
121
+ Skull Island 1.2.1 introduces the ability to use a special top-level key in the configuration called `project` that uses meta-data to track which resources belong to a project. This meta-data can safely be added at another time as this tool will "adopt" otherwise matching resources into a project.
122
+
123
+ To use this functionality, either add the `project` key to your configuration file (usually directly below the `version` key) with some value that will be unique on your gateway, or use `--project foo` (where `foo` is the name of your project) as a CLI flag.
124
+
125
+ When using the `project` feature of Skull Island, the CLI tool will automatically clean up old resources no longer found in your config file. This is, in fact, the _only_ circumstance under which this tool actually removes resources. Use this feature with care, as it can delete large swaths of your configuration if used incorrectly. It is **critical** that this value is unique since this project functionality is used to delete resources.
126
+
115
127
  ### Migrating
116
128
 
117
129
  With Skull Island, it is possible to migrate a configuration from a 0.14.x gateway to one compatible with a 1.2.x gateway. If you have a previous export, you can just run `skull_island migrate /path/to/export.yml` and you'll receive a 1.2 compatible config on standard out. If you'd prefer, you can have that config written to a file as well (just like the export command) like so:
@@ -133,6 +145,7 @@ The import/export/migrate CLI functions produce YAML with support for embedded R
133
145
  ```yaml
134
146
  ---
135
147
  version: '1.2'
148
+ project: FooV2
136
149
  certificates: []
137
150
  consumers:
138
151
  - username: foo
@@ -190,7 +203,7 @@ plugins:
190
203
  service: "<%= lookup :service, 'search_api' %>"
191
204
  ```
192
205
 
193
- All top-level keys (other than `version`) require an Array as a parameter, either by providing a list of entries or an empty Array (`[]`). The above shows how to use the `lookup()` function to refer to another resource. This "looks up" the resource type (`service` in this case) by `name` (`search_api` in this case) and resolves its `id`. This function can also be used to lookup a `route` or `upstream` by its `name`, or a `consumer` by its `username`. Note that Kong itself doesn't _require_ `route` resources to have unique names, so you'll need to enforce that practice yourself for `lookup` to be useful for Routes.
206
+ All top-level keys (other than `version` and `project`) require an Array as a parameter, either by providing a list of entries or an empty Array (`[]`). The above shows how to use the `lookup()` function to refer to another resource. This "looks up" the resource type (`service` in this case) by `name` (`search_api` in this case) and resolves its `id`. This function can also be used to lookup a `route` or `upstream` by its `name`, or a `consumer` by its `username`. Note that Kong itself doesn't _require_ `route` resources to have unique names, so you'll need to enforce that practice yourself for `lookup` to be useful for Routes.
194
207
 
195
208
  While technically _any_ Ruby is valid, the following are pretty helpful for templating your YAML files:
196
209
 
@@ -39,6 +39,7 @@ require 'skull_island/api_client_base'
39
39
  require 'skull_island/api_client'
40
40
  require 'skull_island/simple_api_client'
41
41
  require 'skull_island/resource_collection'
42
+ require 'skull_island/helpers/meta'
42
43
  require 'skull_island/helpers/resource'
43
44
  require 'skull_island/helpers/resource_class'
44
45
  require 'skull_island/helpers/migration'
@@ -67,6 +67,12 @@ module SkullIsland
67
67
  end
68
68
  end
69
69
 
70
+ def delete(uri)
71
+ client_action do |client|
72
+ client[uri].delete(json_headers)
73
+ end
74
+ end
75
+
70
76
  private
71
77
 
72
78
  def client_action
@@ -15,9 +15,10 @@ module SkullIsland
15
15
  class_option :verbose, type: :boolean
16
16
 
17
17
  desc 'export [OPTIONS] [OUTPUT|-]', 'Export the current configuration to OUTPUT'
18
+ option :project, desc: 'Project identifier for metadata'
18
19
  def export(output_file = '-')
19
20
  if output_file == '-'
20
- STDERR.puts '[INFO] Outputting to STDOUT' if options['verbose']
21
+ warn '[INFO] Outputting to STDOUT' if options['verbose']
21
22
  else
22
23
  full_filename = File.expand_path(output_file)
23
24
  dirname = File.dirname(full_filename)
@@ -29,6 +30,7 @@ module SkullIsland
29
30
  validate_server_version
30
31
 
31
32
  output = { 'version' => '1.2' }
33
+ output['project'] = options['project'] if options['project']
32
34
 
33
35
  [
34
36
  Resources::Certificate,
@@ -46,6 +48,7 @@ module SkullIsland
46
48
  end
47
49
 
48
50
  desc 'import [OPTIONS] [INPUT|-]', 'Import a configuration from INPUT'
51
+ option :project, desc: 'Project identifier for metadata'
49
52
  option :test, type: :boolean, desc: "Don't do anything, just show what would happen"
50
53
  def import(input_file = '-')
51
54
  raw ||= acquire_input(input_file, options['verbose'])
@@ -56,19 +59,23 @@ module SkullIsland
56
59
 
57
60
  validate_config_version input['version']
58
61
 
62
+ import_time = Time.now.utc.to_i
63
+ input['project'] = options['project'] if options['project']
64
+
59
65
  [
60
66
  Resources::Certificate,
61
67
  Resources::Consumer,
62
68
  Resources::Upstream,
63
69
  Resources::Service,
64
70
  Resources::Plugin
65
- ].each { |clname| import_class(clname, input) }
71
+ ].each { |clname| import_class(clname, input, import_time) }
66
72
  end
67
73
 
68
74
  desc(
69
75
  'migrate [OPTIONS] [INPUT|-] [OUTPUT|-]',
70
76
  'Migrate an older config from INPUT to OUTPUT'
71
77
  )
78
+ option :project, desc: 'Project identifier for metadata'
72
79
  def migrate(input_file = '-', output_file = '-')
73
80
  raw ||= acquire_input(input_file, options['verbose'])
74
81
 
@@ -79,9 +86,10 @@ module SkullIsland
79
86
  validate_migrate_version input['version']
80
87
 
81
88
  output = migrate_config(input)
89
+ output['project'] = options['project'] if options['project']
82
90
 
83
91
  if output_file == '-'
84
- STDERR.puts '[INFO] Outputting to STDOUT' if options['verbose']
92
+ warn '[INFO] Outputting to STDOUT' if options['verbose']
85
93
  STDOUT.puts output.to_yaml
86
94
  else
87
95
  full_filename = File.expand_path(output_file)
@@ -97,23 +105,30 @@ module SkullIsland
97
105
  private
98
106
 
99
107
  def export_class(class_name, output_data)
100
- STDERR.puts "[INFO] Processing #{class_name.route_key}" if options['verbose']
101
- output_data[class_name.route_key] = class_name.all.collect(&:export)
108
+ warn "[INFO] Processing #{class_name.route_key}" if options['verbose']
109
+ output_data[class_name.route_key] = if options['project']
110
+ class_name.where(:project, options['project'])
111
+ .collect(&:export)
112
+ else
113
+ class_name.all.collect(&:export)
114
+ end
102
115
  end
103
116
 
104
- def import_class(class_name, import_data)
105
- STDERR.puts "[INFO] Processing #{class_name.route_key}" if options['verbose']
117
+ def import_class(class_name, import_data, import_time)
118
+ warn "[INFO] Processing #{class_name.route_key}" if options['verbose']
106
119
  class_name.batch_import(
107
120
  import_data[class_name.route_key],
108
121
  verbose: options['verbose'],
109
- test: options['test']
122
+ test: options['test'],
123
+ time: import_time,
124
+ project: import_data['project']
110
125
  )
111
126
  end
112
127
 
113
128
  # Used to pull input from either STDIN or the specified file
114
129
  def acquire_input(input_file, verbose = false)
115
130
  if input_file == '-'
116
- STDERR.puts '[INFO] Reading from STDIN' if verbose
131
+ warn '[INFO] Reading from STDIN' if verbose
117
132
  STDIN.read
118
133
  else
119
134
  full_filename = File.expand_path(input_file)
@@ -133,10 +148,10 @@ module SkullIsland
133
148
  if version && ['1.1', '1.2'].include?(version)
134
149
  validate_server_version
135
150
  elsif version && ['0.14', '1.0'].include?(version)
136
- STDERR.puts '[CRITICAL] Config version is too old. Try `migrate` instead of `import`.'
151
+ warn '[CRITICAL] Config version is too old. Try `migrate` instead of `import`.'
137
152
  exit 2
138
153
  else
139
- STDERR.puts '[CRITICAL] Config version is unknown or not supported.'
154
+ warn '[CRITICAL] Config version is unknown or not supported.'
140
155
  exit 3
141
156
  end
142
157
  end
@@ -145,7 +160,7 @@ module SkullIsland
145
160
  if version && version == '0.14'
146
161
  true
147
162
  else
148
- STDERR.puts '[CRITICAL] Config version must be 0.14 for migration.'
163
+ warn '[CRITICAL] Config version must be 0.14 for migration.'
149
164
  exit 4
150
165
  end
151
166
  end
@@ -155,7 +170,7 @@ module SkullIsland
155
170
  if server_version.match?(/^1.[12]/)
156
171
  true
157
172
  else
158
- STDERR.puts '[CRITICAL] Server version mismatch!'
173
+ warn '[CRITICAL] Server version mismatch!'
159
174
  exit 1
160
175
  end
161
176
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SkullIsland
4
+ module Helpers
5
+ # Useful for embedding meta-data into special tags
6
+ module Meta
7
+ def add_meta(key, value)
8
+ metatag = "_meta~#{key}~#{value}"
9
+
10
+ # filter out any existing duplicate metatags
11
+ existing_tags = raw_tags.reject { |tag| tag.start_with?("_meta~#{key}~") }
12
+
13
+ # Add the new tag directly, bypassing preprocessing
14
+ raw_set('tags', existing_tags + [metatag])
15
+ end
16
+
17
+ def import_time
18
+ metatags['import_time']
19
+ end
20
+
21
+ def import_time=(time)
22
+ add_meta('import_time', time)
23
+ end
24
+
25
+ def remove_meta(key)
26
+ # filter out an existing metatags
27
+ filtered_tags = raw_tags.reject { |tag| tag.start_with?("_meta~#{key}~") }
28
+
29
+ # Bypassing preprocessing
30
+ raw_set('tags', filtered_tags)
31
+ end
32
+
33
+ def metatags
34
+ metadata = {}
35
+ raw_tags.select { |tag| tag.start_with?('_meta~') }.each do |tag|
36
+ key, value = tag.gsub('_meta~', '').split('~', 2)
37
+ metadata[key] = value
38
+ end
39
+ metadata
40
+ end
41
+
42
+ def project
43
+ metatags['project']
44
+ end
45
+
46
+ def project=(project_id)
47
+ unless project_id.is_a?(String) && project_id.match?(/^[\w_\-\.~]+$/)
48
+ raise Exceptions::InvalidArguments, 'project'
49
+ end
50
+
51
+ add_meta('project', project_id)
52
+ end
53
+
54
+ def raw_tags
55
+ reload if @lazy && !@entity.key?('tags')
56
+ @entity['tags'] || []
57
+ end
58
+
59
+ def preprocess_tags(input)
60
+ input.uniq + metatags.map { |k, v| "_meta~#{k}~#{v}" }
61
+ end
62
+
63
+ def postprocess_tags(value)
64
+ (value || []).reject { |tag| tag.start_with?('_meta~') }
65
+ end
66
+
67
+ def supports_meta?
68
+ true
69
+ end
70
+ end
71
+ end
72
+ end
@@ -30,12 +30,13 @@ module SkullIsland
30
30
 
31
31
  def digest
32
32
  Digest::MD5.hexdigest(
33
- digest_properties.sort.map { |prop| "#{prop}=#{send(prop.to_sym)}" }.compact.join(':')
33
+ digest_properties.sort.map { |prp| "#{prp}=#{send(prp.to_sym) || ''}" }.compact.join(':')
34
34
  )
35
35
  end
36
36
 
37
37
  def digest_properties
38
- properties.keys.reject { |k| %i[created_at updated_at].include? k }
38
+ props = properties.keys.reject { |k| %i[created_at updated_at].include? k }
39
+ supports_meta? ? props + [:project] : props
39
40
  end
40
41
 
41
42
  # Tests for an existing version of this resource based on its properties rather than its `id`
@@ -45,8 +46,8 @@ module SkullIsland
45
46
  entity_data = @api_client.cache(result.first.relative_uri.to_s) do |client|
46
47
  client.get(result.first.relative_uri.to_s)
47
48
  end
48
- @entity = entity_data
49
- @lazy = false
49
+ @entity = entity_data
50
+ @lazy = false
50
51
  @tainted = false
51
52
  true
52
53
  else
@@ -172,8 +173,8 @@ module SkullIsland
172
173
  entity_data = @api_client.cache(relative_uri.to_s) do |client|
173
174
  client.get(relative_uri.to_s)
174
175
  end
175
- @entity = entity_data
176
- @lazy = false
176
+ @entity = entity_data
177
+ @lazy = false
177
178
  @tainted = false
178
179
  true
179
180
  end
@@ -199,6 +200,10 @@ module SkullIsland
199
200
  self.class.relative_uri
200
201
  end
201
202
 
203
+ def supports_meta?
204
+ false
205
+ end
206
+
202
207
  # ActiveRecord ActiveModel compatibility method
203
208
  def update(params)
204
209
  new_params = {}
@@ -179,6 +179,13 @@ module SkullIsland
179
179
  )
180
180
  end
181
181
 
182
+ def self.cleanup_except(project, keep_these)
183
+ where(:project, project).reject { |res| keep_these.include?(res.id) }.map do |res|
184
+ puts "[WARN] ! Removing #{name} (#{res.id})"
185
+ res.destroy
186
+ end
187
+ end
188
+
182
189
  def initialize(options = {})
183
190
  # TODO: better options validations
184
191
  raise Exceptions::InvalidOptions unless options.is_a?(Hash)
@@ -207,5 +214,17 @@ module SkullIsland
207
214
  def relative_uri
208
215
  "#{self.class.relative_uri}/#{id}"
209
216
  end
217
+
218
+ private
219
+
220
+ # A way to add things _without_ preprocessing them
221
+ def raw_set(key, value)
222
+ raise Exceptions::ImmutableModification if immutable?
223
+
224
+ @entity[key.to_s] = value
225
+
226
+ @modified_properties << key.to_sym
227
+ @tainted = true
228
+ end
210
229
  end
211
230
  end
@@ -18,13 +18,18 @@ module SkullIsland
18
18
  def self.batch_import(data, verbose: false, test: false)
19
19
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
20
20
 
21
+ known_ids = []
22
+
21
23
  data.each_with_index do |resource_data, index|
22
24
  resource = new
23
- resource.username = resource_data['username']
24
- resource.password = resource_data['password'] if resource_data['password']
25
+ resource.delayed_set(:username, resource_data, 'username')
26
+ resource.delayed_set(:password, resource_data, 'password') if resource_data['password']
25
27
  resource.delayed_set(:consumer, resource_data, 'consumer')
26
28
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
29
+ known_ids << resource.id
27
30
  end
31
+
32
+ known_ids
28
33
  end
29
34
 
30
35
  def self.relative_uri
@@ -56,6 +61,10 @@ module SkullIsland
56
61
  false
57
62
  end
58
63
 
64
+ def project
65
+ consumer ? consumer.project : nil
66
+ end
67
+
59
68
  private
60
69
 
61
70
  def postprocess_consumer(value)
@@ -7,29 +7,42 @@ module SkullIsland
7
7
  #
8
8
  # @see https://docs.konghq.com/1.1.x/admin-api/#certificate-object Certificate API definition
9
9
  class Certificate < Resource
10
+ include Helpers::Meta
11
+
10
12
  property :cert, required: true, validate: true
11
13
  property :key, required: true, validate: true
12
14
  property :snis, validate: true
13
15
  property :created_at, read_only: true, postprocess: true
14
- property :tags, validate: true
16
+ property :tags, validate: true, preprocess: true, postprocess: true
15
17
 
16
- def self.batch_import(data, verbose: false, test: false)
18
+ # rubocop:disable Metrics/CyclomaticComplexity
19
+ # rubocop:disable Metrics/PerceivedComplexity
20
+ def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
17
21
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
18
22
 
23
+ known_ids = []
24
+
19
25
  data.each_with_index do |resource_data, index|
20
26
  resource = new
21
- resource.cert = resource_data['cert']
22
- resource.key = resource_data['key']
27
+ resource.delayed_set(:cert, resource_data, 'cert')
28
+ resource.delayed_set(:key, resource_data, 'key')
23
29
  resource.snis = resource_data['snis'] if resource_data['snis']
24
30
  resource.tags = resource_data['tags'] if resource_data['tags']
31
+ resource.project = project if project
32
+ resource.import_time = (time || Time.now.utc.to_i) if project
25
33
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
34
+ known_ids << resource.id
26
35
  end
36
+
37
+ cleanup_except(project, known_ids) if project
27
38
  end
39
+ # rubocop:enable Metrics/CyclomaticComplexity
40
+ # rubocop:enable Metrics/PerceivedComplexity
28
41
 
29
42
  def export(options = {})
30
43
  hash = { 'cert' => cert, 'key' => key }
31
44
  hash['snis'] = snis if snis && !snis.empty?
32
- hash['tags'] = tags if tags
45
+ hash['tags'] = tags unless tags.empty?
33
46
  [*options[:exclude]].each do |exclude|
34
47
  hash.delete(exclude.to_s)
35
48
  end
@@ -7,22 +7,33 @@ module SkullIsland
7
7
  #
8
8
  # @see https://docs.konghq.com/1.1.x/admin-api/#consumer-object Consumer API definition
9
9
  class Consumer < Resource
10
+ include Helpers::Meta
11
+
10
12
  property :username
11
13
  property :custom_id
12
14
  property :created_at, read_only: true, postprocess: true
13
- property :tags, validate: true
15
+ property :tags, validate: true, preprocess: true, postprocess: true
14
16
 
15
- def self.batch_import(data, verbose: false, test: false)
17
+ # rubocop:disable Metrics/CyclomaticComplexity
18
+ # rubocop:disable Metrics/PerceivedComplexity
19
+ # rubocop:disable Metrics/AbcSize
20
+ def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
16
21
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
17
22
 
23
+ known_ids = []
24
+
25
+ # rubocop:disable Metrics/BlockLength
18
26
  data.each_with_index do |resource_data, index|
19
27
  resource = new
20
28
  resource.username = resource_data['username']
21
29
  resource.custom_id = resource_data['custom_id']
22
30
  resource.tags = resource_data['tags'] if resource_data['tags']
31
+ resource.project = project if project
32
+ resource.import_time = (time || Time.now.utc.to_i) if project
23
33
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
34
+ known_ids << resource.id
24
35
 
25
- BasicauthCredential.batch_import(
36
+ known_basic_auths = BasicauthCredential.batch_import(
26
37
  (
27
38
  resource_data.dig('credentials', 'basic-auth') || []
28
39
  ).map { |t| t.merge('consumer' => { 'id' => resource.id }) },
@@ -30,7 +41,7 @@ module SkullIsland
30
41
  test: test
31
42
  )
32
43
 
33
- JWTCredential.batch_import(
44
+ known_jwt_auths = JWTCredential.batch_import(
34
45
  (
35
46
  resource_data.dig('credentials', 'jwt') || []
36
47
  ).map { |t| t.merge('consumer' => { 'id' => resource.id }) },
@@ -38,20 +49,36 @@ module SkullIsland
38
49
  test: test
39
50
  )
40
51
 
41
- KeyauthCredential.batch_import(
52
+ known_key_auths = KeyauthCredential.batch_import(
42
53
  (
43
54
  resource_data.dig('credentials', 'key-auth') || []
44
55
  ).map { |t| t.merge('consumer' => { 'id' => resource.id }) },
45
56
  verbose: verbose,
46
57
  test: test
47
58
  )
59
+
60
+ next unless project
61
+
62
+ BasicauthCredential.all.reject { |res| known_basic_auths.include?(res.id) }.map do |res|
63
+ puts "[WARN] ! Removing #{res.class.name} (#{res.id})"
64
+ res.destroy
65
+ end
66
+
67
+ JWTCredential.all.reject { |res| known_jwt_auths.include?(res.id) }.map do |res|
68
+ puts "[WARN] ! Removing #{res.class.name} (#{res.id})"
69
+ res.destroy
70
+ end
71
+
72
+ KeyauthCredential.all.reject { |res| known_key_auths.include?(res.id) }.map do |res|
73
+ puts "[WARN] ! Removing #{res.class.name} (#{res.id})"
74
+ res.destroy
75
+ end
48
76
  end
77
+ # rubocop:enable Metrics/BlockLength
78
+
79
+ cleanup_except(project, known_ids) if project
49
80
  end
50
81
 
51
- # Convenience method to add upstream targets
52
- # rubocop:disable Metrics/AbcSize
53
- # rubocop:disable Metrics/CyclomaticComplexity
54
- # rubocop:disable Metrics/PerceivedComplexity
55
82
  def add_credential!(details)
56
83
  r = if [BasicauthCredential, JWTCredential, KeyauthCredential].include? details.class
57
84
  details
@@ -100,7 +127,7 @@ module SkullIsland
100
127
  hash = { 'username' => username, 'custom_id' => custom_id }
101
128
  creds = credentials_for_export
102
129
  hash['credentials'] = creds unless creds.empty?
103
- hash['tags'] = tags if tags
130
+ hash['tags'] = tags unless tags.empty?
104
131
  [*options[:exclude]].each do |exclude|
105
132
  hash.delete(exclude.to_s)
106
133
  end
@@ -20,17 +20,22 @@ module SkullIsland
20
20
  def self.batch_import(data, verbose: false, test: false)
21
21
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
22
22
 
23
+ known_ids = []
24
+
23
25
  data.each_with_index do |resource_data, index|
24
26
  resource = new
25
27
  resource.algorithm = resource_data['algorithm']
26
- resource.key = resource_data['key'] if resource_data['key']
27
- resource.secret = resource_data['secret'] if resource_data['secret']
28
+ resource.delayed_set(:key, resource_data, 'key') if resource_data['key']
29
+ resource.delayed_set(:secret, resource_data, 'secret') if resource_data['secret']
28
30
  if resource_data['rsa_public_key']
29
- resource.rsa_public_key = resource_data['rsa_public_key']
31
+ resource.delayed_set(:rsa_public_key, resource_data, 'rsa_public_key')
30
32
  end
31
33
  resource.delayed_set(:consumer, resource_data, 'consumer')
32
34
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
35
+ known_ids << resource.id
33
36
  end
37
+
38
+ known_ids
34
39
  end
35
40
 
36
41
  def self.relative_uri
@@ -65,6 +70,10 @@ module SkullIsland
65
70
  false
66
71
  end
67
72
 
73
+ def project
74
+ consumer ? consumer.project : nil
75
+ end
76
+
68
77
  private
69
78
 
70
79
  def postprocess_consumer(value)
@@ -19,7 +19,7 @@ module SkullIsland
19
19
 
20
20
  data.each_with_index do |resource_data, index|
21
21
  resource = new
22
- resource.key = resource_data['key']
22
+ resource.delayed_set(:key, resource_data, 'key')
23
23
  resource.delayed_set(:consumer, resource_data, 'consumer')
24
24
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
25
25
  end
@@ -7,6 +7,8 @@ module SkullIsland
7
7
  #
8
8
  # @see https://docs.konghq.com/1.1.x/admin-api/#plugin-object Plugin API definition
9
9
  class Plugin < Resource
10
+ include Helpers::Meta
11
+
10
12
  property :name
11
13
  property :enabled, type: :boolean
12
14
  property :run_on, validate: true
@@ -15,11 +17,15 @@ module SkullIsland
15
17
  property :route, validate: true, preprocess: true, postprocess: true
16
18
  property :service, validate: true, preprocess: true, postprocess: true
17
19
  property :created_at, read_only: true, postprocess: true
18
- property :tags, validate: true
20
+ property :tags, validate: true, preprocess: true, postprocess: true
19
21
 
20
- def self.batch_import(data, verbose: false, test: false)
22
+ # rubocop:disable Metrics/CyclomaticComplexity
23
+ # rubocop:disable Metrics/PerceivedComplexity
24
+ def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
21
25
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
22
26
 
27
+ known_ids = []
28
+
23
29
  data.each_with_index do |resource_data, index|
24
30
  resource = new
25
31
  resource.name = resource_data['name']
@@ -27,12 +33,19 @@ module SkullIsland
27
33
  resource.run_on = resource_data['run_on'] if resource_data['run_on']
28
34
  resource.config = resource_data['config'].deep_sort if resource_data['config']
29
35
  resource.tags = resource_data['tags'] if resource_data['tags']
36
+ resource.project = project if project
37
+ resource.import_time = (time || Time.now.utc.to_i) if project
30
38
  resource.delayed_set(:consumer, resource_data, 'consumer')
31
39
  resource.delayed_set(:route, resource_data, 'route')
32
40
  resource.delayed_set(:service, resource_data, 'service')
33
41
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
42
+ known_ids << resource.id
34
43
  end
44
+
45
+ cleanup_except(project, known_ids) if project
35
46
  end
47
+ # rubocop:enable Metrics/CyclomaticComplexity
48
+ # rubocop:enable Metrics/PerceivedComplexity
36
49
 
37
50
  def self.enabled_names(api_client: APIClient.instance)
38
51
  api_client.get("#{relative_uri}/enabled")['enabled_plugins']
@@ -55,7 +68,7 @@ module SkullIsland
55
68
  hash['consumer'] = "<%= lookup :consumer, '#{consumer.username}' %>" if consumer
56
69
  hash['route'] = "<%= lookup :route, '#{route.name}' %>" if route
57
70
  hash['service'] = "<%= lookup :service, '#{service.name}' %>" if service
58
- hash['tags'] = tags if tags
71
+ hash['tags'] = tags unless tags.empty?
59
72
  [*options[:exclude]].each do |exclude|
60
73
  hash.delete(exclude.to_s)
61
74
  end
@@ -7,6 +7,8 @@ module SkullIsland
7
7
  #
8
8
  # @see https://docs.konghq.com/1.1.x/admin-api/#route-object Route API definition
9
9
  class Route < Resource
10
+ include Helpers::Meta
11
+
10
12
  property :name
11
13
  property :methods
12
14
  property :paths
@@ -21,14 +23,16 @@ module SkullIsland
21
23
  property :service, validate: true, preprocess: true, postprocess: true
22
24
  property :created_at, read_only: true, postprocess: true
23
25
  property :updated_at, read_only: true, postprocess: true
24
- property :tags, validate: true
26
+ property :tags, validate: true, preprocess: true, postprocess: true
25
27
 
26
28
  # rubocop:disable Metrics/CyclomaticComplexity
27
29
  # rubocop:disable Metrics/PerceivedComplexity
28
30
  # rubocop:disable Metrics/AbcSize
29
- def self.batch_import(data, verbose: false, test: false)
31
+ def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
30
32
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
31
33
 
34
+ known_ids = []
35
+
32
36
  data.each_with_index do |rdata, index|
33
37
  resource = new
34
38
  resource.name = rdata['name']
@@ -41,9 +45,14 @@ module SkullIsland
41
45
  resource.preserve_host = rdata['preserve_host'] unless rdata['preserve_host'].nil?
42
46
  resource.snis = rdata['snis'] if rdata['snis']
43
47
  resource.tags = rdata['tags'] if rdata['tags']
48
+ resource.project = project if project
49
+ resource.import_time = (time || Time.now.utc.to_i) if project
44
50
  resource.delayed_set(:service, rdata, 'service')
45
51
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
52
+ known_ids << resource.id
46
53
  end
54
+
55
+ cleanup_except(project, known_ids) if project
47
56
  end
48
57
  # rubocop:enable Metrics/CyclomaticComplexity
49
58
  # rubocop:enable Metrics/PerceivedComplexity
@@ -68,7 +77,7 @@ module SkullIsland
68
77
  }
69
78
  hash['service'] = "<%= lookup :service, '#{service.name}' %>" if service
70
79
  hash['snis'] = snis if snis && !snis.empty?
71
- hash['tags'] = tags if tags
80
+ hash['tags'] = tags unless tags.empty?
72
81
  [*options[:exclude]].each do |exclude|
73
82
  hash.delete(exclude.to_s)
74
83
  end
@@ -7,6 +7,8 @@ module SkullIsland
7
7
  #
8
8
  # @see https://docs.konghq.com/1.1.x/admin-api/#service-object Service API definition
9
9
  class Service < Resource
10
+ include Helpers::Meta
11
+
10
12
  property :name
11
13
  property :retries
12
14
  property :protocol, validate: true, required: true
@@ -18,27 +20,32 @@ module SkullIsland
18
20
  property :read_timeout, validate: true
19
21
  property :created_at, read_only: true, postprocess: true
20
22
  property :updated_at, read_only: true, postprocess: true
21
- property :tags, validate: true
23
+ property :tags, validate: true, preprocess: true, postprocess: true
22
24
 
23
25
  # rubocop:disable Metrics/CyclomaticComplexity
24
26
  # rubocop:disable Metrics/PerceivedComplexity
25
27
  # rubocop:disable Metrics/AbcSize
26
- def self.batch_import(data, verbose: false, test: false)
28
+ def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
27
29
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
28
30
 
31
+ known_ids = []
32
+
29
33
  data.each_with_index do |rdata, index|
30
34
  resource = new
31
35
  resource.name = rdata['name']
32
36
  resource.retries = rdata['retries'] if rdata['retries']
33
37
  resource.protocol = rdata['protocol']
34
- resource.host = rdata['host']
35
- resource.port = rdata['port']
38
+ resource.delayed_set(:host, rdata, 'host')
39
+ resource.delayed_set(:port, rdata, 'port')
36
40
  resource.path = rdata['path'] if rdata['path']
37
41
  resource.connect_timeout = rdata['connect_timeout'] if rdata['connect_timeout']
38
42
  resource.write_timeout = rdata['write_timeout'] if rdata['write_timeout']
39
43
  resource.read_timeout = rdata['read_timeout'] if rdata['read_timeout']
40
44
  resource.tags = rdata['tags'] if rdata['tags']
45
+ resource.project = project if project
46
+ resource.import_time = (time || Time.now.utc.to_i) if project
41
47
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
48
+ known_ids << resource.id
42
49
 
43
50
  Route.batch_import(
44
51
  (rdata['routes'] || []).map { |r| r.merge('service' => { 'id' => resource.id }) },
@@ -46,6 +53,8 @@ module SkullIsland
46
53
  test: test
47
54
  )
48
55
  end
56
+
57
+ cleanup_except(project, known_ids) if project
49
58
  end
50
59
  # rubocop:enable Metrics/CyclomaticComplexity
51
60
  # rubocop:enable Metrics/PerceivedComplexity
@@ -59,6 +68,11 @@ module SkullIsland
59
68
  r.save
60
69
  end
61
70
 
71
+ def destroy
72
+ routes.each(&:destroy)
73
+ super
74
+ end
75
+
62
76
  # Provides a collection of related {Route} instances
63
77
  def routes
64
78
  Route.where(:service, self, api_client: api_client)
@@ -82,7 +96,7 @@ module SkullIsland
82
96
  'read_timeout' => read_timeout
83
97
  }
84
98
  hash['routes'] = routes.collect { |route| route.export(exclude: 'service') }
85
- hash['tags'] = tags if tags
99
+ hash['tags'] = tags unless tags.empty?
86
100
  [*options[:exclude]].each do |exclude|
87
101
  hash.delete(exclude.to_s)
88
102
  end
@@ -7,6 +7,8 @@ module SkullIsland
7
7
  #
8
8
  # @see https://docs.konghq.com/1.1.x/admin-api/#upstream-objects Upstream API definition
9
9
  class Upstream < Resource
10
+ include Helpers::Meta
11
+
10
12
  property :name, required: true, validate: true
11
13
  property :slots, validate: true
12
14
  property :hash_on, validate: true
@@ -17,14 +19,16 @@ module SkullIsland
17
19
  property :hash_on_cookie_path, validate: true
18
20
  property :healthchecks, validate: true
19
21
  property :created_at, read_only: true, postprocess: true
20
- property :tags, validate: true
22
+ property :tags, validate: true, preprocess: true, postprocess: true
21
23
 
22
24
  # rubocop:disable Metrics/CyclomaticComplexity
23
25
  # rubocop:disable Metrics/PerceivedComplexity
24
26
  # rubocop:disable Metrics/AbcSize
25
- def self.batch_import(data, verbose: false, test: false)
27
+ def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
26
28
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
27
29
 
30
+ known_ids = []
31
+
28
32
  data.each_with_index do |rdata, index|
29
33
  resource = new
30
34
  resource.name = rdata['name']
@@ -41,15 +45,22 @@ module SkullIsland
41
45
  end
42
46
  resource.healthchecks = rdata['healthchecks'] if rdata['healthchecks']
43
47
  resource.tags = rdata['tags'] if rdata['tags']
48
+ resource.project = project if project
49
+ resource.import_time = (time || Time.now.utc.to_i) if project
44
50
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
51
+ known_ids << resource.id
45
52
  puts '[INFO] Processing UpstreamTarget entries...' if verbose
46
53
 
47
54
  UpstreamTarget.batch_import(
48
55
  (rdata['targets'] || []).map { |t| t.merge('upstream' => { 'id' => resource.id }) },
49
56
  verbose: verbose,
50
- test: test
57
+ test: test,
58
+ project: project,
59
+ time: time
51
60
  )
52
61
  end
62
+
63
+ cleanup_except(project, known_ids) if project
53
64
  end
54
65
  # rubocop:enable Metrics/CyclomaticComplexity
55
66
  # rubocop:enable Metrics/PerceivedComplexity
@@ -113,7 +124,7 @@ module SkullIsland
113
124
  'healthchecks' => healthchecks
114
125
  }
115
126
  hash['targets'] = targets.collect { |target| target.export(exclude: 'upstream') }
116
- hash['tags'] = tags if tags
127
+ hash['tags'] = tags unless tags.empty?
117
128
  [*options[:exclude]].each do |exclude|
118
129
  hash.delete(exclude.to_s)
119
130
  end
@@ -7,6 +7,8 @@ module SkullIsland
7
7
  #
8
8
  # @see https://docs.konghq.com/1.1.x/admin-api/#target-object Target API definition
9
9
  class UpstreamTarget < Resource
10
+ include Helpers::Meta
11
+
10
12
  property :target, required: true, validate: true, preprocess: true
11
13
  property(
12
14
  :upstream,
@@ -14,20 +16,31 @@ module SkullIsland
14
16
  )
15
17
  property :weight, validate: true
16
18
  property :created_at, read_only: true, postprocess: true
17
- property :tags, validate: true
19
+ property :tags, validate: true, preprocess: true, postprocess: true
18
20
 
19
- def self.batch_import(data, verbose: false, test: false)
21
+ # rubocop:disable Metrics/CyclomaticComplexity
22
+ # rubocop:disable Metrics/PerceivedComplexity
23
+ def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
20
24
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
21
25
 
26
+ known_ids = []
27
+
22
28
  data.each_with_index do |resource_data, index|
23
29
  resource = new
24
- resource.target = resource_data['target']
30
+ resource.delayed_set(:target, resource_data, 'target')
25
31
  resource.delayed_set(:upstream, resource_data, 'upstream')
26
32
  resource.weight = resource_data['weight'] if resource_data['weight']
27
33
  resource.tags = resource_data['tags'] if resource_data['tags']
34
+ resource.project = project if project
35
+ resource.import_time = (time || Time.now.utc.to_i) if project
28
36
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
37
+ known_ids << resource.id
29
38
  end
39
+
40
+ cleanup_except(project, known_ids) if project
30
41
  end
42
+ # rubocop:enable Metrics/CyclomaticComplexity
43
+ # rubocop:enable Metrics/PerceivedComplexity
31
44
 
32
45
  def self.all(options = {})
33
46
  api_client = options[:api_client] || APIClient.instance
@@ -68,7 +81,7 @@ module SkullIsland
68
81
  def export(options = {})
69
82
  hash = { 'target' => target, 'weight' => weight }
70
83
  hash['upstream'] = "<%= lookup :upstream, '#{upstream.name}' %>" if upstream
71
- hash['tags'] = tags if tags
84
+ hash['tags'] = tags unless tags.empty?
72
85
  [*options[:exclude]].each do |exclude|
73
86
  hash.delete(exclude.to_s)
74
87
  end
@@ -79,19 +92,7 @@ module SkullIsland
79
92
  end
80
93
 
81
94
  def modified_existing?
82
- return false unless new?
83
-
84
- # Find routes of the same name
85
- same_target_and_upstream = self.class.where(:target, target).and(:upstream, upstream)
86
-
87
- existing = same_target_and_upstream.size == 1 ? same_target_and_upstream.first : nil
88
-
89
- if existing
90
- @entity['id'] = existing.id
91
- save
92
- else
93
- false
94
- end
95
+ false # Upstream Targets can not be PATCHed, so can not be modified
95
96
  end
96
97
 
97
98
  private
@@ -24,7 +24,7 @@ module SkullIsland
24
24
  def validate_tags(value)
25
25
  # allow only valid hostnames
26
26
  value.each do |tag|
27
- return false unless tag.is_a?(String) && tag.match?(/\w_-\.~/)
27
+ return false unless tag.is_a?(String) && tag.match?(/^[\w_\-\.~]+$/)
28
28
  end
29
29
  true
30
30
  end
@@ -4,6 +4,6 @@ module SkullIsland
4
4
  VERSION = [
5
5
  1, # Major
6
6
  2, # Minor
7
- 0 # Patch
7
+ 2 # Patch
8
8
  ].join('.')
9
9
  end
@@ -40,5 +40,5 @@ Gem::Specification.new do |spec|
40
40
  spec.add_development_dependency 'rubocop', '~> 0.50'
41
41
  spec.add_development_dependency 'simplecov', '~> 0.15'
42
42
  spec.add_development_dependency 'travis', '~> 1.8'
43
- spec.add_development_dependency 'yard', '~> 0.9'
43
+ spec.add_development_dependency 'yard', '~> 0.9.20'
44
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skull_island
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Gnagy
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-26 00:00:00.000000000 Z
11
+ date: 2019-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deepsort
@@ -198,14 +198,14 @@ dependencies:
198
198
  requirements:
199
199
  - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: '0.9'
201
+ version: 0.9.20
202
202
  type: :development
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: '0.9'
208
+ version: 0.9.20
209
209
  description: A Ruby SDK for Kong 0.14.x
210
210
  email:
211
211
  - jonathan.gnagy@gmail.com
@@ -242,6 +242,7 @@ files:
242
242
  - lib/skull_island/exceptions/invalid_where_query.rb
243
243
  - lib/skull_island/exceptions/new_instance_with_id.rb
244
244
  - lib/skull_island/helpers/api_client.rb
245
+ - lib/skull_island/helpers/meta.rb
245
246
  - lib/skull_island/helpers/migration.rb
246
247
  - lib/skull_island/helpers/resource.rb
247
248
  - lib/skull_island/helpers/resource_class.rb
@@ -284,7 +285,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
284
285
  - !ruby/object:Gem::Version
285
286
  version: '0'
286
287
  requirements: []
287
- rubygems_version: 3.0.4
288
+ rubyforge_project:
289
+ rubygems_version: 2.7.7
288
290
  signing_key:
289
291
  specification_version: 4
290
292
  summary: Ruby SDK for Kong