Skip to content

Commit 1dcca25

Browse files
Merge pull request #867 from fmount/cors
Add multi-region CORS configuration guide for Horizon
2 parents 8efa0f9 + a6ab1da commit 1dcca25

2 files changed

Lines changed: 116 additions & 5 deletions

File tree

docs/horizon.md

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ As a consequence, if the total size of the HTTP request body exceeds the 1
88
GiB limit, httpd returns the `413 Request Entity Too Large` error code.
99
While one possibility is to configure `LimitRequestBody` in Horizon httpd, the
1010
recommended option is to enable `CORS`.
11-
In general Horizon has different available options.
11+
Horizon has three available upload modes.
1212

1313
1. `off`: disables the ability to upload images via Horizon.
1414
2. `legacy`: enables local file upload by piping the image file through the
1515
Horizon’s web server.
16-
2. `direct` sends the image file directly from the web browser to Glance.
16+
3. `direct` sends the image file directly from the web browser to Glance.
1717

1818
"direct" is the preferred mode, and it requires `CORS` support to be enabled on
1919
the Glance API service.
20+
2021
`direct` mode has several benefits:
2122

2223
- Eliminates the 1GiB upload limit
@@ -25,7 +26,7 @@ the Glance API service.
2526
files
2627
- Better performance for large image uploads
2728

28-
To enable `CORS` in glance, perform the following steps:
29+
To enable `CORS` in Glance, perform the following steps:
2930

3031
1. Get the Horizon `Route` associated with the deployment:
3132

@@ -60,7 +61,7 @@ spec:
6061
```
6162
6263
**Note:**
63-
It is not required to add the following parameters:
64+
You don't need to add the following parameters:
6465
6566
```
6667
max_age=3600
@@ -69,3 +70,111 @@ allow_methods=GET,POST,PUT,DELETE
6970

7071
because they represent the [default values](https://github.com/openstack/oslo.middleware/blob/master/oslo_middleware/cors.py#L61)
7172
set through oslo.
73+
74+
## Multi-Region Setup
75+
76+
In multi-region deployments where multiple GlanceAPI instances are deployed in
77+
each region, there's usually a single centralized Horizon instance.
78+
In particular:
79+
- Multiple GlanceAPI instances are deployed across different regions/edge sites
80+
- A single centralized Horizon dashboard serves all regions
81+
- Direct image upload mode is required for performance and scalability
82+
In such deployments, the `HORIZON_IMAGES_UPLOAD_MODE` variable **must be set to
83+
`direct`** mode. The `legacy` mode cannot be used because it routes all image
84+
upload traffic through the central Horizon instance, creating unnecessary
85+
network overhead and defeating the performance benefits of distributed edge
86+
sites.
87+
88+
This scenario makes CORS configuration more complex. The CORS section cannot be
89+
automatically configured in environments where the local Horizon instance is
90+
not deployed in the control plane, because we can't rely on the `glance-operator`
91+
discovery.
92+
93+
### CORS Configuration for Edge Sites
94+
95+
When using direct upload mode across multiple regions, you'll encounter
96+
Cross-Origin Resource Sharing (CORS) restrictions. The browser will block
97+
cross-origin requests from the Horizon domain to edge GlanceAPI endpoints
98+
unless explicitly configured.
99+
100+
According to the [OpenStack Horizon
101+
documentation](https://docs.openstack.org/horizon/latest/configuration/settings.html#images-upload-mode),
102+
Glance services at edge sites must inform the browser via HTTP headers that
103+
they accept requests from the Horizon origin domain.
104+
105+
### Configuration Steps
106+
107+
1. **Identify the Horizon endpoint** that will access the edge GlanceAPI
108+
services.
109+
In the `central` openstack control plane:
110+
111+
```bash
112+
# Get all the Horizon routes that will need access to edge Glance services
113+
$ oc get route horizon -o custom-columns=HOST:.spec.host --no-headers
114+
horizon-openstack.apps.ocp.openstack.lab
115+
```
116+
117+
2. **Configure CORS in the edge region GlanceAPI instances** by adding the
118+
following to the `customServiceConfig` section:
119+
120+
```yaml
121+
apiVersion: core.openstack.org/v1beta1
122+
kind: OpenStackControlPlane
123+
metadata:
124+
name: openstack-region-2
125+
spec:
126+
...
127+
glance:
128+
enabled: true
129+
template:
130+
customServiceConfig: |
131+
[cors]
132+
allowed_origin=https://horizon-openstack.apps.ocp.openstack.lab:443,https://horizon-backup.apps.ocp.openstack.lab:443
133+
max_age=3600
134+
allow_methods=GET,POST,PUT,DELETE
135+
allow_headers=X-Custom-Header,Content-Type,Authorization
136+
expose_headers=X-Custom-Header
137+
```
138+
139+
### Configuration Parameters Explained
140+
141+
- **allowed_origin**: Comma-separated list of all Horizon endpoints that need
142+
access to this GlanceAPI instance. Include the full URL with protocol and
143+
port.
144+
- **max_age**: Time in seconds that browsers can cache CORS preflight responses
145+
(3600 = 1 hour).
146+
- **allow_methods**: HTTP methods permitted for cross-origin requests. Include
147+
all methods used by Horizon for image operations.
148+
- **allow_headers**: Custom headers that Horizon may send with requests.
149+
- **expose_headers**: Headers that the browser is allowed to access in the
150+
response.
151+
152+
### Troubleshooting CORS Issues
153+
154+
If image uploads from Horizon to edge sites fail, check for the following:
155+
156+
1. **Browser Console Errors**: Look for CORS-related errors in the browser
157+
developer console:
158+
```
159+
Access to XMLHttpRequest at
160+
'https://glance-edge.apps.openstack-region-2.openstack.lab' from origin
161+
'https://horizon-openstack.apps.ocp.openstack.lab' has been blocked by CORS policy
162+
```
163+
164+
2. **Verify CORS Headers**: Use browser developer tools to check that the
165+
Glance API is returning proper CORS headers:
166+
```
167+
Access-Control-Allow-Origin: https://horizon-openstack.apps.ocp.openstack.lab
168+
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
169+
```
170+
171+
3. **Test with curl**: Verify CORS configuration by sending a preflight
172+
request:
173+
174+
```bash
175+
curl -H "Origin: https://horizon-openstack.apps.ocp.openstack.lab" \
176+
-H "Access-Control-Request-Method: POST" \
177+
-H "Access-Control-Request-Headers: Content-Type" \
178+
-X OPTIONS \
179+
https://glance-edge.apps.openstack-region-2.openstack.lab/v2/images
180+
```

zuul.d/jobs.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
attempts: 1
66
required-projects:
77
- github.com/openstack-k8s-operators/glance-operator
8-
irrelevant-files:
8+
irrelevant-files: &common-irrelevant-files
99
- .*/*.md
1010
- ^\..*$
1111
- ^LICENSE$
@@ -15,6 +15,7 @@
1515
- ^README.md$
1616
- tests?\/functional
1717
- ^renovate.json$
18+
- ^docs/
1819
vars:
1920
cifmw_install_yamls_sdk_version: v1.41.1
2021
cifmw_cls_pv_count: 20
@@ -24,6 +25,7 @@
2425
- job:
2526
name: glance-operator-tempest
2627
parent: podified-multinode-hci-deployment-crc-1comp-backends
28+
irrelevant-files: *common-irrelevant-files
2729
vars:
2830
cifmw_ceph_daemons_layout:
2931
rgw_enabled: false

0 commit comments

Comments
 (0)