skull_island 1.2.13 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c66eccbdc4037117f866cbb422ad0e551471e231e5137d90b8924a38a904d630
4
- data.tar.gz: bd1ee46f5e880b8cfeda56acbacfb99c81fa679e46aac45defefb21f7c4b0035
3
+ metadata.gz: 1cd4dad5c51622b123e9a28d07515e340fd3bf2aa2633edc408df2eb7016eef2
4
+ data.tar.gz: 91f778ff415330fb0c8c2c6f3118c6c894a76c77b42338ff345ff0848b0fd332
5
5
  SHA512:
6
- metadata.gz: 32a3f5c1fcd0e54b9df82880c564d0e4a4af6f8482c67d5ca41e9e977c77d3c6b5684c55ff0198af909404abf6f2a085e1c605d13afea2d5436e22c9872683b9
7
- data.tar.gz: 148b3e4fcfe3c21a25903571230fa6f5bc61c3b682b17cb2e4021e3d3527ceaecc8ce24376b0d16511afd0e5b3af7cd02b6a22c7677a512e861d1290b94b7a56
6
+ metadata.gz: 820eb9e9833274cf58dce2b3200c55bdddb29adf331457141a76a517048b33e1ee86d823a0367f32207ec4ec4287046f9b2f35e4f35f12daebcd3a215eb163a8
7
+ data.tar.gz: 13027398c076a86a7eee66824e72ed848cd0bce3d063a4f6ac441929c79379541ef2946669385dc2fc6c5c0c50ee3d1c1d4e1a28349f4195c93a04061ab942b2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- skull_island (1.2.13)
4
+ skull_island (1.4.0)
5
5
  deepsort (~> 0.4)
6
6
  erubi (~> 1.8)
7
7
  json (~> 2.1)
@@ -53,7 +53,7 @@ GEM
53
53
  linguistics (2.1.0)
54
54
  loggability (~> 0.11)
55
55
  loggability (0.14.0)
56
- mime-types (3.3.1)
56
+ mime-types (3.3)
57
57
  mime-types-data (~> 3.2015)
58
58
  mime-types-data (3.2019.1009)
59
59
  multi_json (1.14.1)
@@ -62,7 +62,7 @@ GEM
62
62
  net-http-pipeline (1.0.1)
63
63
  netrc (0.11.0)
64
64
  parallel (1.19.1)
65
- parser (2.7.0.1)
65
+ parser (2.6.5.0)
66
66
  ast (~> 2.4.0)
67
67
  pusher-client (0.6.2)
68
68
  json
@@ -78,15 +78,15 @@ GEM
78
78
  rspec-core (~> 3.9.0)
79
79
  rspec-expectations (~> 3.9.0)
80
80
  rspec-mocks (~> 3.9.0)
81
- rspec-core (3.9.1)
82
- rspec-support (~> 3.9.1)
81
+ rspec-core (3.9.0)
82
+ rspec-support (~> 3.9.0)
83
83
  rspec-expectations (3.9.0)
84
84
  diff-lcs (>= 1.2.0, < 2.0)
85
85
  rspec-support (~> 3.9.0)
86
86
  rspec-mocks (3.9.0)
87
87
  diff-lcs (>= 1.2.0, < 2.0)
88
88
  rspec-support (~> 3.9.0)
89
- rspec-support (3.9.2)
89
+ rspec-support (3.9.0)
90
90
  rubocop (0.78.0)
91
91
  jaro_winkler (~> 1.5.1)
92
92
  parallel (~> 1.10)
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Skull Island
2
2
 
3
- A full-featured SDK for [Kong](https://konghq.com/kong/) 1.1.x/1.2.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).
3
+ A full-featured SDK for [Kong](https://konghq.com/kong/) 1.4.x (with support for migrating from 0.14.x, 1.1.x, and 1.2.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
  ![Gem](https://img.shields.io/gem/v/skull_island)
6
6
  ![Travis (.org)](https://img.shields.io/travis/jgnagy/skull_island)
@@ -30,7 +30,7 @@ gem install skull_island
30
30
  Or add this to your Gemfile:
31
31
 
32
32
  ```ruby
33
- gem 'skull_island', '~> 1.2'
33
+ gem 'skull_island', '~> 1.4'
34
34
  ```
35
35
 
36
36
  Or add this to your .gemspec:
@@ -38,7 +38,7 @@ Or add this to your .gemspec:
38
38
  ```ruby
39
39
  Gem::Specification.new do |spec|
40
40
  # ...
41
- spec.add_runtime_dependency 'skull_island', '~> 1.2'
41
+ spec.add_runtime_dependency 'skull_island', '~> 1.4'
42
42
  # ...
43
43
  end
44
44
  ```
@@ -47,7 +47,7 @@ end
47
47
 
48
48
  Skull Island comes with an executable called `skull_island` that leverages the SDK under the hood. Learn about what it can do via `help`:
49
49
 
50
- ```
50
+ ```sh
51
51
  $ skull_island help
52
52
  Commands:
53
53
  skull_island export [OPTIONS] [OUTPUT|-] # Export the current configuration to OUTPUT
@@ -63,7 +63,7 @@ Options:
63
63
 
64
64
  To use the commands that interact with the Kong API, set environment variables for the required parameters:
65
65
 
66
- ```
66
+ ```sh
67
67
  KONG_ADMIN_URL='https://api-admin.mydomain.com' \
68
68
  KONG_ADMIN_USERNAME='my-basicauth-user' \
69
69
  KONG_ADMIN_PASSWORD='my-basicauth-password' \
@@ -74,7 +74,7 @@ Note that you can skip `KONG_ADMIN_USERNAME` and `KONG_ADMIN_PASSWORD` if you ar
74
74
 
75
75
  Also note that if you're having SSL issues (such as with a private CA), you can have Ruby make use of a custom CA public key using `SSL_CERT_FILE`:
76
76
 
77
- ```
77
+ ```sh
78
78
  SSL_CERT_FILE=/path/to/cabundle.pem \
79
79
  KONG_ADMIN_URL='https://api-admin.mydomain.com' \
80
80
  KONG_ADMIN_USERNAME='my-basicauth-user' \
@@ -88,14 +88,14 @@ The CLI allows you to export an existing configuration to a YAML + ERB document
88
88
 
89
89
  The `export` command will default to outputting to STDOUT if you don't provide an output file location. Otherwise, simply specify the filename you'd like to export to:
90
90
 
91
- ```
91
+ ```sh
92
92
  KONG_ADMIN_URL='https://api-admin.mydomain.com' \
93
93
  skull_island export /path/to/export.yml
94
94
  ```
95
95
 
96
96
  You can also get a little more information by turning on `--verbose`:
97
97
 
98
- ```
98
+ ```sh
99
99
  KONG_ADMIN_URL='https://api-admin.mydomain.com' \
100
100
  skull_island export --verbose /path/to/export.yml
101
101
  ```
@@ -110,14 +110,14 @@ For most credential types, exporting works as expected (you'll see the plaintext
110
110
 
111
111
  Skull Island also supports importing configurations (both partial and full) from a YAML + ERB document:
112
112
 
113
- ```
113
+ ```sh
114
114
  KONG_ADMIN_URL='https://api-admin.mydomain.com' \
115
115
  skull_island import /path/to/export.yml
116
116
  ```
117
117
 
118
118
  It'll also read from STDIN if you don't specify a file path (or if you specify `-` as the path):
119
119
 
120
- ```
120
+ ```sh
121
121
  cat /path/to/export.yml | KONG_ADMIN_URL='https://api-admin.mydomain.com' skull_island import
122
122
  # OR
123
123
  KONG_ADMIN_URL='https://api-admin.mydomain.com' skull_island import < /path/to/export.yml
@@ -125,14 +125,14 @@ KONG_ADMIN_URL='https://api-admin.mydomain.com' skull_island import < /path/to/e
125
125
 
126
126
  You can also get a little more information by turning on `--verbose`:
127
127
 
128
- ```
128
+ ```sh
129
129
  KONG_ADMIN_URL='https://api-admin.mydomain.com' \
130
130
  skull_island import --verbose /path/to/export.yml
131
131
  ```
132
132
 
133
133
  Importing also supports a "dry run" functionality that shows you what it would do (but makes no changes) using `--test`:
134
134
 
135
- ```
135
+ ```sh
136
136
  KONG_ADMIN_URL='https://api-admin.mydomain.com' \
137
137
  skull_island import --verbose --test /path/to/export.yml
138
138
  ```
@@ -141,7 +141,7 @@ Note that `--test` has a high likelihood of generating errors with a complicated
141
141
 
142
142
  #### Importing with Projects
143
143
 
144
- 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.
144
+ Skull Island 1.2.1 introduced 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.
145
145
 
146
146
  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.
147
147
 
@@ -149,17 +149,17 @@ When using the `project` feature of Skull Island, the CLI tool will automaticall
149
149
 
150
150
  ### Migrating
151
151
 
152
- 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:
152
+ With Skull Island, it is possible to migrate a configuration from a 0.14.x, 1.1.x, or 1.2.x gateway to the most recent compatible gateway. If you have a previous export, you can just run `skull_island migrate /path/to/export.yml` and you'll receive a 1.4 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:
153
153
 
154
- ```
154
+ ```sh
155
155
  skull_island migrate /path/to/export.yml /output/location/migrated.yml
156
156
  ```
157
157
 
158
- 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.
158
+ While this hasn't been heavily tested for all possible use-cases, any configuration generated or usable by the `'~> 0.14'` or `'~> 1.2'` 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.
159
159
 
160
- 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.
160
+ If you don't have a previous export, you'll need to install an older version of this gem using something like `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.
161
161
 
162
- 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+.
162
+ 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 are used heavily by skull_island. 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 and beyond.
163
163
 
164
164
  ### Reset A Gateway
165
165
 
@@ -167,7 +167,7 @@ Skull Island can completely clear the configuration from a Kong instance using t
167
167
 
168
168
  Fully resetting a gateway looks like this:
169
169
 
170
- ```
170
+ ```sh
171
171
  skull_island reset --force
172
172
  ```
173
173
 
@@ -175,7 +175,7 @@ You can, of course, include `--verbose` to see `skull_island` do its work, thoug
175
175
 
176
176
  You can also restrict the reset to just resources associated with a particular project using the `--project` flag:
177
177
 
178
- ```
178
+ ```sh
179
179
  skull_island reset --force --project foo
180
180
  ```
181
181
 
@@ -185,10 +185,10 @@ This assumes the project is called `foo`.
185
185
 
186
186
  If you're wondering what version of `skull_island` is installed, use:
187
187
 
188
- ```
188
+ ```sh
189
189
  $ skull_island version
190
190
 
191
- SkullIsland Version: 1.2.5
191
+ SkullIsland Version: 1.4.1
192
192
  ```
193
193
 
194
194
  ### File Format
@@ -197,9 +197,14 @@ The import/export/migrate CLI functions produce YAML with support for embedded R
197
197
 
198
198
  ```yaml
199
199
  ---
200
- version: '1.2'
200
+ version: '1.4'
201
201
  project: FooV2
202
202
  certificates: []
203
+ ca_certificates:
204
+ - cert: |-
205
+ -----BEGIN CERTIFICATE-----
206
+ MIIFUzCCA...
207
+ -----END CERTIFICATE-----
203
208
  consumers:
204
209
  - username: foo
205
210
  custom_id: foo
@@ -265,9 +270,9 @@ plugins:
265
270
  service: "<%= lookup :service, 'search_api' %>"
266
271
  ```
267
272
 
268
- 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.
273
+ 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 (`[]`), or they can be omitted entirely which is the same as providing 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.
269
274
 
270
- Note that while this configuration looks a lot like the [DB-less](https://docs.konghq.com/1.1.x/db-less-and-declarative-config/) configuration (and even may, at times, be interchangeable), this is merely a coincidence. **Skull Island doesn't support the DB-less mode for Kong.** This may potentially change in the future, but for now it is not a goal of this project.
275
+ Note that while this configuration looks a lot like the [DB-less](https://docs.konghq.com/1.4.x/db-less-and-declarative-config/) configuration (and even may, at times, be interchangeable), this is merely a coincidence. **Skull Island doesn't support the DB-less mode for Kong.** This may potentially change in the future, but for now it is not a goal of this project.
271
276
 
272
277
  #### Embedded Ruby
273
278
 
@@ -277,6 +282,8 @@ While technically _any_ Ruby is valid, the following are pretty helpful for temp
277
282
 
278
283
  * `ENV.fetch('VARIABLE_NAME', 'default value')` - This allows looking up the environment variable `VARIABLE_NAME` and using its value, or, if it isn't defined, it uses `default value` as the value. With this we could change `host: api.example.com` to `host: <%= ENV.fetch('API_HOST', 'api.example.com') %>`. With this, if `API_HOST` is provided, it'll use that, otherwise it will default to `api.example.com`. This is especially helpful for sensitive information; you can version control the configuration but pass in things like credentials via environment variables at runtime.
279
284
 
285
+ Note also that 1.4.x and beyond of Skull Island support two phases of embedded ruby: first, a simple phase that treats the **entire file** as just text, allowing you to use the full power of ruby for things like loops, conditional logic, and more; the second phase is applied for individual attributes within the rendered YAML document. This is where the `lookup()` function above is used.
286
+
280
287
  ## SDK Usage
281
288
 
282
289
  The API Client requires configuration before it can be used. For now, this is a matter of calling `APIClient.configure()`, passing a Hash, with Symbols for keys:
@@ -391,7 +398,26 @@ service.routes.size
391
398
  # => 4
392
399
  ```
393
400
 
394
- From here, the SDK mostly wraps the attributes described in the [Kong API Docs](https://docs.konghq.com/1.2.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.
401
+ From here, the SDK mostly wraps the attributes described in the [Kong API Docs](https://docs.konghq.com/1.4.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.
402
+
403
+ #### CA Certificates
404
+
405
+ These are used by the gateway to verify upstream certificates when connecting to them via HTTPS. These are not used to allow Kong to _generate_ certificates. Thus, there is only a public key (`cert`) attribute for this resource.
406
+
407
+ ```ruby
408
+ resource = Resources::CACertificate.new
409
+
410
+ # These attributes can be set and read
411
+ resource.cert = '-----BEGIN CERTIFICATE-----...' # PEM-encoded public key
412
+ resource.tags = ['production', 'example'] # Array of tags
413
+ resource.save
414
+
415
+ # These attributes are read-only
416
+ resource.id
417
+ # => "1cad3055-1027-459d-b76e-f590dc5f0071"
418
+ resource.created_at
419
+ # => #<DateTime: 2018-07-17T12:51:28+00:00 ((2458317j,46288s,0n),+0s,2299161j)>
420
+ ```
395
421
 
396
422
  #### Certificates
397
423
 
@@ -554,6 +580,7 @@ resource = Resources::Service.new
554
580
 
555
581
  # These attributes can be set and read
556
582
  resource.protocol = 'http'
583
+ resource.client_certificate = { 'id' => '77e32ff2-...' }
557
584
  resource.connect_timeout = 60000
558
585
  resource.host = 'example.com'
559
586
  resource.port = 80
@@ -591,6 +618,7 @@ resource = Resources::Upstream.new
591
618
 
592
619
  # These attributes can be set and read
593
620
  resource.name = 'service.v1.xyz'
621
+ resource.algorithm = 'round-robin'
594
622
  resource.hash_on = 'none'
595
623
  resource.hash_fallback = 'none'
596
624
  resource.slots = 1000
@@ -11,6 +11,7 @@ module SkullIsland
11
11
  # Base CLI for SkullIsland
12
12
  class CLI < Thor
13
13
  include Helpers::Migration
14
+ include Helpers::CliErb
14
15
 
15
16
  class_option :verbose, type: :boolean
16
17
 
@@ -29,10 +30,11 @@ module SkullIsland
29
30
 
30
31
  validate_server_version
31
32
 
32
- output = { 'version' => '1.2' }
33
+ output = { 'version' => '1.4' }
33
34
  output['project'] = options['project'] if options['project']
34
35
 
35
36
  [
37
+ Resources::CACertificate,
36
38
  Resources::Certificate,
37
39
  Resources::Consumer,
38
40
  Resources::Upstream,
@@ -54,7 +56,7 @@ module SkullIsland
54
56
  raw ||= acquire_input(input_file, options['verbose'])
55
57
 
56
58
  # rubocop:disable Security/YAMLLoad
57
- input = YAML.load(raw)
59
+ input = YAML.load(erb_preprocess(raw))
58
60
  # rubocop:enable Security/YAMLLoad
59
61
 
60
62
  validate_config_version input['version']
@@ -63,12 +65,16 @@ module SkullIsland
63
65
  input['project'] = options['project'] if options['project']
64
66
 
65
67
  [
68
+ Resources::CACertificate,
66
69
  Resources::Certificate,
67
70
  Resources::Consumer,
68
71
  Resources::Upstream,
69
72
  Resources::Service,
70
73
  Resources::Plugin
71
- ].each { |clname| import_class(clname, input, import_time) }
74
+ ].each do |clname|
75
+ input[clname.route_key] = [] unless input[clname.route_key] # enforce all top-level keys
76
+ import_class(clname, input, import_time)
77
+ end
72
78
  end
73
79
 
74
80
  desc(
@@ -117,6 +123,7 @@ module SkullIsland
117
123
  warn '[WARN] ! FULLY Resetting gateway'
118
124
  end
119
125
  [
126
+ Resources::CACertificate,
120
127
  Resources::Certificate,
121
128
  Resources::Consumer,
122
129
  Resources::Upstream,
@@ -184,9 +191,9 @@ module SkullIsland
184
191
  end
185
192
 
186
193
  def validate_config_version(version)
187
- if version && ['1.1', '1.2'].include?(version)
194
+ if version && ['1.4'].include?(version)
188
195
  validate_server_version
189
- elsif version && ['0.14', '1.0'].include?(version)
196
+ elsif version && ['0.14', '1.0', '1.1', '1.2'].include?(version)
190
197
  warn '[CRITICAL] Config version is too old. Try `migrate` instead of `import`.'
191
198
  exit 2
192
199
  else
@@ -206,7 +213,7 @@ module SkullIsland
206
213
 
207
214
  def validate_server_version
208
215
  server_version = SkullIsland::APIClient.about_service['version']
209
- if server_version.match?(/^1.[12]/)
216
+ if server_version.match?(/^1.[4]/)
210
217
  true
211
218
  else
212
219
  warn '[CRITICAL] Server version mismatch!'
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SkullIsland
4
+ module Helpers
5
+ # Performs a simple, first pass ERb preprocess on the entire input file for the CLI
6
+ module CliErb
7
+ def erb_preprocess(input)
8
+ warn '[INFO] Preprocessing template' if options['verbose']
9
+ # rubocop:disable Security/Eval
10
+ eval(Erubi::Engine.new(input).src)
11
+ # rubocop:enable Security/Eval
12
+ end
13
+
14
+ # At this phase, we want to leave this alone...
15
+ def lookup(type, value)
16
+ "<%= lookup :#{type}, '#{value}' %>"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -6,7 +6,9 @@ module SkullIsland
6
6
  module Migration
7
7
  def migrate_config(config)
8
8
  if config['version'] == '0.14'
9
- migrate_0_14_to_1_1(config)
9
+ migrate_config migrate_0_14_to_1_1(config)
10
+ elsif ['1.1', '1.2', '1.3'].include?(config['version'])
11
+ migrate_1_1_to_1_4(config)
10
12
  else
11
13
  false # Just return false if it can't be migrated
12
14
  end
@@ -29,6 +31,12 @@ module SkullIsland
29
31
  new_config['version'] = '1.1'
30
32
  new_config
31
33
  end
34
+
35
+ def migrate_1_1_to_1_4(config)
36
+ new_config = config.dup
37
+ new_config['version'] = '1.4'
38
+ new_config
39
+ end
32
40
  end
33
41
  end
34
42
  end
@@ -16,7 +16,7 @@ module SkullIsland
16
16
 
17
17
  # rubocop:disable Style/GuardClause
18
18
  # rubocop:disable Security/Eval
19
- def delayed_set(property, data, key)
19
+ def delayed_set(property, data, key = property.to_s)
20
20
  if data[key]
21
21
  value = recursive_erubi(data[key])
22
22
  send(
@@ -21,8 +21,8 @@ module SkullIsland
21
21
 
22
22
  data.each_with_index do |resource_data, index|
23
23
  resource = new
24
- resource.delayed_set(:group, resource_data, 'group')
25
- resource.delayed_set(:consumer, resource_data, 'consumer')
24
+ resource.delayed_set(:group, resource_data)
25
+ resource.delayed_set(:consumer, resource_data)
26
26
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
27
27
  known_ids << resource.id
28
28
  end
@@ -24,9 +24,9 @@ module SkullIsland
24
24
 
25
25
  data.each_with_index do |resource_data, index|
26
26
  resource = new
27
- resource.delayed_set(:username, resource_data, 'username')
28
- resource.delayed_set(:password, resource_data, 'password') if resource_data['password']
29
- resource.delayed_set(:consumer, resource_data, 'consumer')
27
+ resource.delayed_set(:username, resource_data)
28
+ resource.delayed_set(:password, resource_data) if resource_data['password']
29
+ resource.delayed_set(:consumer, resource_data)
30
30
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
31
31
  known_ids << resource.id
32
32
  end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SkullIsland
4
+ # Resource classes go here...
5
+ module Resources
6
+ # The CA Certificate resource class
7
+ #
8
+ # @see https://docs.konghq.com/1.4.x/admin-api/#ca-certificate-object CA Certificate definition
9
+ class CACertificate < Resource
10
+ include Helpers::Meta
11
+
12
+ property :cert, required: true, validate: true
13
+ property :created_at, read_only: true, postprocess: true
14
+ property :tags, validate: true, preprocess: true, postprocess: true
15
+
16
+ def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
17
+ raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
18
+
19
+ known_ids = []
20
+
21
+ data.each_with_index do |resource_data, index|
22
+ resource = new
23
+ resource.delayed_set(:cert, resource_data)
24
+ resource.tags = resource_data['tags'] if resource_data['tags']
25
+ resource.project = project if project
26
+ resource.import_time = (time || Time.now.utc.to_i) if project
27
+ resource.import_update_or_skip(index: index, verbose: verbose, test: test)
28
+ known_ids << resource.id
29
+ end
30
+
31
+ cleanup_except(project, known_ids) if project
32
+ end
33
+
34
+ def export(options = {})
35
+ hash = { 'cert' => cert }
36
+ hash['tags'] = tags unless tags.empty?
37
+ [*options[:exclude]].each do |exclude|
38
+ hash.delete(exclude.to_s)
39
+ end
40
+ [*options[:include]].each do |inc|
41
+ hash[inc.to_s] = send(inc.to_sym)
42
+ end
43
+ hash.reject { |_, value| value.nil? }
44
+ end
45
+
46
+ def modified_existing?
47
+ return false unless new?
48
+
49
+ # Find CA certs of the same cert
50
+ same_cert = self.class.where(:cert, cert)
51
+
52
+ existing = same_cert.size == 1 ? same_cert.first : nil
53
+
54
+ if existing
55
+ @entity['id'] = existing.id
56
+ save
57
+ else
58
+ false
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ # Used to validate {#cert} on set
65
+ def validate_cert(value)
66
+ # only String is allowed
67
+ value.is_a?(String)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -24,8 +24,8 @@ module SkullIsland
24
24
 
25
25
  data.each_with_index do |resource_data, index|
26
26
  resource = new
27
- resource.delayed_set(:cert, resource_data, 'cert')
28
- resource.delayed_set(:key, resource_data, 'key')
27
+ resource.delayed_set(:cert, resource_data)
28
+ resource.delayed_set(:key, resource_data)
29
29
  resource.snis = resource_data['snis'] if resource_data['snis']
30
30
  resource.tags = resource_data['tags'] if resource_data['tags']
31
31
  resource.project = project if project
@@ -25,11 +25,9 @@ module SkullIsland
25
25
  data.each_with_index do |resource_data, index|
26
26
  resource = new
27
27
  resource.algorithm = resource_data['algorithm']
28
- resource.delayed_set(:key, resource_data, 'key') if resource_data['key']
29
- resource.delayed_set(:secret, resource_data, 'secret') if resource_data['secret']
30
- if resource_data['rsa_public_key']
31
- resource.delayed_set(:rsa_public_key, resource_data, 'rsa_public_key')
32
- end
28
+ resource.delayed_set(:key, resource_data) if resource_data['key']
29
+ resource.delayed_set(:secret, resource_data) if resource_data['secret']
30
+ resource.delayed_set(:rsa_public_key, resource_data) if resource_data['rsa_public_key']
33
31
  resource.delayed_set(:consumer, resource_data, 'consumer')
34
32
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
35
33
  known_ids << resource.id
@@ -21,8 +21,8 @@ module SkullIsland
21
21
 
22
22
  data.each_with_index do |resource_data, index|
23
23
  resource = new
24
- resource.delayed_set(:key, resource_data, 'key')
25
- resource.delayed_set(:consumer, resource_data, 'consumer')
24
+ resource.delayed_set(:key, resource_data)
25
+ resource.delayed_set(:consumer, resource_data)
26
26
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
27
27
  known_ids << resource.id
28
28
  end
@@ -31,13 +31,13 @@ module SkullIsland
31
31
  resource.name = resource_data['name']
32
32
  resource.enabled = resource_data['enabled']
33
33
  resource.run_on = resource_data['run_on'] if resource_data['run_on']
34
- resource.delayed_set(:config, resource_data, 'config') if resource_data['config']
34
+ resource.delayed_set(:config, resource_data) if resource_data['config']
35
35
  resource.tags = resource_data['tags'] if resource_data['tags']
36
36
  resource.project = project if project
37
37
  resource.import_time = (time || Time.now.utc.to_i) if project
38
- resource.delayed_set(:consumer, resource_data, 'consumer')
39
- resource.delayed_set(:route, resource_data, 'route')
40
- resource.delayed_set(:service, resource_data, 'service')
38
+ resource.delayed_set(:consumer, resource_data)
39
+ resource.delayed_set(:route, resource_data)
40
+ resource.delayed_set(:service, resource_data)
41
41
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
42
42
  known_ids << resource.id
43
43
  end
@@ -5,7 +5,7 @@ module SkullIsland
5
5
  module Resources
6
6
  # The Route resource class
7
7
  #
8
- # @see https://docs.konghq.com/1.1.x/admin-api/#route-object Route API definition
8
+ # @see https://docs.konghq.com/1.4.x/admin-api/#route-object Route API definition
9
9
  class Route < Resource
10
10
  include Helpers::Meta
11
11
 
@@ -13,7 +13,9 @@ module SkullIsland
13
13
  property :methods
14
14
  property :paths
15
15
  property :protocols, validate: true
16
+ property :headers, validate: true
16
17
  property :hosts, validate: true
18
+ property :https_redirect_status_code, validate: true
17
19
  property :regex_priority, validate: true
18
20
  property :strip_path, type: :boolean
19
21
  property :preserve_host, type: :boolean
@@ -39,15 +41,19 @@ module SkullIsland
39
41
  resource.methods = rdata['methods'] if rdata['methods']
40
42
  resource.paths = rdata['paths'] if rdata['paths']
41
43
  resource.protocols = rdata['protocols'] if rdata['protocols']
42
- resource.delayed_set(:hosts, rdata, 'hosts') if rdata['hosts']
44
+ resource.delayed_set(:hosts, rdata) if rdata['hosts']
45
+ resource.delayed_set(:headers, rdata) if rdata['headers']
46
+ if rdata['https_redirect_status_code']
47
+ resource.https_redirect_status_code = rdata['https_redirect_status_code']
48
+ end
43
49
  resource.regex_priority = rdata['regex_priority'] if rdata['regex_priority']
44
50
  resource.strip_path = rdata['strip_path'] unless rdata['strip_path'].nil?
45
51
  resource.preserve_host = rdata['preserve_host'] unless rdata['preserve_host'].nil?
46
- resource.delayed_set(:snis, rdata, 'snis') if rdata['snis']
52
+ resource.delayed_set(:snis, rdata) if rdata['snis']
47
53
  resource.tags = rdata['tags'] if rdata['tags']
48
54
  resource.project = project if project
49
55
  resource.import_time = (time || Time.now.utc.to_i) if project
50
- resource.delayed_set(:service, rdata, 'service')
56
+ resource.delayed_set(:service, rdata)
51
57
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
52
58
  known_ids << resource.id
53
59
  end
@@ -71,12 +77,14 @@ module SkullIsland
71
77
  'paths' => paths,
72
78
  'protocols' => protocols,
73
79
  'hosts' => hosts,
80
+ 'https_redirect_status_code' => https_redirect_status_code,
74
81
  'regex_priority' => regex_priority,
75
82
  'strip_path' => strip_path?,
76
83
  'preserve_host' => preserve_host?
77
84
  }
78
85
  hash['service'] = "<%= lookup :service, '#{service.name}' %>" if service
79
86
  hash['snis'] = snis if snis && !snis.empty?
87
+ hash['headers'] = headers if headers && !headers.empty?
80
88
  hash['tags'] = tags unless tags.empty?
81
89
  [*options[:exclude]].each do |exclude|
82
90
  hash.delete(exclude.to_s)
@@ -129,10 +137,19 @@ module SkullIsland
129
137
 
130
138
  # Used to validate {#protocols} on set
131
139
  def validate_protocols(value)
132
- value.is_a?(Array) && # Must be an array
133
- (1..4).cover?(value.size) && # Must be exactly 1..4 in size
134
- value.uniq == value && # Must not have duplicate values
135
- (value - %w[http https tls tcp]).empty? # Must only contain appropriate protocols
140
+ valid_protos = %w[http https tls tcp grpc grpcs]
141
+ value.is_a?(Array) && # Must be an array
142
+ (1..4).cover?(value.size) && # Must be exactly 1..4 in size
143
+ value.uniq == value && # Must not have duplicate values
144
+ (value - valid_protos).empty? # Must only contain appropriate protocols
145
+ end
146
+
147
+ # Validates the {#headers} on set
148
+ def validate_headers(value)
149
+ value.is_a?(Hash) &&
150
+ value.keys.map(&:class).uniq == [String] &&
151
+ value.values.map(&:class).uniq == [Array] &&
152
+ value.values.map { |v| v.map(&:class) }.flatten.uniq == [String]
136
153
  end
137
154
 
138
155
  # Used to validate {#hosts} on set
@@ -144,6 +161,11 @@ module SkullIsland
144
161
  true
145
162
  end
146
163
 
164
+ # Validates the {#https_redirect_status_code} on set
165
+ def validate_https_redirect_status_code(value)
166
+ value.is_a?(Integer) && value <= 599 && value >= 100
167
+ end
168
+
147
169
  # Used to validate {#regex_priority} on set
148
170
  def validate_regex_priority(value)
149
171
  # only positive Integers are allowed
@@ -18,6 +18,7 @@ module SkullIsland
18
18
  property :connect_timeout, validate: true
19
19
  property :write_timeout, validate: true
20
20
  property :read_timeout, validate: true
21
+ property :client_certificate, validate: true, preprocess: true, postprocess: true
21
22
  property :created_at, read_only: true, postprocess: true
22
23
  property :updated_at, read_only: true, postprocess: true
23
24
  property :tags, validate: true, preprocess: true, postprocess: true
@@ -35,12 +36,13 @@ module SkullIsland
35
36
  resource.name = rdata['name']
36
37
  resource.retries = rdata['retries'] if rdata['retries']
37
38
  resource.protocol = rdata['protocol']
38
- resource.delayed_set(:host, rdata, 'host')
39
- resource.delayed_set(:port, rdata, 'port')
39
+ resource.delayed_set(:host, rdata)
40
+ resource.delayed_set(:port, rdata)
40
41
  resource.path = rdata['path'] if rdata['path']
41
42
  resource.connect_timeout = rdata['connect_timeout'] if rdata['connect_timeout']
42
43
  resource.write_timeout = rdata['write_timeout'] if rdata['write_timeout']
43
44
  resource.read_timeout = rdata['read_timeout'] if rdata['read_timeout']
45
+ resource.delayed_set(:client_certificate, rdata) if rdata['client_certificate']
44
46
  resource.tags = rdata['tags'] if rdata['tags']
45
47
  resource.project = project if project
46
48
  resource.import_time = (time || Time.now.utc.to_i) if project
@@ -50,7 +52,9 @@ module SkullIsland
50
52
  Route.batch_import(
51
53
  (rdata['routes'] || []).map { |r| r.merge('service' => { 'id' => resource.id }) },
52
54
  verbose: verbose,
53
- test: test
55
+ test: test,
56
+ project: project,
57
+ time: time
54
58
  )
55
59
  end
56
60
 
@@ -83,6 +87,7 @@ module SkullIsland
83
87
  Plugin.where(:service, self, api_client: api_client)
84
88
  end
85
89
 
90
+ # rubocop:disable Metrics/AbcSize
86
91
  def export(options = {})
87
92
  hash = {
88
93
  'name' => name,
@@ -97,6 +102,7 @@ module SkullIsland
97
102
  }
98
103
  hash['routes'] = routes.collect { |route| route.export(exclude: 'service') }
99
104
  hash['tags'] = tags unless tags.empty?
105
+ hash['client_certificate'] = client_certificate if client_certificate
100
106
  [*options[:exclude]].each do |exclude|
101
107
  hash.delete(exclude.to_s)
102
108
  end
@@ -105,6 +111,7 @@ module SkullIsland
105
111
  end
106
112
  hash.reject { |_, value| value.nil? }
107
113
  end
114
+ # rubocop:enable Metrics/AbcSize
108
115
 
109
116
  def modified_existing?
110
117
  return false unless new?
@@ -139,6 +146,27 @@ module SkullIsland
139
146
 
140
147
  private
141
148
 
149
+ def postprocess_client_certificate(value)
150
+ if value.is_a?(Hash)
151
+ Certificate.new(
152
+ entity: value,
153
+ lazy: true,
154
+ tainted: false,
155
+ api_client: api_client
156
+ )
157
+ else
158
+ value
159
+ end
160
+ end
161
+
162
+ def preprocess_client_certificate(input)
163
+ if input.is_a?(Hash)
164
+ input
165
+ else
166
+ { 'id' => input.id }
167
+ end
168
+ end
169
+
142
170
  # Used to validate {#protocol} on set
143
171
  def validate_protocol(value)
144
172
  # only HTTP and HTTPS are allowed
@@ -10,6 +10,7 @@ module SkullIsland
10
10
  include Helpers::Meta
11
11
 
12
12
  property :name, required: true, validate: true
13
+ property :algorithm, validate: true
13
14
  property :slots, validate: true
14
15
  property :hash_on, validate: true
15
16
  property :hash_fallback, validate: true
@@ -18,6 +19,7 @@ module SkullIsland
18
19
  property :hash_on_cookie, validate: true
19
20
  property :hash_on_cookie_path, validate: true
20
21
  property :healthchecks, validate: true
22
+ property :host_header, validate: true
21
23
  property :created_at, read_only: true, postprocess: true
22
24
  property :tags, validate: true, preprocess: true, postprocess: true
23
25
 
@@ -32,6 +34,7 @@ module SkullIsland
32
34
  data.each_with_index do |rdata, index|
33
35
  resource = new
34
36
  resource.name = rdata['name']
37
+ resource.algorithm = rdata['algorithm'] if rdata['algorithm']
35
38
  resource.slots = rdata['slots'] if rdata['slots']
36
39
  resource.hash_on = rdata['hash_on']
37
40
  resource.hash_fallback = rdata['hash_fallback'] if rdata['hash_fallback']
@@ -44,6 +47,7 @@ module SkullIsland
44
47
  resource.hash_on_cookie_path = rdata['hash_on_cookie_path']
45
48
  end
46
49
  resource.healthchecks = rdata['healthchecks'] if rdata['healthchecks']
50
+ resource.host_header = rdata['host_header'] if rdata['host_header']
47
51
  resource.tags = rdata['tags'] if rdata['tags']
48
52
  resource.project = project if project
49
53
  resource.import_time = (time || Time.now.utc.to_i) if project
@@ -111,6 +115,7 @@ module SkullIsland
111
115
  )
112
116
  end
113
117
 
118
+ # rubocop:disable Metrics/AbcSize
114
119
  def export(options = {})
115
120
  hash = {
116
121
  'name' => name,
@@ -123,7 +128,9 @@ module SkullIsland
123
128
  'hash_on_cookie_path' => hash_on_cookie_path,
124
129
  'healthchecks' => healthchecks
125
130
  }
131
+ hash['algorithm'] = algorithm if algorithm
126
132
  hash['targets'] = targets.collect { |target| target.export(exclude: 'upstream') }
133
+ hash['host_header'] = host_header if host_header
127
134
  hash['tags'] = tags unless tags.empty?
128
135
  [*options[:exclude]].each do |exclude|
129
136
  hash.delete(exclude.to_s)
@@ -133,6 +140,7 @@ module SkullIsland
133
140
  end
134
141
  hash.reject { |_, value| value.nil? }
135
142
  end
143
+ # rubocop:enable Metrics/AbcSize
136
144
 
137
145
  def modified_existing?
138
146
  return false unless new?
@@ -152,6 +160,11 @@ module SkullIsland
152
160
 
153
161
  private
154
162
 
163
+ # Validates the upstream balancing {#algorithm}
164
+ def validate_algorithm(value)
165
+ %w[round-robin consistent-hashing least-connections].include?(value)
166
+ end
167
+
155
168
  # Used to validate {#hash_on} on set
156
169
  def validate_hash_on(value)
157
170
  # only String of an acceptable value are allowed
@@ -206,6 +219,12 @@ module SkullIsland
206
219
  # only Hash is allowed
207
220
  value.is_a?(Hash)
208
221
  end
222
+
223
+ # Enforces valid host headers for upstreams
224
+ def validate_host_header(value)
225
+ # allow only valid hostnames
226
+ value.match?(host_regex) && !value.match?(/_/)
227
+ end
209
228
  end
210
229
  end
211
230
  end
@@ -27,8 +27,8 @@ module SkullIsland
27
27
 
28
28
  data.each_with_index do |resource_data, index|
29
29
  resource = new
30
- resource.delayed_set(:target, resource_data, 'target')
31
- resource.delayed_set(:upstream, resource_data, 'upstream')
30
+ resource.delayed_set(:target, resource_data)
31
+ resource.delayed_set(:upstream, resource_data)
32
32
  resource.weight = resource_data['weight'] if resource_data['weight']
33
33
  resource.tags = resource_data['tags'] if resource_data['tags']
34
34
  resource.project = project if project
@@ -3,7 +3,7 @@
3
3
  module SkullIsland
4
4
  VERSION = [
5
5
  1, # Major
6
- 2, # Minor
7
- 13 # Patch
6
+ 4, # Minor
7
+ 0 # Patch
8
8
  ].join('.')
9
9
  end
data/lib/skull_island.rb CHANGED
@@ -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/cli_erb'
42
43
  require 'skull_island/helpers/meta'
43
44
  require 'skull_island/helpers/resource'
44
45
  require 'skull_island/helpers/resource_class'
@@ -46,6 +47,7 @@ require 'skull_island/helpers/migration'
46
47
  require 'skull_island/validations/resource'
47
48
  require 'skull_island/resource'
48
49
  require 'skull_island/resources/access_control_list'
50
+ require 'skull_island/resources/ca_certificate'
49
51
  require 'skull_island/resources/certificate'
50
52
  require 'skull_island/resources/basicauth_credential'
51
53
  require 'skull_island/resources/jwt_credential'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skull_island
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.13
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Gnagy
@@ -257,6 +257,7 @@ files:
257
257
  - lib/skull_island/exceptions/invalid_where_query.rb
258
258
  - lib/skull_island/exceptions/new_instance_with_id.rb
259
259
  - lib/skull_island/helpers/api_client.rb
260
+ - lib/skull_island/helpers/cli_erb.rb
260
261
  - lib/skull_island/helpers/meta.rb
261
262
  - lib/skull_island/helpers/migration.rb
262
263
  - lib/skull_island/helpers/resource.rb
@@ -266,6 +267,7 @@ files:
266
267
  - lib/skull_island/resource_collection.rb
267
268
  - lib/skull_island/resources/access_control_list.rb
268
269
  - lib/skull_island/resources/basicauth_credential.rb
270
+ - lib/skull_island/resources/ca_certificate.rb
269
271
  - lib/skull_island/resources/certificate.rb
270
272
  - lib/skull_island/resources/consumer.rb
271
273
  - lib/skull_island/resources/jwt_credential.rb