Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standalone configuration #926

Merged
merged 8 commits into from
Feb 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added "last" attribute in the mapping rules. When set to true indicates that, if the rule matches, APIcast should not try to match the rules placed after this one [PR #982](https://github.com/3scale/apicast/pull/982), [THREESCALE-1344](https://issues.jboss.org/browse/THREESCALE-1344)
- Added TLS Validation policy to verify TLS Client Certificate against a whitelist. [PR #966](https://github.com/3scale/apicast/pull/966), [THREESCALE-1671](https://issues.jboss.org/browse/THREESCALE-1671)
- New CLI command "push_policy" that pushes a policy schema to the 3scale admin portal [PR #986](https://github.com/3scale/apicast/pull/986), [THREESCALE-871](https://issues.jboss.org/browse/THREESCALE-871)
- Added support for experimental standalone YAML configuration [PR #926](https://github.com/3scale/apicast/pull/926)

### Changed

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ stop-development: ## Stop development environment
rover: $(ROVER)
@echo $(ROVER)

$(S2I_CONTEXT)/Roverfile.lock : $(S2I_CONTEXT)/Roverfile
$(S2I_CONTEXT)/Roverfile.lock : $(S2I_CONTEXT)/Roverfile $(S2I_CONTEXT)/apicast-scm-1.rockspec
$(ROVER) lock --roverfile=$(S2I_CONTEXT)/Roverfile

lua_modules: $(ROVER) $(S2I_CONTEXT)/Roverfile.lock
Expand Down
174 changes: 174 additions & 0 deletions examples/configuration/standalone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
global:
log_level: debug
error_log: stderr
access_log: stdout
opentracing_tracer: jaeger
upstream:
load_balancer: least_conn
retry: 5xx
retry_times: 3

# we can pretend this would be nested inside `servers` block in the future
server:
# nginx config options like client_body_timeout or send_timeout
listen:
- port: 8090
name: management
- port: 8081
name: echo # and also fake backend
- port: 8080
name: default # default would be the default name
- port: 8089
name: default # default would be the default name
proxy_protocol: true
- port: 8443
# name: default # several listen could have the same name
protocol: http2 # | spdy | http
tls: true
- port: 8444
name: default
protocol: http2 # | spdy | http
proxy_protocol: true
tls:
protocols: TLSv1.3
# those two could be the defaults as policies have ssl_certificate phase
certificate: conf/server.crt
certificate_key: conf/server.key
ciphers: "HIGH:!aNULL:!MD5"
- port: 9421
name: prometheus
tls:
protocols: TLSv1.3
# those two could be the defaults as policies have ssl_certificate phase
certificate: conf/server.crt
certificate_key: conf/server.key
ciphers:
- HIGH
- "!aNULL"
- "!MD5"

routes:
- # Route object
name: management
match:
# Condition DSL to be defined by Rate limit policy and Conditional policy evaluation
server_port: management # otherwise would match the default
destination: # Destination DSL, AB testing, traffic split, etc. to be extended in the future
service: management
policy_chain: management
upstream: management

- name: echo
match:
server_port: echo # otherwise would match the default
destination:
service: echo

- match:
server_port: prometheus
routes:
- match:
uri_path: '/metrics'
http_method: 'GET'
destination:
service: prometheus

- match:
http_method: 'POST'
destination:
http_response: 405

# I'd like to treat this as a route tree.
# If it matches all conditions of this rule then we can route it deeper.
# But if it does not match the child rules we should reject the request with 404 (or with some other policy).
destination:
service: not_found

- match:
http_host: auth.example.com
destination:
service: auth-server

- match:
server_port: default # could be ommited, default would be the default
destination:
service: 3scale

- match:
always: true
destination:
service: not_found

internal: # TODO: if we can figure out better name than "service" we would make our life much easier, vhost?

- name: auth-server
policy_chain:
- policy: example.authentication.server
configuration:
redis: external://redis

- name: 3scale
policy_chain:
- policy: apicast.policy.load_configuration
- policy: apicast.policy.find_service
- policy: apicast.policy.local_chain

- name: simple
policy_chain:
- policy: example.authentication.client
configuration:
server: internal://auth-server

upstream: http://echo-api.3scale.net

- name: echo
policy_chain:
- logging
# - echo
# upstream: http://echo-api.3scale.net
upstream: external://echo

- name: backend # this is fake backend
policy_chain:
- echo

- name: management
policy_chain:
- policy: apicast.policy.management
configuration:
mode: debug

- name: prometheus
policy_chain:
- policy: apicast.policy.prometheus

- name: echo
policy_chain:
- policy: apicast.policy.cors
configuration:
allow_methods: GET
allow_origin: '*'
- policy: apicast.policy.echo

- name: logging
policy_chain:
- policy: log
configuration:
url: syslog://localhost
fields: url, path, client_ip

external: # kind of like egress, but it could also be an internal service
# an abstraction for stubbing out external services with policies (fake backend vs external service)
- name: backend
server: https://su1.3scale.net
load_balancer: least_conn

- name: echo
server: https://echo-api.3scale.net
load_balancer: least_conn

- name: redis
server: tcp://localhost:6879
load_balancer: least_conn
retries: 3

5 changes: 3 additions & 2 deletions gateway/Roverfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ lua-resty-iputils 0.3.0-1||production
lua-resty-jit-uuid 0.0.7-1||production
lua-resty-jwt 0.2.0-0||production
lua-resty-repl 0.0.6-0||development
lua-resty-url 0.3.2-1||production
lua-resty-url 0.3.4-1||production
lua-term 0.7-1||testing
lua_cliargs 3.0-1||testing
luacov 0.13.0-1||testing
luafilesystem 1.7.0-2||production,development,testing
luassert 1.7.10-0||testing
luasystem 0.2.1-0||testing
lyaml 6.2.3-1||production
markdown 0.33-1||development
mediator_lua 1.1.2-0||testing
net-url 0.9-1||testing
nginx-lua-prometheus 0.20171117-4||production
penlight 1.5.4-1||production,development,testing
router 2.1-0||production
say 1.3-1||testing
say 1.3-1||testing
1 change: 1 addition & 0 deletions gateway/apicast-scm-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ description = {
dependencies = {
'lua-resty-http',
'inspect',
'lyaml',
'router',
'lua-resty-jwt',
'lua-resty-url',
Expand Down
2 changes: 1 addition & 1 deletion gateway/config/development.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ return {
lua_code_cache = 'on',
configuration_loader = 'lazy',
configuration_cache = 0,
configuration = data_url('application/json', configuration),
configuration = context.configuration or os.getenv('APICAST_CONFIGURATION') or data_url('application/json', configuration),
mikz marked this conversation as resolved.
Show resolved Hide resolved
port = { metrics = 9421 }, -- see https://github.com/prometheus/prometheus/wiki/Default-port-allocations,
timer_resolution = false,
}
34 changes: 34 additions & 0 deletions gateway/config/standalone.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
local PolicyChain = require('apicast.policy_chain')
local resty_url = require('resty.url')
local format = string.format

local function to_url(uri)
local url = resty_url.parse(uri)

if url then
return uri
elseif uri then
return format('file:%s', uri)
end
end

local standalone = assert(PolicyChain.load_policy(
'apicast.policy.standalone',
'builtin',
{ url = to_url(context.configuration) }))

if arg then -- running CLI to generate nginx config
mikz marked this conversation as resolved.
Show resolved Hide resolved
return {
template = 'http.d/standalone.conf.liquid',
standalone = standalone:load_configuration(),
configuration = standalone.url,
}

else -- booting APIcast
return {
policy_chain = PolicyChain.new{
standalone,
},
configuration = standalone.url,
}
end
2 changes: 1 addition & 1 deletion gateway/cpanfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
requires 'Test::APIcast', '0.17';
requires 'Test::APIcast', '0.19';
requires 'Crypt::JWT';
requires 'Test::Deep';
requires 'TAP::Harness::JUnit';
Expand Down
6 changes: 3 additions & 3 deletions gateway/cpanfile.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -495,10 +495,10 @@ DISTRIBUTIONS
Test::More 0
Time::HiRes 0
XML::Simple 0
Test-APIcast-0.17
pathname: M/MC/MCICHRA/Test-APIcast-0.17.tar.gz
Test-APIcast-0.19
pathname: M/MC/MCICHRA/Test-APIcast-0.19.tar.gz
provides:
Test::APIcast 0.17
Test::APIcast 0.19
Test::APIcast::Blackbox undef
requirements:
File::Slurp 0
Expand Down
67 changes: 67 additions & 0 deletions gateway/http.d/standalone.conf.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{% for server in standalone.server.listen %}
server {
listen {{ server.port }} default_server
{%- if server.tls %} ssl {% endif -%}
{%- case server.protocol -%}
{%- when 'http2' %}{{- server.protocol -}}
{%- when 'spdy' %}{{- server.protocol -}}
{%- endcase -%}
{%- if server.proxy_protocol %} proxy_protocol {% endif -%}
;

{% if server.tls.protocols -%}
ssl_protocols {{ server.tls.protocols | join: " " }};
{%- endif %}
{% if server.tls.certificate -%}
ssl_certificate {{ server.tls.certificate | filesystem | first }};
{%- endif %}
{% if server.tls.certificate_key -%}
ssl_certificate_key {{ server.tls.certificate_key | filesystem | first }};
{%- endif %}
{% if server.tls.ciphers -%}
ssl_ciphers {{ server.tls.ciphers | join: ":" }};
{%- endif %}

{%- capture server_name -%}{{ server.name | default: 'default' }}{%- endcapture %}
set $port_name {{ server_name }};
server_name {{ server_name }};

set $ctx_ref -1;
davidor marked this conversation as resolved.
Show resolved Hide resolved

location / {
rewrite_by_lua_block {
require('resty.ctx').stash()
require('apicast.executor'):rewrite()
}
access_by_lua_block { require('apicast.executor'):access() }
content_by_lua_block { require('apicast.executor'):content() }
post_action @post_action;
}

body_filter_by_lua_block { require('apicast.executor'):body_filter() }
header_filter_by_lua_block { require('apicast.executor'):header_filter() }

location @post_action {
internal;

proxy_pass_request_headers off;

rewrite_by_lua_block { require('resty.ctx').apply() }
content_by_lua_block { require('apicast.executor'):post_action() }
log_by_lua_block { require('apicast.executor'):log() }
}
}
{% endfor %}

{% for upstream in standalone.external %}
upstream {{ upstream.name }} {
server 0.0.0.1:1;

balancer_by_lua_block {
require('apicast.executor'):balancer('{{ upstream.load_balancer }}')
}

keepalive {{ upstream.keepalive | default: 64 }};
}

{% endfor %}
13 changes: 12 additions & 1 deletion gateway/src/apicast/cli/command/start.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ local sub = string.sub
local exec = require('resty.execvp')
local resty_env = require('resty.env')
local re = require('ngx.re')
local resty_url = require('resty.url')

local Template = require('apicast.cli.template')
local Environment = require('apicast.cli.environment')
Expand Down Expand Up @@ -106,9 +107,19 @@ local function openresty_binary(candidates)
find_openresty_command(candidates)
end

local function to_uri(uri)
local url = resty_url.parse(uri)

if url then
return uri
elseif uri then
return format('file:%s', uri)
end
end

local function build_env(options, config, context)
return {
APICAST_CONFIGURATION = options.configuration or context.configuration,
APICAST_CONFIGURATION = to_uri(options.configuration or context.configuration),
APICAST_CONFIGURATION_LOADER = options.configuration_loader or context.configuration_loader or 'lazy',
APICAST_CONFIGURATION_CACHE = options.cache or context.configuration_cache,
THREESCALE_DEPLOYMENT_ENV = context.configuration_channel or options.channel or config.name,
Expand Down
Loading