skull_island 0.14.1 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -3
- data/Gemfile.lock +1 -1
- data/README.md +26 -11
- data/lib/skull_island.rb +1 -0
- data/lib/skull_island/api_client_base.rb +1 -0
- data/lib/skull_island/cli.rb +88 -18
- data/lib/skull_island/helpers/migration.rb +34 -0
- data/lib/skull_island/helpers/resource.rb +6 -5
- data/lib/skull_island/resources/basicauth_credential.rb +13 -13
- data/lib/skull_island/resources/certificate.rb +13 -4
- data/lib/skull_island/resources/consumer.rb +8 -5
- data/lib/skull_island/resources/keyauth_credential.rb +13 -13
- data/lib/skull_island/resources/plugin.rb +39 -35
- data/lib/skull_island/resources/route.rb +30 -14
- data/lib/skull_island/resources/service.rb +4 -1
- data/lib/skull_island/resources/upstream.rb +6 -3
- data/lib/skull_island/resources/upstream_target.rb +18 -15
- data/lib/skull_island/validations/resource.rb +9 -0
- data/lib/skull_island/version.rb +3 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2599c9fbc76abcc4be21923b95477c784515165c3891aa5155d7a9d88c5c887b
|
4
|
+
data.tar.gz: df6f3715f49a4a6cb09118bd446f1c7097fa7d0228dfce497e7396e63921e13c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70be200f4e3721d42c820176d16350e705c40c38254876322181a1509538b0e7612156fbb2ddb29b9a8bdfab522ec8452046b346a2fe059a3bd838f4f2c578bc
|
7
|
+
data.tar.gz: 7c426dfbf53dbb080ed5211c14ce22b0d5ef78aa06a8e27c1fd1d91b1534065f77554ffc93edc56728fec870aa8bdd591ed10d1fcadf454c4372f897e16f03bf
|
data/.rubocop.yml
CHANGED
@@ -8,10 +8,10 @@ Metrics/LineLength:
|
|
8
8
|
Max: 100
|
9
9
|
|
10
10
|
Metrics/ClassLength:
|
11
|
-
Max:
|
11
|
+
Max: 170
|
12
12
|
|
13
13
|
Metrics/ModuleLength:
|
14
|
-
Max:
|
14
|
+
Max: 170
|
15
15
|
Exclude:
|
16
16
|
- 'lib/skull_island/helpers/resource.rb'
|
17
17
|
|
@@ -23,7 +23,7 @@ Metrics/PerceivedComplexity:
|
|
23
23
|
- 'lib/skull_island/cli.rb'
|
24
24
|
|
25
25
|
Metrics/AbcSize:
|
26
|
-
Max:
|
26
|
+
Max: 27
|
27
27
|
|
28
28
|
Metrics/BlockLength:
|
29
29
|
Max: 35
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Skull Island
|
2
2
|
|
3
|
-
|
3
|
+
A full-featured SDK for [Kong](https://konghq.com/kong/) 1.1.x (with support for migrating from 0.14.x). Note that this is unofficial (meaning this project is in no way officially endorsed, recommended, or related to Kong [as a company](https://konghq.com/) or an [open-source project](https://github.com/Kong/kong)). It is also in no way related to the [pet toy company](https://www.kongcompany.com/) by the same name (but hopefully that was obvious).
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -13,7 +13,7 @@ gem install skull_island
|
|
13
13
|
Or add this to your Gemfile:
|
14
14
|
|
15
15
|
```ruby
|
16
|
-
gem 'skull_island', '~>
|
16
|
+
gem 'skull_island', '~> 1.1'
|
17
17
|
```
|
18
18
|
|
19
19
|
Or add this to your .gemspec:
|
@@ -21,7 +21,7 @@ Or add this to your .gemspec:
|
|
21
21
|
```ruby
|
22
22
|
Gem::Specification.new do |spec|
|
23
23
|
# ...
|
24
|
-
spec.add_runtime_dependency 'skull_island', '~>
|
24
|
+
spec.add_runtime_dependency 'skull_island', '~> 1.1'
|
25
25
|
# ...
|
26
26
|
end
|
27
27
|
```
|
@@ -33,9 +33,10 @@ Skull Island comes with an executable called `skull_island` that leverages the S
|
|
33
33
|
```
|
34
34
|
$ skull_island help
|
35
35
|
Commands:
|
36
|
-
skull_island export [OPTIONS]
|
37
|
-
skull_island help [COMMAND]
|
38
|
-
skull_island import [OPTIONS]
|
36
|
+
skull_island export [OPTIONS] [OUTPUT|-] # Export the current configuration to OUTPUT
|
37
|
+
skull_island help [COMMAND] # Describe available commands or one specific command
|
38
|
+
skull_island import [OPTIONS] [INPUT|-] # Import a configuration from INPUT
|
39
|
+
skull_island migrate [OPTIONS] [INPUT|-] [OUTPUT|-] # Migrate an older config from INPUT to OUTPUT
|
39
40
|
|
40
41
|
Options:
|
41
42
|
[--verbose], [--no-verbose]
|
@@ -111,13 +112,27 @@ KONG_ADMIN_URL='https://api-admin.mydomain.com' \
|
|
111
112
|
skull_island import --verbose --test /path/to/export.yml
|
112
113
|
```
|
113
114
|
|
115
|
+
### Migrating
|
116
|
+
|
117
|
+
With Skull Island, it is possible to migrate a configuration from a 0.14.x gateway to one compatible with a 1.1.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.1 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:
|
118
|
+
|
119
|
+
```
|
120
|
+
skull_island migrate /path/to/export.yml /output/location/migrated.yml
|
121
|
+
```
|
122
|
+
|
123
|
+
While this hasn't been heavily tested for all possible use-cases, any configuration generated or usable by the `'~> 0.14'` version of this gem should safely convert using the migration command. This tool also makes no guarantees about plugin functionality, configuration compatibility across versions, or that the same plugins are installed and available in your newer gateway. It should go without saying that you should **test and confirm** that all of your functionality was successfully migrated.
|
124
|
+
|
125
|
+
If you don't have a previous export, you'll need to install an older version of this gem using `gem install --version '~> 0.14' skull_island`, then perform an `export`, then you can switch back to the latest version of the gem for migrating and importing.
|
126
|
+
|
127
|
+
While it would be possible to make migration _automatic_ for the `import` command, `skull_island` intentionally doesn't do this to avoid the appearance that the config is losslessly compatible across versions. In reality, the newer config version has additional features (like tagging) that will likely be used heavily. It makes sense to this author to maintain the migration component and the normal functionality as distinct features to encourage the use of the newer capabilities in 1.1+.
|
128
|
+
|
114
129
|
### File Format
|
115
130
|
|
116
|
-
The import/export CLI functions produce YAML with support for embedded Ruby ([ERB](https://ruby-doc.org/stdlib-2.5.3/libdoc/erb/rdoc/ERB.html)). The file is structured like this (as an example):
|
131
|
+
The import/export/migrate CLI functions produce YAML with support for embedded Ruby ([ERB](https://ruby-doc.org/stdlib-2.5.3/libdoc/erb/rdoc/ERB.html)). The file is structured like this (as an example):
|
117
132
|
|
118
133
|
```yaml
|
119
134
|
---
|
120
|
-
version: '
|
135
|
+
version: '1.1'
|
121
136
|
certificates: []
|
122
137
|
consumers:
|
123
138
|
- username: foo
|
@@ -172,7 +187,7 @@ plugins:
|
|
172
187
|
key_names:
|
173
188
|
- x-api-key
|
174
189
|
run_on_preflight: true
|
175
|
-
|
190
|
+
service: "<%= lookup :service, 'search_api' %>"
|
176
191
|
```
|
177
192
|
|
178
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.
|
@@ -295,7 +310,7 @@ service.routes.size
|
|
295
310
|
# => 4
|
296
311
|
```
|
297
312
|
|
298
|
-
From here, the SDK mostly wraps the attributes described in the [Kong API Docs](https://docs.konghq.com/
|
313
|
+
From here, the SDK mostly wraps the attributes described in the [Kong API Docs](https://docs.konghq.com/1.1.x/admin-api/). For simplicity, I'll go over the resource types and attributes this SDK supports manipulating. Rely on the API documentation to determine which attributes are required and under which conditions.
|
299
314
|
|
300
315
|
#### Certificates
|
301
316
|
|
@@ -365,7 +380,7 @@ resource.enabled = true # A Boolean
|
|
365
380
|
resource.config = { 'minute' => 50, 'hour' => 1000 } # A Hash of config keys and values
|
366
381
|
|
367
382
|
# Either reference related resources by ID
|
368
|
-
resource.service = '5fd1z584-1adb-40a5-c042-63b19db49x21'
|
383
|
+
resource.service = { 'id' => '5fd1z584-1adb-40a5-c042-63b19db49x21' }
|
369
384
|
resource.service
|
370
385
|
# => #<SkullIsland::Resources::Services:0x00007f9f201f6f44...
|
371
386
|
|
data/lib/skull_island.rb
CHANGED
@@ -41,6 +41,7 @@ require 'skull_island/simple_api_client'
|
|
41
41
|
require 'skull_island/resource_collection'
|
42
42
|
require 'skull_island/helpers/resource'
|
43
43
|
require 'skull_island/helpers/resource_class'
|
44
|
+
require 'skull_island/helpers/migration'
|
44
45
|
require 'skull_island/validations/resource'
|
45
46
|
require 'skull_island/resource'
|
46
47
|
require 'skull_island/resources/certificate'
|
data/lib/skull_island/cli.rb
CHANGED
@@ -10,9 +10,11 @@ require 'thor'
|
|
10
10
|
module SkullIsland
|
11
11
|
# Base CLI for SkullIsland
|
12
12
|
class CLI < Thor
|
13
|
+
include Helpers::Migration
|
14
|
+
|
13
15
|
class_option :verbose, type: :boolean
|
14
16
|
|
15
|
-
desc 'export [OPTIONS]
|
17
|
+
desc 'export [OPTIONS] [OUTPUT|-]', 'Export the current configuration to OUTPUT'
|
16
18
|
def export(output_file = '-')
|
17
19
|
if output_file == '-'
|
18
20
|
STDERR.puts '[INFO] Outputting to STDOUT' if options['verbose']
|
@@ -24,7 +26,9 @@ module SkullIsland
|
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
27
|
-
|
29
|
+
validate_server_version
|
30
|
+
|
31
|
+
output = { 'version' => '1.1' }
|
28
32
|
|
29
33
|
[
|
30
34
|
Resources::Certificate,
|
@@ -41,29 +45,17 @@ module SkullIsland
|
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
44
|
-
desc 'import [OPTIONS]
|
48
|
+
desc 'import [OPTIONS] [INPUT|-]', 'Import a configuration from INPUT'
|
45
49
|
option :test, type: :boolean, desc: "Don't do anything, just show what would happen"
|
46
50
|
def import(input_file = '-')
|
47
|
-
raw ||=
|
48
|
-
STDERR.puts '[INFO] Reading from STDOUT' if options['verbose']
|
49
|
-
STDIN.read
|
50
|
-
else
|
51
|
-
full_filename = File.expand_path(input_file)
|
52
|
-
unless File.exist?(full_filename) && File.ftype(full_filename) == 'file'
|
53
|
-
raise Exceptions::InvalidArguments, "#{full_filename} is invalid"
|
54
|
-
end
|
55
|
-
|
56
|
-
begin
|
57
|
-
File.read(full_filename)
|
58
|
-
rescue StandardError => e
|
59
|
-
raise "Unable to process #{relative_path}: #{e.message}"
|
60
|
-
end
|
61
|
-
end
|
51
|
+
raw ||= acquire_input(input_file, options['verbose'])
|
62
52
|
|
63
53
|
# rubocop:disable Security/YAMLLoad
|
64
54
|
input = YAML.load(raw)
|
65
55
|
# rubocop:enable Security/YAMLLoad
|
66
56
|
|
57
|
+
validate_config_version input['version']
|
58
|
+
|
67
59
|
[
|
68
60
|
Resources::Certificate,
|
69
61
|
Resources::Consumer,
|
@@ -73,6 +65,35 @@ module SkullIsland
|
|
73
65
|
].each { |clname| import_class(clname, input) }
|
74
66
|
end
|
75
67
|
|
68
|
+
desc(
|
69
|
+
'migrate [OPTIONS] [INPUT|-] [OUTPUT|-]',
|
70
|
+
'Migrate an older config from INPUT to OUTPUT'
|
71
|
+
)
|
72
|
+
def migrate(input_file = '-', output_file = '-')
|
73
|
+
raw ||= acquire_input(input_file, options['verbose'])
|
74
|
+
|
75
|
+
# rubocop:disable Security/YAMLLoad
|
76
|
+
input = YAML.load(raw)
|
77
|
+
# rubocop:enable Security/YAMLLoad
|
78
|
+
|
79
|
+
validate_migrate_version input['version']
|
80
|
+
|
81
|
+
output = migrate_config(input)
|
82
|
+
|
83
|
+
if output_file == '-'
|
84
|
+
STDERR.puts '[INFO] Outputting to STDOUT' if options['verbose']
|
85
|
+
STDOUT.puts output.to_yaml
|
86
|
+
else
|
87
|
+
full_filename = File.expand_path(output_file)
|
88
|
+
dirname = File.dirname(full_filename)
|
89
|
+
unless File.exist?(dirname) && File.ftype(dirname) == 'directory'
|
90
|
+
raise Exceptions::InvalidArguments, "#{full_filename} is invalid"
|
91
|
+
end
|
92
|
+
|
93
|
+
File.write(full_filename, output.to_yaml)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
76
97
|
private
|
77
98
|
|
78
99
|
def export_class(class_name, output_data)
|
@@ -88,5 +109,54 @@ module SkullIsland
|
|
88
109
|
test: options['test']
|
89
110
|
)
|
90
111
|
end
|
112
|
+
|
113
|
+
# Used to pull input from either STDIN or the specified file
|
114
|
+
def acquire_input(input_file, verbose = false)
|
115
|
+
if input_file == '-'
|
116
|
+
STDERR.puts '[INFO] Reading from STDIN' if verbose
|
117
|
+
STDIN.read
|
118
|
+
else
|
119
|
+
full_filename = File.expand_path(input_file)
|
120
|
+
unless File.exist?(full_filename) && File.ftype(full_filename) == 'file'
|
121
|
+
raise Exceptions::InvalidArguments, "#{full_filename} is invalid"
|
122
|
+
end
|
123
|
+
|
124
|
+
begin
|
125
|
+
File.read(full_filename)
|
126
|
+
rescue StandardError => e
|
127
|
+
raise "Unable to process #{relative_path}: #{e.message}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def validate_config_version(version)
|
133
|
+
if version && version == '1.1'
|
134
|
+
validate_server_version
|
135
|
+
elsif version && ['0.14', '1.0'].include?(version)
|
136
|
+
STDERR.puts '[CRITICAL] Config version is too old. Try `migrate` instead of `import`.'
|
137
|
+
exit 2
|
138
|
+
else
|
139
|
+
STDERR.puts '[CRITICAL] Config version is unknown or not supported.'
|
140
|
+
exit 3
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def validate_migrate_version(version)
|
145
|
+
if version && version == '0.14'
|
146
|
+
true
|
147
|
+
else
|
148
|
+
STDERR.puts '[CRITICAL] Config version must be 0.14 for migration.'
|
149
|
+
exit 4
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def validate_server_version
|
154
|
+
if SkullIsland::APIClient.about_service['version'].start_with? '1.1'
|
155
|
+
true
|
156
|
+
else
|
157
|
+
STDERR.puts '[CRITICAL] Server version mismatch!'
|
158
|
+
exit 1
|
159
|
+
end
|
160
|
+
end
|
91
161
|
end
|
92
162
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SkullIsland
|
4
|
+
module Helpers
|
5
|
+
# Simple helper methods for migrating old configs
|
6
|
+
module Migration
|
7
|
+
def migrate_config(config)
|
8
|
+
if config['version'] == '0.14'
|
9
|
+
migrate_0_14_to_1_1(config)
|
10
|
+
else
|
11
|
+
false # Just return false if it can't be migrated
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def migrate_0_14_to_1_1(config)
|
16
|
+
new_config = config.dup
|
17
|
+
config['plugins']&.each_with_index do |plugin, plugin_index|
|
18
|
+
%w[consumer route service].each do |rtype|
|
19
|
+
if plugin["#{rtype}_id"]&.start_with?('<%=')
|
20
|
+
new_config['plugins'][plugin_index][rtype] = plugin["#{rtype}_id"].dup
|
21
|
+
new_config['plugins'][plugin_index].delete("#{rtype}_id")
|
22
|
+
elsif plugin["#{rtype}_id"]
|
23
|
+
new_config['plugins'][plugin_index][rtype] = {
|
24
|
+
'id' => plugin["#{rtype}_id"].dup
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
new_config['version'] = '1.1'
|
30
|
+
new_config
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -18,9 +18,10 @@ module SkullIsland
|
|
18
18
|
def delayed_set(property, data, key)
|
19
19
|
# rubocop:disable Security/Eval
|
20
20
|
if data[key]
|
21
|
+
value = data[key].is_a?(String) ? eval(Erubi::Engine.new(data[key]).src) : data[key]
|
21
22
|
send(
|
22
23
|
"#{property}=".to_sym,
|
23
|
-
|
24
|
+
value.is_a?(String) && value.start_with?('{"') ? eval(value) : value
|
24
25
|
)
|
25
26
|
end
|
26
27
|
# rubocop:enable Security/Eval
|
@@ -94,13 +95,13 @@ module SkullIsland
|
|
94
95
|
def lookup(type, value)
|
95
96
|
case type
|
96
97
|
when :consumer
|
97
|
-
Resources::Consumer.find(:username, value).id
|
98
|
+
{ 'id' => Resources::Consumer.find(:username, value).id }
|
98
99
|
when :route
|
99
|
-
Resources::Route.find(:name, value).id
|
100
|
+
{ 'id' => Resources::Route.find(:name, value).id }
|
100
101
|
when :service
|
101
|
-
Resources::Service.find(:name, value).id
|
102
|
+
{ 'id' => Resources::Service.find(:name, value).id }
|
102
103
|
when :upstream
|
103
|
-
Resources::Upstream.find(:name, value).id
|
104
|
+
{ 'id' => Resources::Upstream.find(:name, value).id }
|
104
105
|
else
|
105
106
|
raise Exceptions::InvalidArguments, "#{type} is not a valid lookup type"
|
106
107
|
end
|
@@ -10,8 +10,8 @@ module SkullIsland
|
|
10
10
|
property :username, required: true, validate: true
|
11
11
|
property :password, validated: true
|
12
12
|
property(
|
13
|
-
:
|
14
|
-
required: true, validate: true, preprocess: true, postprocess: true
|
13
|
+
:consumer,
|
14
|
+
required: true, validate: true, preprocess: true, postprocess: true
|
15
15
|
)
|
16
16
|
property :created_at, read_only: true, postprocess: true
|
17
17
|
|
@@ -22,7 +22,7 @@ module SkullIsland
|
|
22
22
|
resource = new
|
23
23
|
resource.username = resource_data['username']
|
24
24
|
resource.password = resource_data['password'] if resource_data['password']
|
25
|
-
resource.delayed_set(:consumer, resource_data, '
|
25
|
+
resource.delayed_set(:consumer, resource_data, 'consumer')
|
26
26
|
resource.import_update_or_skip(index: index, verbose: verbose, test: test)
|
27
27
|
end
|
28
28
|
end
|
@@ -41,7 +41,7 @@ module SkullIsland
|
|
41
41
|
|
42
42
|
def export(options = {})
|
43
43
|
hash = { 'username' => username, 'password' => password }
|
44
|
-
hash['
|
44
|
+
hash['consumer'] = "<%= lookup :consumer, '#{consumer.username}' %>" if consumer
|
45
45
|
[*options[:exclude]].each do |exclude|
|
46
46
|
hash.delete(exclude.to_s)
|
47
47
|
end
|
@@ -58,10 +58,10 @@ module SkullIsland
|
|
58
58
|
|
59
59
|
private
|
60
60
|
|
61
|
-
def
|
62
|
-
if value.is_a?(
|
61
|
+
def postprocess_consumer(value)
|
62
|
+
if value.is_a?(Hash)
|
63
63
|
Consumer.new(
|
64
|
-
entity:
|
64
|
+
entity: value,
|
65
65
|
lazy: true,
|
66
66
|
tainted: false
|
67
67
|
)
|
@@ -70,18 +70,18 @@ module SkullIsland
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
def
|
74
|
-
if input.is_a?(
|
73
|
+
def preprocess_consumer(input)
|
74
|
+
if input.is_a?(Hash)
|
75
75
|
input
|
76
76
|
else
|
77
|
-
input.id
|
77
|
+
{ 'id' => input.id }
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
81
|
# Used to validate {#consumer} on set
|
82
|
-
def
|
83
|
-
# allow either a Consumer object or a
|
84
|
-
value.is_a?(Consumer) || value.is_a?(
|
82
|
+
def validate_consumer(value)
|
83
|
+
# allow either a Consumer object or a Hash
|
84
|
+
value.is_a?(Consumer) || value.is_a?(Hash)
|
85
85
|
end
|
86
86
|
|
87
87
|
# Used to validate {#password} on set
|
@@ -5,12 +5,13 @@ module SkullIsland
|
|
5
5
|
module Resources
|
6
6
|
# The Certificate resource class
|
7
7
|
#
|
8
|
-
# @see https://docs.konghq.com/
|
8
|
+
# @see https://docs.konghq.com/1.1.x/admin-api/#certificate-object Certificate API definition
|
9
9
|
class Certificate < Resource
|
10
10
|
property :cert, required: true, validate: true
|
11
11
|
property :key, required: true, validate: true
|
12
12
|
property :snis, validate: true
|
13
13
|
property :created_at, read_only: true, postprocess: true
|
14
|
+
property :tags, validate: true
|
14
15
|
|
15
16
|
def self.batch_import(data, verbose: false, test: false)
|
16
17
|
raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
|
@@ -20,12 +21,15 @@ module SkullIsland
|
|
20
21
|
resource.cert = resource_data['cert']
|
21
22
|
resource.key = resource_data['key']
|
22
23
|
resource.snis = resource_data['snis'] if resource_data['snis']
|
24
|
+
resource.tags = resource_data['tags'] if resource_data['tags']
|
23
25
|
resource.import_update_or_skip(index: index, verbose: verbose, test: test)
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
27
29
|
def export(options = {})
|
28
|
-
hash = { 'cert' => cert, 'key' => key
|
30
|
+
hash = { 'cert' => cert, 'key' => key }
|
31
|
+
hash['snis'] = snis if snis && !snis.empty?
|
32
|
+
hash['tags'] = tags if tags
|
29
33
|
[*options[:exclude]].each do |exclude|
|
30
34
|
hash.delete(exclude.to_s)
|
31
35
|
end
|
@@ -67,8 +71,13 @@ module SkullIsland
|
|
67
71
|
|
68
72
|
# Used to validate {#snis} on set
|
69
73
|
def validate_snis(value)
|
70
|
-
|
71
|
-
|
74
|
+
return false unless value.is_a?(Array)
|
75
|
+
|
76
|
+
# allow only valid hostnames
|
77
|
+
value.each do |sni|
|
78
|
+
return false unless sni.match?(host_regex) && !sni.match?(/_/)
|
79
|
+
end
|
80
|
+
true
|
72
81
|
end
|
73
82
|
end
|
74
83
|
end
|
@@ -5,11 +5,12 @@ module SkullIsland
|
|
5
5
|
module Resources
|
6
6
|
# The Consumer resource class
|
7
7
|
#
|
8
|
-
# @see https://docs.konghq.com/
|
8
|
+
# @see https://docs.konghq.com/1.1.x/admin-api/#consumer-object Consumer API definition
|
9
9
|
class Consumer < Resource
|
10
10
|
property :username
|
11
11
|
property :custom_id
|
12
12
|
property :created_at, read_only: true, postprocess: true
|
13
|
+
property :tags, validate: true
|
13
14
|
|
14
15
|
def self.batch_import(data, verbose: false, test: false)
|
15
16
|
raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
|
@@ -18,12 +19,13 @@ module SkullIsland
|
|
18
19
|
resource = new
|
19
20
|
resource.username = resource_data['username']
|
20
21
|
resource.custom_id = resource_data['custom_id']
|
22
|
+
resource.tags = resource_data['tags'] if resource_data['tags']
|
21
23
|
resource.import_update_or_skip(index: index, verbose: verbose, test: test)
|
22
24
|
|
23
25
|
BasicauthCredential.batch_import(
|
24
26
|
(
|
25
27
|
resource_data.dig('credentials', 'basic-auth') || []
|
26
|
-
).map { |t| t.merge('
|
28
|
+
).map { |t| t.merge('consumer' => { 'id' => resource.id }) },
|
27
29
|
verbose: verbose,
|
28
30
|
test: test
|
29
31
|
)
|
@@ -31,7 +33,7 @@ module SkullIsland
|
|
31
33
|
KeyauthCredential.batch_import(
|
32
34
|
(
|
33
35
|
resource_data.dig('credentials', 'key-auth') || []
|
34
|
-
).map { |t| t.merge('
|
36
|
+
).map { |t| t.merge('consumer' => { 'id' => resource.id }) },
|
35
37
|
verbose: verbose,
|
36
38
|
test: test
|
37
39
|
)
|
@@ -75,6 +77,7 @@ module SkullIsland
|
|
75
77
|
hash = { 'username' => username, 'custom_id' => custom_id }
|
76
78
|
creds = credentials_for_export
|
77
79
|
hash['credentials'] = creds unless creds.empty?
|
80
|
+
hash['tags'] = tags if tags
|
78
81
|
[*options[:exclude]].each do |exclude|
|
79
82
|
hash.delete(exclude.to_s)
|
80
83
|
end
|
@@ -106,12 +109,12 @@ module SkullIsland
|
|
106
109
|
creds = {}
|
107
110
|
unless credentials['key-auth'].empty?
|
108
111
|
creds['key-auth'] = credentials['key-auth'].collect do |cred|
|
109
|
-
cred.export(exclude: '
|
112
|
+
cred.export(exclude: 'consumer')
|
110
113
|
end
|
111
114
|
end
|
112
115
|
unless credentials['basic-auth'].empty?
|
113
116
|
creds['basic-auth'] = credentials['basic-auth'].collect do |cred|
|
114
|
-
cred.export(exclude: '
|
117
|
+
cred.export(exclude: 'consumer')
|
115
118
|
end
|
116
119
|
end
|
117
120
|
creds
|
@@ -9,8 +9,8 @@ module SkullIsland
|
|
9
9
|
class KeyauthCredential < Resource
|
10
10
|
property :key, validate: true
|
11
11
|
property(
|
12
|
-
:
|
13
|
-
required: true, validate: true, preprocess: true, postprocess: true
|
12
|
+
:consumer,
|
13
|
+
required: true, validate: true, preprocess: true, postprocess: true
|
14
14
|
)
|
15
15
|
property :created_at, read_only: true, postprocess: true
|
16
16
|
|
@@ -20,7 +20,7 @@ module SkullIsland
|
|
20
20
|
data.each_with_index do |resource_data, index|
|
21
21
|
resource = new
|
22
22
|
resource.key = resource_data['key']
|
23
|
-
resource.delayed_set(:consumer, resource_data, '
|
23
|
+
resource.delayed_set(:consumer, resource_data, 'consumer')
|
24
24
|
resource.import_update_or_skip(index: index, verbose: verbose, test: test)
|
25
25
|
end
|
26
26
|
end
|
@@ -39,7 +39,7 @@ module SkullIsland
|
|
39
39
|
|
40
40
|
def export(options = {})
|
41
41
|
hash = { 'key' => key }
|
42
|
-
hash['
|
42
|
+
hash['consumer'] = "<%= lookup :consumer, '#{consumer.username}' %>" if consumer
|
43
43
|
[*options[:exclude]].each do |exclude|
|
44
44
|
hash.delete(exclude.to_s)
|
45
45
|
end
|
@@ -56,10 +56,10 @@ module SkullIsland
|
|
56
56
|
|
57
57
|
private
|
58
58
|
|
59
|
-
def
|
60
|
-
if value.is_a?(
|
59
|
+
def postprocess_consumer(value)
|
60
|
+
if value.is_a?(Hash)
|
61
61
|
Consumer.new(
|
62
|
-
entity:
|
62
|
+
entity: value,
|
63
63
|
lazy: true,
|
64
64
|
tainted: false
|
65
65
|
)
|
@@ -68,18 +68,18 @@ module SkullIsland
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
def
|
72
|
-
if input.is_a?(
|
71
|
+
def preprocess_consumer(input)
|
72
|
+
if input.is_a?(Hash)
|
73
73
|
input
|
74
74
|
else
|
75
|
-
input.id
|
75
|
+
{ 'id' => input.id }
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
79
|
# Used to validate {#consumer} on set
|
80
|
-
def
|
81
|
-
# allow either a Consumer object or a
|
82
|
-
value.is_a?(Consumer) || value.is_a?(
|
80
|
+
def validate_consumer(value)
|
81
|
+
# allow either a Consumer object or a Hash
|
82
|
+
value.is_a?(Consumer) || value.is_a?(Hash)
|
83
83
|
end
|
84
84
|
|
85
85
|
# Used to validate {#key} on set
|
@@ -5,16 +5,17 @@ module SkullIsland
|
|
5
5
|
module Resources
|
6
6
|
# The Plugin resource class
|
7
7
|
#
|
8
|
-
# @see https://docs.konghq.com/
|
8
|
+
# @see https://docs.konghq.com/1.1.x/admin-api/#plugin-object Plugin API definition
|
9
9
|
class Plugin < Resource
|
10
10
|
property :name
|
11
11
|
property :enabled, type: :boolean
|
12
|
-
|
12
|
+
property :run_on, validate: true
|
13
13
|
property :config, validate: true, preprocess: true, postprocess: true
|
14
|
-
property :
|
15
|
-
property :
|
16
|
-
property :
|
14
|
+
property :consumer, validate: true, preprocess: true, postprocess: true
|
15
|
+
property :route, validate: true, preprocess: true, postprocess: true
|
16
|
+
property :service, validate: true, preprocess: true, postprocess: true
|
17
17
|
property :created_at, read_only: true, postprocess: true
|
18
|
+
property :tags, validate: true
|
18
19
|
|
19
20
|
def self.batch_import(data, verbose: false, test: false)
|
20
21
|
raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
|
@@ -23,10 +24,12 @@ module SkullIsland
|
|
23
24
|
resource = new
|
24
25
|
resource.name = resource_data['name']
|
25
26
|
resource.enabled = resource_data['enabled']
|
27
|
+
resource.run_on = resource_data['run_on'] if resource_data['run_on']
|
26
28
|
resource.config = resource_data['config'].deep_sort if resource_data['config']
|
27
|
-
resource.
|
28
|
-
resource.delayed_set(:
|
29
|
-
resource.delayed_set(:
|
29
|
+
resource.tags = resource_data['tags'] if resource_data['tags']
|
30
|
+
resource.delayed_set(:consumer, resource_data, 'consumer')
|
31
|
+
resource.delayed_set(:route, resource_data, 'route')
|
32
|
+
resource.delayed_set(:service, resource_data, 'service')
|
30
33
|
resource.import_update_or_skip(index: index, verbose: verbose, test: test)
|
31
34
|
end
|
32
35
|
end
|
@@ -45,9 +48,10 @@ module SkullIsland
|
|
45
48
|
'enabled' => enabled?,
|
46
49
|
'config' => config.deep_sort
|
47
50
|
}
|
48
|
-
hash['
|
49
|
-
hash['
|
50
|
-
hash['
|
51
|
+
hash['consumer'] = "<%= lookup :consumer, '#{consumer.username}' %>" if consumer
|
52
|
+
hash['route'] = "<%= lookup :route, '#{route.name}' %>" if route
|
53
|
+
hash['service'] = "<%= lookup :service, '#{service.name}' %>" if service
|
54
|
+
hash['tags'] = tags if tags
|
51
55
|
[*options[:exclude]].each do |exclude|
|
52
56
|
hash.delete(exclude.to_s)
|
53
57
|
end
|
@@ -94,8 +98,7 @@ module SkullIsland
|
|
94
98
|
value.deep_sort
|
95
99
|
end
|
96
100
|
|
97
|
-
|
98
|
-
def postprocess_consumer_id(value)
|
101
|
+
def postprocess_consumer(value)
|
99
102
|
if value.is_a?(Hash)
|
100
103
|
Consumer.new(
|
101
104
|
entity: value,
|
@@ -113,19 +116,17 @@ module SkullIsland
|
|
113
116
|
end
|
114
117
|
end
|
115
118
|
|
116
|
-
|
117
|
-
def preprocess_consumer_id(input)
|
119
|
+
def preprocess_consumer(input)
|
118
120
|
if input.is_a?(Hash)
|
119
|
-
input
|
121
|
+
input
|
120
122
|
elsif input.is_a?(Consumer)
|
121
|
-
input.id
|
123
|
+
{ 'id' => input.id }
|
122
124
|
else
|
123
125
|
input
|
124
126
|
end
|
125
127
|
end
|
126
128
|
|
127
|
-
|
128
|
-
def postprocess_route_id(value)
|
129
|
+
def postprocess_route(value)
|
129
130
|
if value.is_a?(Hash)
|
130
131
|
Route.new(
|
131
132
|
entity: value,
|
@@ -143,19 +144,17 @@ module SkullIsland
|
|
143
144
|
end
|
144
145
|
end
|
145
146
|
|
146
|
-
|
147
|
-
def preprocess_route_id(input)
|
147
|
+
def preprocess_route(input)
|
148
148
|
if input.is_a?(Hash)
|
149
|
-
input
|
149
|
+
input
|
150
150
|
elsif input.is_a?(Route)
|
151
|
-
input.id
|
151
|
+
{ 'id' => input.id }
|
152
152
|
else
|
153
153
|
input
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
157
|
-
|
158
|
-
def postprocess_service_id(value)
|
157
|
+
def postprocess_service(value)
|
159
158
|
if value.is_a?(Hash)
|
160
159
|
Service.new(
|
161
160
|
entity: value,
|
@@ -173,12 +172,11 @@ module SkullIsland
|
|
173
172
|
end
|
174
173
|
end
|
175
174
|
|
176
|
-
|
177
|
-
def preprocess_service_id(input)
|
175
|
+
def preprocess_service(input)
|
178
176
|
if input.is_a?(Hash)
|
179
|
-
input
|
177
|
+
input
|
180
178
|
elsif input.is_a?(Service)
|
181
|
-
input.id
|
179
|
+
{ 'id' => input.id }
|
182
180
|
else
|
183
181
|
input
|
184
182
|
end
|
@@ -191,21 +189,27 @@ module SkullIsland
|
|
191
189
|
end
|
192
190
|
|
193
191
|
# Used to validate {#consumer} on set
|
194
|
-
def
|
192
|
+
def validate_consumer(value)
|
195
193
|
# allow either a Consumer object or a Hash of a specific structure
|
196
|
-
value.is_a?(Consumer) || value.is_a?(
|
194
|
+
value.is_a?(Consumer) || value.is_a?(Hash)
|
197
195
|
end
|
198
196
|
|
199
197
|
# Used to validate {#route} on set
|
200
|
-
def
|
198
|
+
def validate_route(value)
|
199
|
+
# allow either a Route object or a Hash of a specific structure
|
200
|
+
value.is_a?(Route) || value.is_a?(Hash)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Used to validate {#run_on} on set
|
204
|
+
def validate_run_on(value)
|
201
205
|
# allow either a Route object or a Hash of a specific structure
|
202
|
-
|
206
|
+
%w[first second all].include?(value)
|
203
207
|
end
|
204
208
|
|
205
209
|
# Used to validate {#service} on set
|
206
|
-
def
|
210
|
+
def validate_service(value)
|
207
211
|
# allow either a Service object or a Hash of a specific structure
|
208
|
-
value.is_a?(Service) || value.is_a?(
|
212
|
+
value.is_a?(Service) || value.is_a?(Hash)
|
209
213
|
end
|
210
214
|
end
|
211
215
|
end
|
@@ -5,8 +5,9 @@ module SkullIsland
|
|
5
5
|
module Resources
|
6
6
|
# The Route resource class
|
7
7
|
#
|
8
|
-
# @see https://docs.konghq.com/
|
8
|
+
# @see https://docs.konghq.com/1.1.x/admin-api/#route-object Route API definition
|
9
9
|
class Route < Resource
|
10
|
+
property :name
|
10
11
|
property :methods
|
11
12
|
property :paths
|
12
13
|
property :protocols, validate: true
|
@@ -14,23 +15,23 @@ module SkullIsland
|
|
14
15
|
property :regex_priority, validate: true
|
15
16
|
property :strip_path, type: :boolean
|
16
17
|
property :preserve_host, type: :boolean
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# property :sources
|
21
|
-
# property :destinations
|
18
|
+
property :snis, validate: true
|
19
|
+
property :sources
|
20
|
+
property :destinations
|
22
21
|
property :service, validate: true, preprocess: true, postprocess: true
|
23
22
|
property :created_at, read_only: true, postprocess: true
|
24
23
|
property :updated_at, read_only: true, postprocess: true
|
24
|
+
property :tags, validate: true
|
25
25
|
|
26
26
|
# rubocop:disable Metrics/CyclomaticComplexity
|
27
27
|
# rubocop:disable Metrics/PerceivedComplexity
|
28
|
+
# rubocop:disable Metrics/AbcSize
|
28
29
|
def self.batch_import(data, verbose: false, test: false)
|
29
30
|
raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
|
30
31
|
|
31
32
|
data.each_with_index do |rdata, index|
|
32
33
|
resource = new
|
33
|
-
|
34
|
+
resource.name = rdata['name']
|
34
35
|
resource.methods = rdata['methods'] if rdata['methods']
|
35
36
|
resource.paths = rdata['paths'] if rdata['paths']
|
36
37
|
resource.protocols = rdata['protocols'] if rdata['protocols']
|
@@ -38,21 +39,25 @@ module SkullIsland
|
|
38
39
|
resource.regex_priority = rdata['regex_priority'] if rdata['regex_priority']
|
39
40
|
resource.strip_path = rdata['strip_path'] unless rdata['strip_path'].nil?
|
40
41
|
resource.preserve_host = rdata['preserve_host'] unless rdata['preserve_host'].nil?
|
42
|
+
resource.snis = rdata['snis'] if rdata['snis']
|
43
|
+
resource.tags = rdata['tags'] if rdata['tags']
|
41
44
|
resource.delayed_set(:service, rdata, 'service')
|
42
45
|
resource.import_update_or_skip(index: index, verbose: verbose, test: test)
|
43
46
|
end
|
44
47
|
end
|
45
48
|
# rubocop:enable Metrics/CyclomaticComplexity
|
46
49
|
# rubocop:enable Metrics/PerceivedComplexity
|
50
|
+
# rubocop:enable Metrics/AbcSize
|
47
51
|
|
48
52
|
# Provides a collection of related {Plugin} instances
|
49
53
|
def plugins
|
50
54
|
Plugin.where(:route, self, api_client: api_client)
|
51
55
|
end
|
52
56
|
|
57
|
+
# rubocop:disable Metrics/AbcSize
|
53
58
|
def export(options = {})
|
54
59
|
hash = {
|
55
|
-
|
60
|
+
'name' => name,
|
56
61
|
'methods' => methods,
|
57
62
|
'paths' => paths,
|
58
63
|
'protocols' => protocols,
|
@@ -61,7 +66,9 @@ module SkullIsland
|
|
61
66
|
'strip_path' => strip_path?,
|
62
67
|
'preserve_host' => preserve_host?
|
63
68
|
}
|
64
|
-
hash['service'] =
|
69
|
+
hash['service'] = "<%= lookup :service, '#{service.name}' %>" if service
|
70
|
+
hash['snis'] = snis if snis && !snis.empty?
|
71
|
+
hash['tags'] = tags if tags
|
65
72
|
[*options[:exclude]].each do |exclude|
|
66
73
|
hash.delete(exclude.to_s)
|
67
74
|
end
|
@@ -70,15 +77,13 @@ module SkullIsland
|
|
70
77
|
end
|
71
78
|
hash.reject { |_, value| value.nil? }
|
72
79
|
end
|
80
|
+
# rubocop:enable Metrics/AbcSize
|
73
81
|
|
74
82
|
def modified_existing?
|
75
83
|
return false unless new?
|
76
84
|
|
77
|
-
# Find routes of the same
|
78
|
-
same_name_and_service = self.class.where(:
|
79
|
-
.and(:hosts, hosts)
|
80
|
-
.and(:paths, paths)
|
81
|
-
.and(:service, service)
|
85
|
+
# Find routes of the same name and service
|
86
|
+
same_name_and_service = self.class.where(:name, name).and(:service, service)
|
82
87
|
|
83
88
|
existing = same_name_and_service.size == 1 ? same_name_and_service.first : nil
|
84
89
|
|
@@ -140,6 +145,17 @@ module SkullIsland
|
|
140
145
|
# allow either a Service object or a Hash of a specific structure
|
141
146
|
value.is_a?(Service) || (value.is_a?(Hash) && value['id'].is_a?(String))
|
142
147
|
end
|
148
|
+
|
149
|
+
# Used to validate {#snis} on set
|
150
|
+
def validate_snis(value)
|
151
|
+
return false unless value.is_a?(Array)
|
152
|
+
|
153
|
+
# allow only valid hostnames
|
154
|
+
value.each do |sni|
|
155
|
+
return false unless sni.match?(host_regex) && !sni.match?(/_/)
|
156
|
+
end
|
157
|
+
true
|
158
|
+
end
|
143
159
|
end
|
144
160
|
end
|
145
161
|
end
|
@@ -5,7 +5,7 @@ module SkullIsland
|
|
5
5
|
module Resources
|
6
6
|
# The Service resource class
|
7
7
|
#
|
8
|
-
# @see https://docs.konghq.com/
|
8
|
+
# @see https://docs.konghq.com/1.1.x/admin-api/#service-object Service API definition
|
9
9
|
class Service < Resource
|
10
10
|
property :name
|
11
11
|
property :retries
|
@@ -18,6 +18,7 @@ module SkullIsland
|
|
18
18
|
property :read_timeout, validate: true
|
19
19
|
property :created_at, read_only: true, postprocess: true
|
20
20
|
property :updated_at, read_only: true, postprocess: true
|
21
|
+
property :tags, validate: true
|
21
22
|
|
22
23
|
# rubocop:disable Metrics/CyclomaticComplexity
|
23
24
|
# rubocop:disable Metrics/PerceivedComplexity
|
@@ -36,6 +37,7 @@ module SkullIsland
|
|
36
37
|
resource.connect_timeout = rdata['connect_timeout'] if rdata['connect_timeout']
|
37
38
|
resource.write_timeout = rdata['write_timeout'] if rdata['write_timeout']
|
38
39
|
resource.read_timeout = rdata['read_timeout'] if rdata['read_timeout']
|
40
|
+
resource.tags = rdata['tags'] if rdata['tags']
|
39
41
|
resource.import_update_or_skip(index: index, verbose: verbose, test: test)
|
40
42
|
|
41
43
|
Route.batch_import(
|
@@ -80,6 +82,7 @@ module SkullIsland
|
|
80
82
|
'read_timeout' => read_timeout
|
81
83
|
}
|
82
84
|
hash['routes'] = routes.collect { |route| route.export(exclude: 'service') }
|
85
|
+
hash['tags'] = tags if tags
|
83
86
|
[*options[:exclude]].each do |exclude|
|
84
87
|
hash.delete(exclude.to_s)
|
85
88
|
end
|
@@ -5,7 +5,7 @@ module SkullIsland
|
|
5
5
|
module Resources
|
6
6
|
# The Upstream resource class
|
7
7
|
#
|
8
|
-
# @see https://docs.konghq.com/
|
8
|
+
# @see https://docs.konghq.com/1.1.x/admin-api/#upstream-objects Upstream API definition
|
9
9
|
class Upstream < Resource
|
10
10
|
property :name, required: true, validate: true
|
11
11
|
property :slots, validate: true
|
@@ -17,6 +17,7 @@ module SkullIsland
|
|
17
17
|
property :hash_on_cookie_path, validate: true
|
18
18
|
property :healthchecks, validate: true
|
19
19
|
property :created_at, read_only: true, postprocess: true
|
20
|
+
property :tags, validate: true
|
20
21
|
|
21
22
|
# rubocop:disable Metrics/CyclomaticComplexity
|
22
23
|
# rubocop:disable Metrics/PerceivedComplexity
|
@@ -39,11 +40,12 @@ module SkullIsland
|
|
39
40
|
resource.hash_on_cookie_path = rdata['hash_on_cookie_path']
|
40
41
|
end
|
41
42
|
resource.healthchecks = rdata['healthchecks'] if rdata['healthchecks']
|
43
|
+
resource.tags = rdata['tags'] if rdata['tags']
|
42
44
|
resource.import_update_or_skip(index: index, verbose: verbose, test: test)
|
43
45
|
puts '[INFO] Processing UpstreamTarget entries...' if verbose
|
44
46
|
|
45
47
|
UpstreamTarget.batch_import(
|
46
|
-
(rdata['targets'] || []).map { |t| t.merge('
|
48
|
+
(rdata['targets'] || []).map { |t| t.merge('upstream' => { 'id' => resource.id }) },
|
47
49
|
verbose: verbose,
|
48
50
|
test: test
|
49
51
|
)
|
@@ -77,7 +79,7 @@ module SkullIsland
|
|
77
79
|
|
78
80
|
def target(target_id)
|
79
81
|
UpstreamTarget.new(
|
80
|
-
entity: { 'id' => target_id, '
|
82
|
+
entity: { 'id' => target_id, 'upstream' => { 'id' => id } },
|
81
83
|
lazy: true,
|
82
84
|
tainted: false,
|
83
85
|
api_client: api_client
|
@@ -116,6 +118,7 @@ module SkullIsland
|
|
116
118
|
'healthchecks' => healthchecks
|
117
119
|
}
|
118
120
|
hash['targets'] = targets.collect { |route| route.export(exclude: 'upstream_id') }
|
121
|
+
hash['tags'] = tags if tags
|
119
122
|
[*options[:exclude]].each do |exclude|
|
120
123
|
hash.delete(exclude.to_s)
|
121
124
|
end
|
@@ -5,15 +5,16 @@ module SkullIsland
|
|
5
5
|
module Resources
|
6
6
|
# The Upstream Target resource class
|
7
7
|
#
|
8
|
-
# @see https://docs.konghq.com/
|
8
|
+
# @see https://docs.konghq.com/1.1.x/admin-api/#target-object Target API definition
|
9
9
|
class UpstreamTarget < Resource
|
10
10
|
property :target, required: true, validate: true, preprocess: true
|
11
11
|
property(
|
12
|
-
:
|
13
|
-
required: true, validate: true, preprocess: true, postprocess: true
|
12
|
+
:upstream,
|
13
|
+
required: true, validate: true, preprocess: true, postprocess: true
|
14
14
|
)
|
15
15
|
property :weight, validate: true
|
16
16
|
property :created_at, read_only: true, postprocess: true
|
17
|
+
property :tags, validate: true
|
17
18
|
|
18
19
|
def self.batch_import(data, verbose: false, test: false)
|
19
20
|
raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
|
@@ -21,8 +22,9 @@ module SkullIsland
|
|
21
22
|
data.each_with_index do |resource_data, index|
|
22
23
|
resource = new
|
23
24
|
resource.target = resource_data['target']
|
24
|
-
resource.delayed_set(:upstream, resource_data, '
|
25
|
+
resource.delayed_set(:upstream, resource_data, 'upstream')
|
25
26
|
resource.weight = resource_data['weight'] if resource_data['weight']
|
27
|
+
resource.tags = resource_data['tags'] if resource_data['tags']
|
26
28
|
resource.import_update_or_skip(index: index, verbose: verbose, test: test)
|
27
29
|
end
|
28
30
|
end
|
@@ -46,7 +48,8 @@ module SkullIsland
|
|
46
48
|
|
47
49
|
def export(options = {})
|
48
50
|
hash = { 'target' => target, 'weight' => weight }
|
49
|
-
hash['
|
51
|
+
hash['upstream'] = "<%= lookup :upstream, '#{upstream.name}' %>" if upstream
|
52
|
+
hash['tags'] = tags if tags
|
50
53
|
[*options[:exclude]].each do |exclude|
|
51
54
|
hash.delete(exclude.to_s)
|
52
55
|
end
|
@@ -82,20 +85,20 @@ module SkullIsland
|
|
82
85
|
end
|
83
86
|
end
|
84
87
|
|
85
|
-
def
|
88
|
+
def preprocess_upstream(input)
|
86
89
|
if input.is_a?(Hash)
|
87
|
-
input['id']
|
88
|
-
elsif input.is_a?(String)
|
89
90
|
input
|
91
|
+
elsif input.is_a?(String)
|
92
|
+
{ 'id' => input }
|
90
93
|
else
|
91
|
-
input.id
|
94
|
+
{ 'id' => input.id }
|
92
95
|
end
|
93
96
|
end
|
94
97
|
|
95
|
-
def
|
96
|
-
if value.is_a?(
|
98
|
+
def postprocess_upstream(value)
|
99
|
+
if value.is_a?(Hash)
|
97
100
|
Upstream.new(
|
98
|
-
entity:
|
101
|
+
entity: value,
|
99
102
|
lazy: true,
|
100
103
|
tainted: false
|
101
104
|
)
|
@@ -113,9 +116,9 @@ module SkullIsland
|
|
113
116
|
end
|
114
117
|
|
115
118
|
# Used to validate #upstream on set
|
116
|
-
def
|
117
|
-
# allow either a Upstream object or a
|
118
|
-
value.is_a?(Upstream) || value.is_a?(String)
|
119
|
+
def validate_upstream(value)
|
120
|
+
# allow either a Upstream object or a Hash
|
121
|
+
value.is_a?(Upstream) || value.is_a?(Hash) || value.is_a?(String)
|
119
122
|
end
|
120
123
|
|
121
124
|
# Used to validate {#weight} on set
|
@@ -19,6 +19,15 @@ module SkullIsland
|
|
19
19
|
raise Exceptions::InvalidArguments if data[name.to_s].nil?
|
20
20
|
end
|
21
21
|
end
|
22
|
+
|
23
|
+
# Used to validate #tags on set
|
24
|
+
def validate_tags(value)
|
25
|
+
# allow only valid hostnames
|
26
|
+
value.each do |tag|
|
27
|
+
return false unless tag.is_a?(String) && tag.match?(/\w_-\.~/)
|
28
|
+
end
|
29
|
+
true
|
30
|
+
end
|
22
31
|
end
|
23
32
|
end
|
24
33
|
end
|
data/lib/skull_island/version.rb
CHANGED
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:
|
4
|
+
version: 1.1.1
|
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-05-
|
11
|
+
date: 2019-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: deepsort
|
@@ -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/migration.rb
|
245
246
|
- lib/skull_island/helpers/resource.rb
|
246
247
|
- lib/skull_island/helpers/resource_class.rb
|
247
248
|
- lib/skull_island/lru_cache.rb
|