Skip to content
Draft
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
23 changes: 23 additions & 0 deletions configs/virtualhost.yaml.default
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# virtualhost.yaml
#
# This configuration file defines a virtual host that provides domain-scoped configs and
# remap rules, overriding global configs.
#
# Remap rule config flow:
# 1. Resolve to a single virtualhost
# A. Look through exact match virtualhost domains. If found, use virtualhost config.
# B. Look through wildcard virtualhost doamins. If found, use virtualhost config.
# C. If no virtualhost config found, skip to 3.
# 2. Within virtualhost config, use virtualhost remap rules.
# A. Follow existing remap.config rules. If found, use remap rule. (See remap.config for details)
# 3. If no virtualhost or remap rule found, use global remap.config
#
# Example:
# virtualhost:
# - id: example
# domains:
# - example.com
# - "*.com" # Only allow single left-most: "*.[domain]" format
#
# remap:
# - map http://example.com http://origin.example.com/
196 changes: 196 additions & 0 deletions doc/admin-guide/files/virtualhost.yaml.en.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@

.. Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.

.. include:: ../../common.defs

.. configfile:: virtualhost.yaml

virtualhost.yaml
************

The :file:`virtualhost.yaml` file defines configuration blocks that apply to a group of domains.
Each virtual host entry defines a set of domains and the remap rules associated with those domains.
Virtual host remap rules override global :file:`remap.config` rules but remain fully backward compatible
with existing configurations. If absent, ATS behaves exactly as before.

Currently, this file only supports :file:`remap.config` overrides. Future versions will expand virtual
host support to additional configuration types (e.g. :file:`sni.yaml`, :file:`ssl_multicert.config`,
:file:`parent.config`, etc)

By default this is named :file:`virtualhost.yaml`. The filename can be changed by setting
:ts:cv:`proxy.config.virtualhost.filename`.


Configuration
=============

:file:`virtualhost.yaml` is YAML format with top level namespace **virtualhost** and a list of virtual host
entries. Each virtual host entry must provide an **id** and at least one domain defined in **domains**.

An example configuration looks like:

.. code-block:: yaml

virtualhost:
- id: example
domains:
- example.com

remap:
- map http://example.com http://origin.example.com/


===================== ==========================================================
Field Name Description
===================== ==========================================================
``id`` Virtual host identifier to perform specific operations on
``domains`` List of domains to resolve a request to
``remap`` List of remap rules as defined in remap.config
===================== ==========================================================

``domains``
Domains can be defined as request domain name or subdomains using wildcard feature.
Wildcard support only allows single left most ``*``. This does not support regex.
When matching to a virtual host entry, domains with exact match have precedence
over wildcard. If a domain matches to multiple wildcard domains, the virtual host
config defined first has precedence.

For example:
Supported:
- ``foo.example.com``
- ``*.example.com``
- ``*.com``

NOT Supported:
- ``foo[0-9]+.example.com`` (regex)
- ``bar.*.example.net`` (``*`` in the middle)
- ``*.bar.*.com`` (multiple ``*``)
- ``*.*.baz.com`` (multiple ``*``)
- ``baz*.example.net`` (partial wildcard)
- ``*baz.example.net`` (partial wildcard)
- ``b*z.example.net`` (partial wildcard)
- ``*`` (global)

Evaluation Order
----------------

|TS| evaluates a request using deterministic precedence in the following order:

1. Resolve to a single virtualhost
a. Check for an exact domain match. If any virtual host lists the request hostname explicitly,
that virtual host is selected.
b. Check for a wildcard domain match. If any virtual host wildcard domains define a subdomain
of the request hostname in the form ``*.[domain]``, that virtual host is selected.
c. If no matching virtual host exists, the request proceeds using global configuration
(i.e :file:`remap.config`). Skip to step 3.
2. Within selected virtual host config, use virtual host remap rules.
a. Follow existing :file:`remap.config` rules and matching orders. If a matching remap rule
is found, that remap rule is selected.
3. If neither virtual host nor remap rules match, ATS falls back to global :file:`remap.config` resolution.

Only one virtual host entry may match a given request. If multiple entries could match, ATS uses the first matching
entry defined in :file:`virtualhost.yaml`.


Granular Reload
===============

|TS| now supports granular configuration reloads for individual virtual hosts defined in :file:`virtualhost.yaml`.
In addition to reloading the entire |TS| configuration with :option:`traffic_ctl config reload`, users can
selectively reload a single virtual host entry without affecting other virtual host entries.

By only updating the necessary changes, this reduces configuration deployment time and improves visibility on the changes made.

To reload for a specific virtual host, use:

::

$ traffic_ctl config reload --virtualhost <id>

Where **<id>** is the virtual host ID defined in :file:`virtualhost.yaml`. Only the **<id>** virtual host
configuration will be reloaded. This does not affect other virtual hosts or global configuration files.

Example:

::

$ traffic_ctl config reload --virtualhost foo
┌ Virtualhost: foo
└┬ Reload status: ok
├ Message: Virtualhost successfully reloaded


Examples
========

.. code-block:: yaml

# virtualhost.yaml
virtualhost:
- id: example
domains:
- example.com

remap:
- map http://example.com/ http://origin.example.com/

# remap.config
map / http://other.example.com/

This rules translates in the following translation.

================================================ ========================================================
Client Request Translated Request
================================================ ========================================================
``http://example.com/index.html`` ``http://origin.example.com/index.html``
``http://www.x.com/index.html`` ``http://other.example.com/index.html``
================================================ ========================================================

.. code-block:: yaml

# virtualhost.yaml
virtualhost:
- id: example
domains:
- "*.example.com"

remap:
- regex_map http://sub[0-9]+.example.com/ http://origin$1.example.com/

- id: foo
domains:
- foo.example.com

remap:
- map http:/foo.example.com/ http://foo.origin.com/

This rules translates in the following translation.

================================================ ========================================================
Client Request Translated Request
================================================ ========================================================
``http://sub0.example.com/index.html`` ``http://origin0.example.com/index.html``
``http://foo.example.com/index.html`` ``http://foo.origin.com/index.html``
``http://bar.example.com/index.html`` No remap rule found in virtual host entry `example`
================================================ ========================================================


See Also
========

:ref:`remap.config`
1 change: 1 addition & 0 deletions include/mgmt/rpc/handlers/config/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ namespace rpc::handlers::config
{
swoc::Rv<YAML::Node> set_config_records(std::string_view const &id, YAML::Node const &params);
swoc::Rv<YAML::Node> reload_config(std::string_view const &id, YAML::Node const &params);
swoc::Rv<YAML::Node> reload_virtualhost_config(std::string_view const &id, YAML::Node const &params);

} // namespace rpc::handlers::config
107 changes: 107 additions & 0 deletions include/proxy/VirtualHost.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/** @file

Virtual Host configuration

@section license License

Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#pragma once

#include <string>
#include <string_view>

#include "iocore/eventsystem/ConfigProcessor.h"
#include "proxy/http/remap/UrlRewrite.h"
#include "tscore/Ptr.h"

class VirtualHostConfig : public ConfigInfo
{
public:
VirtualHostConfig() = default;
VirtualHostConfig(const VirtualHostConfig &other)
: _entries(other._entries),
_exact_domains_to_id(other._exact_domains_to_id),
_wildcard_domains_to_id(other._wildcard_domains_to_id)
{
}
VirtualHostConfig &
operator=(const VirtualHostConfig &other)
{
if (this != &other) {
_entries = other._entries;
_exact_domains_to_id = other._exact_domains_to_id;
_wildcard_domains_to_id = other._wildcard_domains_to_id;
}
return *this;
}
~VirtualHostConfig() = default;

struct Entry : public RefCountObjInHeap {
std::string id;
std::vector<std::string> exact_domains;
std::vector<std::string> wildcard_domains;
Ptr<UrlRewrite> remap_table;

Entry *acquire() const;
void release() const;
std::string get_id() const;
};

bool load();
bool set_entry(std::string_view id, Ptr<Entry> &entry);
static bool load_entry(std::string_view id, Ptr<Entry> &entry);
Ptr<Entry> find_by_id(std::string_view id) const;
Ptr<Entry> find_by_domain(std::string_view domain) const;

private:
using entry_map = std::unordered_map<std::string, Ptr<Entry>>;
using name_map = std::unordered_map<std::string, std::string>;

entry_map _entries;
name_map _exact_domains_to_id;
name_map _wildcard_domains_to_id;
};

class VirtualHost
{
public:
using scoped_config = ConfigProcessor::scoped_config<VirtualHost, VirtualHostConfig>;

static void startup();
static int reconfigure();
static int reconfigure(std::string_view id);
static VirtualHostConfig *acquire();
static void release(VirtualHostConfig *config);

private:
static int config_callback(const char *, RecDataT, RecData, void *);
static int _configid;
};

struct VirtualHostConfigContinuation : public Continuation {
VirtualHostConfigContinuation() : Continuation(nullptr) { SET_HANDLER(&VirtualHostConfigContinuation::reconfigure); }

int
reconfigure(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
{
VirtualHost::reconfigure();
delete this;
return EVENT_DONE;
}
};
5 changes: 4 additions & 1 deletion include/proxy/http/HttpSM.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "api/InkAPIInternal.h"
#include "proxy/ProxyTransaction.h"
#include "proxy/hdrs/HdrUtils.h"
#include "proxy/VirtualHost.h"

// inknet
#include "proxy/http/PreWarmManager.h"
Expand Down Expand Up @@ -306,7 +307,8 @@ class HttpSM : public Continuation, public PluginUserArgs<TS_USER_ARGS_TXN>

// This unfortunately can't go into the t_state, because of circular dependencies. We could perhaps refactor
// this, with a lot of work, but this is easier for now.
UrlRewrite *m_remap = nullptr;
UrlRewrite *m_remap = nullptr;
VirtualHostConfig::Entry *m_virtualhost_entry = nullptr;

History<HISTORY_DEFAULT_SIZE> history;
NetVConnection *
Expand Down Expand Up @@ -364,6 +366,7 @@ class HttpSM : public Continuation, public PluginUserArgs<TS_USER_ARGS_TXN>

// Y! ebalsa: remap handlers
int state_remap_request(int event, void *data);
void set_virtualhost_entry(std::string_view domain);
void do_remap_request(bool);

// Cache Handlers
Expand Down
9 changes: 7 additions & 2 deletions include/proxy/http/remap/RemapConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@

#include "proxy/http/remap/AclFiltering.h"

namespace YAML
{
class Node;
}

class UrlRewrite;

#define BUILD_TABLE_MAX_ARGS 2048
Expand Down Expand Up @@ -79,15 +84,15 @@ struct BUILD_TABLE_INFO {
};

const char *remap_parse_directive(BUILD_TABLE_INFO *bti, char *errbuf, size_t errbufsize);
bool remap_parse_config_bti(const char *path, BUILD_TABLE_INFO *bti);
bool remap_parse_config_bti(const char *path, BUILD_TABLE_INFO *bti, YAML::Node const *remap_node = nullptr);

const char *remap_validate_filter_args(acl_filter_rule **rule_pp, const char *const *argv, int argc, char *errStrBuf,
size_t errStrBufSize, ACLBehaviorPolicy behavior_policy);

unsigned long remap_check_option(const char *const *argv, int argc, unsigned long findmode = 0, int *_ret_idx = nullptr,
const char **argptr = nullptr);

bool remap_parse_config(const char *path, UrlRewrite *rewrite);
bool remap_parse_config(const char *path, UrlRewrite *rewrite, YAML::Node const *remap_node);

using load_remap_file_func = void (*)(const char *, const char *);

Expand Down
Loading