Replace sphinxcontrib-*diag
As expected (and as done in lot of other OpenStack services) *blockdiag and *seqdiag extensions stop working for us and we need to replace this usage. Other services go directly to graphviz. Sadly sequence diagrams doesn't look good, but there is no other alternative so far. It would be nice if we would have mermaid allowed in global requirements, but that tends to be a long process while we need an urgent solution (since otherwise doc build is broken). Change-Id: Ie5fc80d7e5506c8c426a289687acc6c7c30f5ebd
This commit is contained in:
parent
15f34eff17
commit
51045cc0dd
@ -34,3 +34,6 @@ python3-devel [platform:rpm]
|
||||
|
||||
libmariadb-devel [platform:suse]
|
||||
openldap2-devel [platform:suse]
|
||||
|
||||
# Required for sphinx graphviz image generation
|
||||
graphviz [test doc]
|
||||
|
@ -4,9 +4,7 @@
|
||||
openstackdocstheme>=2.2.1 # Apache-2.0
|
||||
sphinx>=2.0.0,!=2.1.0 # BSD
|
||||
sphinxcontrib-apidoc>=0.2.0 # BSD
|
||||
sphinxcontrib-seqdiag>=0.8.4 # BSD
|
||||
sphinx-feature-classification>=0.3.2 # Apache-2.0
|
||||
sphinxcontrib-blockdiag>=1.5.5 # BSD
|
||||
reno>=3.1.0 # Apache-2.0
|
||||
os-api-ref>=1.4.0 # Apache-2.0
|
||||
python-ldap>=3.0.0 # PSF
|
||||
|
@ -117,20 +117,51 @@ process is key to being able to debug later on.
|
||||
Normal keystone
|
||||
---------------
|
||||
|
||||
.. seqdiag::
|
||||
.. graphviz::
|
||||
:name: normal-keystone
|
||||
:alt: Diagram of keystone's normal auth flow, in which a user agent
|
||||
authenticates and authorizes themself with keystone and obtains a
|
||||
scoped token to pass to an OpenStack service.
|
||||
|
||||
seqdiag {
|
||||
default_fontsize = 13;
|
||||
useragent [label = "User Agent"]; keystone [label = "Keystone"]; openstack [label = "OpenStack"];
|
||||
useragent -> keystone [label = "GET /v3/auth/tokens"];
|
||||
keystone -> keystone [label = "Authenticate"];
|
||||
keystone -> keystone [label = "Authorize"];
|
||||
useragent <- keystone [label = "Scoped token"];
|
||||
useragent -> openstack [label = "GET /v2.1/servers"];
|
||||
digraph {
|
||||
nodesep=1
|
||||
node [shape=point]
|
||||
|
||||
// first column
|
||||
useragent_top [label = "User Agent" shape="box"]
|
||||
useragent_bottom [label = "User Agent" shape="box"]
|
||||
// chain rows of the column
|
||||
useragent_top -> u0 [arrowhead="none" style="dashed"]
|
||||
u0 -> u1 -> u2 [arrowhead="none" style="bold"]
|
||||
u2 -> useragent_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// second column
|
||||
keystone_top [label = "Keystone" shape="box"]
|
||||
keystone_bottom [label = "Keystone" shape="box"]
|
||||
keystone_top -> k0 [arrowhead="none" style="dashed"]
|
||||
k0 -> k1 -> k2 -> k3 [arrowhead="none" style="bold"]
|
||||
k3 -> keystone_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
openstack_top [label = "OpenStack" shape="box"]
|
||||
openstack_bottom [label = "OpenStack" shape="box"]
|
||||
openstack_top -> o0 -> openstack_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// Order columns
|
||||
useragent_top -> keystone_top -> openstack_top [style="invis"]
|
||||
|
||||
// Event links
|
||||
u0 -> k0 [weight=0 label = "GET /v3/auth/tokens"]
|
||||
k1 -> k1 [weight=0 label = "Authenticate"]
|
||||
k2 -> k2 [weight=0 label = "Authorize"]
|
||||
u1 -> k3 [weight=0 label = "Scoped token" dir="back"]
|
||||
u2 -> o0 [weight=0 xlabel = "GET /v2.1/servers"]
|
||||
|
||||
// bind nodes to levels
|
||||
{rank=same; useragent_top keystone_top openstack_top }
|
||||
{rank=same; u0 k0 }
|
||||
{rank=same; u1 k3 }
|
||||
{rank=same; u2 o0 }
|
||||
{rank=same; useragent_bottom keystone_bottom openstack_bottom }
|
||||
}
|
||||
|
||||
In a normal keystone flow, the user requests a scoped token directly from
|
||||
@ -147,26 +178,61 @@ SAML2.0
|
||||
SAML2.0 WebSSO
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. seqdiag::
|
||||
.. graphviz::
|
||||
:name: saml2-websso
|
||||
:alt: Diagram of a standard WebSSO authentication flow.
|
||||
|
||||
seqdiag {
|
||||
edge_length = 325;
|
||||
default_fontsize = 13;
|
||||
useragent [label = "User Agent"]; sp [label = "Service Provider"]; idp [label = "Identity Provider"];
|
||||
useragent -> sp [label = "GET /secure"];
|
||||
useragent <- sp [label = "HTTP 302
|
||||
Location: https://idp/auth?
|
||||
SAMLRequest=req"];
|
||||
useragent -> idp [label = "GET /auth?SAMLRequest=req"];
|
||||
idp -> idp [label = "Authenticate"];
|
||||
useragent <- idp [label = "HTTP 200
|
||||
SAMLResponse in HTML form"];
|
||||
useragent -> sp [label = "POST /assertionconsumerservice"];
|
||||
sp -> sp [label = "Validate"];
|
||||
useragent <- sp [label = "HTTP 302; Location: /secure"];
|
||||
useragent -> sp [label = "GET /secure"];
|
||||
digraph {
|
||||
nodesep=1
|
||||
node [shape=point]
|
||||
|
||||
// first column
|
||||
useragent_top [label = "User Agent" shape="box"]
|
||||
useragent_bottom [label = "User Agent" shape="box"]
|
||||
// chain rows of the column
|
||||
useragent_top -> u0 [arrowhead="none" style="dashed"]
|
||||
u0 -> u1 -> u2 -> u3 -> u4 -> u5 -> u6 [arrowhead="none" style="bold"]
|
||||
u6 -> useragent_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// second column
|
||||
sp_top [label = "Service Provider" shape="box"]
|
||||
sp_bottom [label = "Service Provider" shape="box"]
|
||||
sp_top -> sp0 [arrowhead="none" style="dashed"]
|
||||
sp0 -> sp1 [arrowhead="none" style="bold"]
|
||||
sp1 -> sp2 [arrowhead="none" style="dashed"]
|
||||
sp2 -> sp3 -> sp4 [arrowhead="none" style="bold"]
|
||||
sp4 -> sp5 -> sp_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
idp_top [label = "Identity Provider" shape="box"]
|
||||
idp_bottom [label = "Identity Provider" shape="box"]
|
||||
idp_top -> idp0 [arrowhead="none" style="dashed"]
|
||||
idp0 -> idp1 -> idp2 [arrowhead="none" style="bold"]
|
||||
idp2 -> idp_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// Order columns
|
||||
useragent_top -> sp_top -> idp_top [style="invis"]
|
||||
|
||||
// Event links
|
||||
u0 -> sp0 [weight=0 xlabel = "GET /secure"]
|
||||
u1 -> sp1 [weight=0 xlabel = "HTTP 302\nLocation: https://idp/auth?SAMLRequest=req" dir=back]
|
||||
u2 -> idp0 [weight=0 xlabel = "GET /auth?SAMLRequest=req"]
|
||||
idp1 -> idp1 [weight=0 xlabel = "Authenticate"]
|
||||
u3 -> idp2 [weight=0 xlabel = "HTTP 200\nSAMLResponse in HTML form" dir=back]
|
||||
u4 -> sp2 [weigth=0 xlabel= "POST /assertionconsumerservice"]
|
||||
sp3 -> sp3 [weight=0 xlabel = "Validate"]
|
||||
u5 -> sp4 [ weight=0 xlabel = "HTTP 302; Location: /secure" dir=back]
|
||||
u6 -> sp5 [weight=0 xlabel = "GET /secure"]
|
||||
|
||||
// bind nodes to levels
|
||||
{rank=same; useragent_top sp_top idp_top }
|
||||
{rank=same; u0 sp0 }
|
||||
{rank=same; u1 sp1 }
|
||||
{rank=same; u2 idp0 }
|
||||
{rank=same; u3 idp2 }
|
||||
{rank=same; u4 sp2 }
|
||||
{rank=same; u5 sp4 }
|
||||
{rank=same; u6 sp5 }
|
||||
{rank=same; useragent_bottom sp_bottom idp_bottom }
|
||||
}
|
||||
|
||||
This diagram shows a standard `WebSSO`_ authentication flow, not one involving
|
||||
@ -194,24 +260,59 @@ redirect back to the original resource the user had requested.
|
||||
SAML2.0 ECP
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. seqdiag::
|
||||
.. graphviz::
|
||||
:name: saml2-ecp
|
||||
:alt: Diagram of a standard ECP authentication flow.
|
||||
|
||||
seqdiag {
|
||||
default_fontsize = 13;
|
||||
useragent [label = "User Agent"]; sp [label = "Service Provider"]; idp [label = "Identity Provider"];
|
||||
useragent -> sp [label = "GET /secure"];
|
||||
useragent <- sp [label = "HTTP 200
|
||||
SAML Request"];
|
||||
useragent -> idp [label = "POST /auth
|
||||
SAML Request"];
|
||||
idp -> idp [label = "Authenticate"];
|
||||
useragent <- idp [label = "HTTP 200
|
||||
SAMLResponse in SOAP"];
|
||||
useragent -> sp [label = "POST /responseconsumer"];
|
||||
sp -> sp [label = "Validate"];
|
||||
useragent <- sp [label = "HTTP 200 /secure"];
|
||||
digraph {
|
||||
nodesep=1
|
||||
node [shape=point]
|
||||
|
||||
// first column
|
||||
useragent_top [label = "User Agent" shape="box"]
|
||||
useragent_bottom [label = "User Agent" shape="box"]
|
||||
// chain rows of the column
|
||||
useragent_top -> u0 [arrowhead="none" style="dashed"]
|
||||
u0 -> u1 -> u2 -> u3 -> u4 -> u5 [arrowhead="none" style="bold"]
|
||||
u5 -> useragent_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// second column
|
||||
sp_top [label = "Service Provider" shape="box"]
|
||||
sp_bottom [label = "Service Provider" shape="box"]
|
||||
sp_top -> sp0 [arrowhead="none" style="dashed"]
|
||||
sp0 -> sp1 [arrowhead="none" style="bold"]
|
||||
sp1 -> sp2 [arrowhead="none" style="dashed"]
|
||||
sp2 -> sp3 -> sp4 [arrowhead="none" style="bold"]
|
||||
sp4 -> sp_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
idp_top [label = "Identity Provider" shape="box"]
|
||||
idp_bottom [label = "Identity Provider" shape="box"]
|
||||
idp_top -> idp0 [arrowhead="none" style="dashed"]
|
||||
idp0 -> idp1 -> idp2 [arrowhead="none" style="bold"]
|
||||
idp2 -> idp_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// Order columns
|
||||
useragent_top -> sp_top -> idp_top [style="invis"]
|
||||
|
||||
// Event links
|
||||
u0 -> sp0 [weight=0 xlabel = "GET /secure"]
|
||||
u1 -> sp1 [weight=0 xlabel = "HTTP 200\nSAML Request" dir=back]
|
||||
u2 -> idp0 [weight=0 xlabel = "POST /auth\nSAML Request"]
|
||||
idp1 -> idp1 [weight=0 xlabel = "Authenticate"]
|
||||
u3 -> idp2 [weight=0 xlabel = "HTTP 200\nSAMLResponse in SOAP" dir=back]
|
||||
u4 -> sp2 [weigth=0 xlabel= "POST /assertionconsumerservice"]
|
||||
sp3 -> sp3 [weight=0 xlabel = "Validate"]
|
||||
u5 -> sp4 [ weight=0 xlabel = "HTTP 200; Location: /secure" dir=back]
|
||||
|
||||
// bind nodes to levels
|
||||
{rank=same; useragent_top sp_top idp_top }
|
||||
{rank=same; u0 sp0 }
|
||||
{rank=same; u1 sp1 }
|
||||
{rank=same; u2 idp0 }
|
||||
{rank=same; u3 idp2 }
|
||||
{rank=same; u4 sp2 }
|
||||
{rank=same; u5 sp4 }
|
||||
{rank=same; useragent_bottom sp_bottom idp_bottom }
|
||||
}
|
||||
|
||||
`ECP`_ is another SAML profile. Generally the flow is similar to the WebSSO
|
||||
@ -231,36 +332,89 @@ WebSSO with keystone and horizon
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
.. seqdiag::
|
||||
.. graphviz::
|
||||
:name: saml2-keystone-horizon
|
||||
:alt: Diagram of the SAML2.0 WebSSO auth flow specific to horizon, keystone, and the
|
||||
HTTPD module acting as service provider.
|
||||
|
||||
seqdiag {
|
||||
default_fontsize = 13;
|
||||
useragent [label = "User Agent"]; horizon [label = "Horizon"]; httpd [label = "HTTPD", color = "lightgrey"]; keystone [label = "Keystone", color = "lightgrey"]; idp [label = "Identity Provider"];
|
||||
useragent -> horizon [label = "POST /auth/login"];
|
||||
useragent <- horizon [label = "HTTP 302
|
||||
Location:
|
||||
/v3/auth/OS-FEDERATION
|
||||
/websso/saml2"];
|
||||
useragent -> httpd [label = "GET /v3/auth/OS-FEDERATION/websso/saml2"];
|
||||
useragent <- httpd [label = "HTTP 302
|
||||
Location: https://idp/auth?SAMLRequest=req"];
|
||||
useragent -> idp [label = "GET /auth"];
|
||||
idp -> idp [label = "Authenticate"];
|
||||
useragent <- idp [label = "HTTP 200
|
||||
SAMLResponse in HTML form"];
|
||||
useragent -> httpd [label = "POST /assertionconsumerservice"];
|
||||
httpd -> httpd [label = "Validate"];
|
||||
useragent <- httpd [label = "HTTP 302
|
||||
Location: /v3/auth/OS-FEDERATION/websso/saml2"];
|
||||
useragent -> keystone [label = "GET /v3/auth/OS-FEDERATION/websso/saml2"];
|
||||
keystone -> keystone [label = "Issue token"];
|
||||
useragent <- keystone [label = "HTTP 200
|
||||
HTML form containing unscoped token"];
|
||||
useragent -> horizon [label = "POST /auth/websso"];
|
||||
useragent <- horizon [label = "successful login"];
|
||||
digraph {
|
||||
nodesep=1
|
||||
node [shape=point]
|
||||
|
||||
// first column
|
||||
useragent_top [label = "User Agent" shape="box"]
|
||||
useragent_bottom [label = "User Agent" shape="box"]
|
||||
// chain rows of the column
|
||||
useragent_top -> u0 [arrowhead="none" style="dashed"]
|
||||
u0 -> u1 -> u2 -> u3 -> u4 -> u5 -> u6 -> u7 -> u8 -> u9 -> u10 -> u11 [arrowhead="none" style="bold"]
|
||||
u11 -> useragent_bottom [arrowhead="none" style="bold"]
|
||||
|
||||
// second column
|
||||
h_top [label = "Horizon" shape="box"]
|
||||
h_bottom [label = "Horizon" shape="box"]
|
||||
h_top -> h0 [arrowhead="none" style="dashed"]
|
||||
h0 -> h1 [arrowhead="none" style="bold"]
|
||||
h1 -> h2 [arrowhead="none" style="dashed"]
|
||||
h2 -> h3 [arrowhead="none" style="bold"]
|
||||
h3 -> h_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// second column
|
||||
http_top [label = "Httpd" shape="box"]
|
||||
http_bottom [label = "Httpd" shape="box"]
|
||||
http_top -> http0 [arrowhead="none" style="dashed"]
|
||||
http0 -> http1 [arrowhead="none" style="bold"]
|
||||
http1 -> http2 [arrowhead="none" style="dashed"]
|
||||
http2 -> http3 -> http4 [arrowhead="none" style="bold"]
|
||||
http4 -> http_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// second column
|
||||
k_top [label = "Keystone" shape="box"]
|
||||
k_bottom [label = "Keystone" shape="box"]
|
||||
k_top -> k0 [arrowhead="none" style="dashed"]
|
||||
k0 -> k1 -> k2 [arrowhead="none" style="bold"]
|
||||
k2 -> k_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
idp_top [label = "Identity Provider" shape="box"]
|
||||
idp_bottom [label = "Identity Provider" shape="box"]
|
||||
idp_top -> idp0 [arrowhead="none" style="dashed"]
|
||||
idp0 -> idp1 -> idp2 [arrowhead="none" style="bold"]
|
||||
idp2 -> idp_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// Order columns
|
||||
useragent_top -> h_top -> http_top -> k_top -> idp_top [style="invis"]
|
||||
|
||||
// Event links
|
||||
u0 -> h0 [weight=0 xlabel = "POST /v3/auth/tokens"]
|
||||
u1 -> h1 [weight=0 xlabel = "HTTP 302\nLocation: /v3/auth/OS-FEDERATION/webssol/saml2" dir=back]
|
||||
u2 -> http0 [weight=0 xlabel = "GET /v3/auth/OS-FEDERATION/websso/saml2"]
|
||||
u3 -> http1 [weight=0 xlabel = "HTTP 302\nLocation: https://idp/auth?SAMLRequest=req" dir=back]
|
||||
u4 -> idp0 [weight=0 xlabel = "GET /auth"]
|
||||
idp1 -> idp1 [weight=0 xlabel = "Authenticate"]
|
||||
u5 -> idp2 [weight=0 xlabel = "HTTP 200\nSAMLResonse in HTML form" dir=back]
|
||||
u6 -> http2 [weight=0 xlabel = "POST /assertionconsumerservice"]
|
||||
http3 -> http3 [weight=0 xlabel = "Validate"]
|
||||
u7 -> http4 [weight=0 xlabel = "HTTP 302\nLocation: /v3/auth/OS-FEDERATION/websso/saml2" dir=back]
|
||||
u8 -> k0 [weight=0 xlabel="GET /v3/auth/OS-FEDERATION/websso/saml2"]
|
||||
k1 -> k1 [weight=0 xlabel="Issue token"]
|
||||
u9 -> k2 [weight=0 xlabel="HTTP 200\nHTML form containing unscoped token" dir=back]
|
||||
u10 -> h2 [weight=0 xlabel="POST /auth/websso"]
|
||||
u11 -> h3 [weight=0 xlabel="successful login" dir=back]
|
||||
|
||||
// bind nodes to levels
|
||||
{rank=same;useragent_top;h_top;http_top;k_top;idp_top}
|
||||
{rank=same;u0;h0 }
|
||||
{rank=same;u1;h1 }
|
||||
{rank=same;u2;http0 }
|
||||
{rank=same;u3;http1 }
|
||||
{rank=same;u4;idp0 }
|
||||
{rank=same;u5;idp2 }
|
||||
{rank=same;u6;http2 }
|
||||
{rank=same;u7;http4 }
|
||||
{rank=same;u8;k0 }
|
||||
{rank=same;u9;k2 }
|
||||
{rank=same;u10;h2}
|
||||
{rank=same;u11;h3}
|
||||
{rank=same;useragent_bottom;h_bottom;http_bottom;k_bottom;idp_bottom}
|
||||
}
|
||||
|
||||
Keystone is not a web front-end, which means horizon needs to handle some parts
|
||||
@ -292,29 +446,68 @@ secure resource it requests from keystone.
|
||||
Keystone to Keystone
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. seqdiag::
|
||||
.. graphviz::
|
||||
:name: keystone-to-keystone
|
||||
:alt: Diagram of the IdP-initiated auth flow in a keystone-to-keystone model.
|
||||
|
||||
seqdiag {
|
||||
edge_length = 240;
|
||||
default_fontsize = 13;
|
||||
useragent [label = "User Agent"]; sp [label = "Service Provider"]; idp [label = "Identity Provider"];
|
||||
useragent -> idp [label = "POST /v3/auth/tokens"];
|
||||
idp -> idp [label = "Authenticate"];
|
||||
useragent <- idp [label = "HTTP 201
|
||||
X-Subject-Token: token"];
|
||||
useragent -> idp [label = "POST /v3/auth/OS-FEDERATION/saml2/ecp"];
|
||||
useragent <- idp [label = "HTTP 201
|
||||
SAMLResponse in SOAP envelope"];
|
||||
useragent -> sp [label = "POST /PAOS-url"];
|
||||
sp -> sp [label = "Validate"];
|
||||
useragent <- sp [label = "HTTP 302"];
|
||||
useragent -> sp [label = "GET /v3/OS-FED/.../auth"];
|
||||
useragent <- sp [label = "HTTP 201
|
||||
X-Subject-Token: unscoped token"];
|
||||
useragent -> sp [label = "POST /v3/auth/tokens
|
||||
(request scoped token)"];
|
||||
digraph {
|
||||
nodesep=1
|
||||
node [shape=point]
|
||||
|
||||
// first column
|
||||
useragent_top [label = "User Agent" shape="box"]
|
||||
useragent_bottom [label = "User Agent" shape="box"]
|
||||
// chain rows of the column
|
||||
useragent_top -> u0 [arrowhead="none" style="dashed"]
|
||||
u0 -> u1 -> u2 -> u3 -> u4 -> u5 -> u6 -> u7 -> u8 [arrowhead="none" style="bold"]
|
||||
u8 -> useragent_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// second column
|
||||
sp_top [label = "Service Provider" shape="box"]
|
||||
sp_bottom [label = "Service Provider" shape="box"]
|
||||
sp_top -> sp0 [arrowhead="none" style="dashed"]
|
||||
sp0 -> sp1 -> sp2 [arrowhead="none" style="bold"]
|
||||
sp2 -> sp3 [arrowhead="none" style="dashed"]
|
||||
sp3 -> sp4 [arrowhead="none" style="bold"]
|
||||
sp4 -> sp5 [arrowhead="none" style="dashed"]
|
||||
sp5 -> sp_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
idp_top [label = "Identity Provider" shape="box"]
|
||||
idp_bottom [label = "Identity Provider" shape="box"]
|
||||
idp_top -> idp0 [arrowhead="none" style="dashed"]
|
||||
idp0 -> idp1 -> idp2 [arrowhead="none" style="bold"]
|
||||
idp2 -> idp3 [arrowhead="none" style="dashed"]
|
||||
idp3 -> idp4 [arrowhead="none" style="bold"]
|
||||
idp4 -> idp_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// Order columns
|
||||
useragent_top -> sp_top -> idp_top [style="invis"]
|
||||
|
||||
// Event links
|
||||
u0 -> idp0 [weight=0 xlabel = "POST /v3/auth/tokens"]
|
||||
idp1 -> idp1 [weight=0 xlabel = "Authenticate"]
|
||||
u1 -> idp2 [weight=0 xlabel = "HTTP 201\nX-Subject-Token: token" dir=back]
|
||||
u2 -> idp3 [weight=0 xlabel = "POST /v3/auth/OS-FEDERATION/saml2/ecp"]
|
||||
u3 -> idp4 [weight=0 xlabel = "HTTP 201\nSAMLResponse in SOAP envelope" dir=back]
|
||||
u4 -> sp0 [weight=0 xlabel = "POST /PAOS-url"]
|
||||
sp1 -> sp1 [weight=0 xlabel = "Validate"]
|
||||
u5 -> sp2 [weight=0 xlabel = "HTTP 302" dir=back]
|
||||
u6 -> sp3 [weight=0 xlabel = "GET /v3/OS-FED/.../auth"]
|
||||
u7 -> sp4 [weight=0 xlabel = "HTTP 201\nX-Subject-Token: unscoped token" dir=back]
|
||||
u8 -> sp5 [weight=0 xlabel = "POST /v3/auth/tokens\n(request scoped token)"]
|
||||
|
||||
// bind nodes to levels
|
||||
{rank=same;useragent_top;sp_top;idp_top}
|
||||
{rank=same;u0;idp0 }
|
||||
{rank=same;u1;idp2 }
|
||||
{rank=same;u2;idp3 }
|
||||
{rank=same;u3;idp4 }
|
||||
{rank=same;u4;sp0 }
|
||||
{rank=same;u5;sp2 }
|
||||
{rank=same;u6;sp3 }
|
||||
{rank=same;u7;sp4 }
|
||||
{rank=same;u8;sp5 }
|
||||
{rank=same;useragent_bottom;sp_bottom;idp_bottom}
|
||||
}
|
||||
|
||||
When keystone is used as an Identity Provider in a Keystone to Keystone
|
||||
@ -339,31 +532,67 @@ OpenID Connect
|
||||
OpenID Connect Authentication Flow
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. seqdiag::
|
||||
.. graphviz::
|
||||
:name: openidc
|
||||
:alt: Diagram of a standard OpenID Connect authentication flow
|
||||
:align: left
|
||||
|
||||
seqdiag {
|
||||
edge_length = 330;
|
||||
default_fontsize = 13;
|
||||
useragent [label = "User Agent"]; sp [label = "Service Provider"]; idp [label = "Identity Provider"];
|
||||
useragent -> sp [label = "GET /secure"];
|
||||
useragent <- sp [label = "HTTP 302
|
||||
Location: https://idp/auth?
|
||||
client_id=XXX&redirect_uri=https://sp/secure"];
|
||||
useragent -> idp [label = "GET /auth?client_id=XXX&redirect_uri=https://sp/secure"];
|
||||
idp -> idp [label = "Authenticate"];
|
||||
useragent <- idp [label = "HTTP 302
|
||||
Location: https://sp/auth?code=XXX"];
|
||||
useragent -> sp [label = "GET /auth?code=XXX"];
|
||||
sp -> idp [label = "POST https://idp/token
|
||||
code=XXX&redirect_uri=https://sp/secure"];
|
||||
sp <- idp [label = "HTTP 200
|
||||
{\"access_code\": \"XXX\",
|
||||
\"id_token\": \"XXX\"}"];
|
||||
useragent <- sp [label = "HTTP 302; Location: /secure"];
|
||||
useragent -> sp [label = "GET /secure"];
|
||||
digraph auth {
|
||||
nodesep=1
|
||||
node [shape=point]
|
||||
|
||||
// first column
|
||||
useragent_top [label = "User Agent" shape="box"]
|
||||
useragent_bottom [label = "User Agent" shape="box"]
|
||||
// chain rows of the column
|
||||
useragent_top -> u0 [arrowhead="none" style="dashed"]
|
||||
u0 -> u1 -> u2 -> u3 -> u4 -> u5 -> u6 [arrowhead="none" style="bold"]
|
||||
u6 -> useragent_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// second column
|
||||
sp_top [label = "Service Provider" shape="box"]
|
||||
sp_bottom [label = "Service Provider" shape="box"]
|
||||
sp_top -> sp0 [arrowhead="none" style="dashed"]
|
||||
sp0 -> sp1 [arrowhead="none" style="bold"]
|
||||
sp1 -> sp2 [arrowhead="none" style="dashed"]
|
||||
sp2 -> sp3 -> sp4 -> sp5 [arrowhead="none" style="bold"]
|
||||
sp5 -> sp6 -> sp_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
idp_top [label = "Identity Provider" shape="box"]
|
||||
idp_bottom [label = "Identity Provider" shape="box"]
|
||||
idp_top -> idp0 [arrowhead="none" style="dashed"]
|
||||
idp0 -> idp1 -> idp2 [arrowhead="none" style="bold"]
|
||||
idp2 -> idp3 [arrowhead="none" style="dashed"]
|
||||
idp3 -> idp4 [arrowhead="none" style="bold"]
|
||||
idp4 -> idp_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// Order columns
|
||||
useragent_top -> sp_top -> idp_top [style="invis"]
|
||||
|
||||
// Event links
|
||||
u0 -> sp0 [weight=0 xlabel = "GET /secure"]
|
||||
u1 -> sp1 [weight=0 xlabel = "HTTP 302\nLocation: https://idp/auth?client_id=XXX&redirect_uri=https://sp/secure" dir=back]
|
||||
u2 -> idp0 [weight=0 xlabel = "GET /auth?client_id=XXX&redirect_uri=https://sp/secure"]
|
||||
idp1 -> idp1 [weight=0 xlabel = "Authenticate"]
|
||||
u3 -> idp2 [weight=0 xlabel = "HTTP 302\nLocation: https://sp/auth?code=XXX" dir=back]
|
||||
u4 -> sp2 [weight=0 xlabel = "GET /auth?code=XXX"]
|
||||
sp3 -> idp3 [weight=0 xlabel = "POST https://idp/token?code=XXX&redirect_uri=https://sp/secure"]
|
||||
sp4 -> idp4 [weight=0 xlabel = "HTTP 200\n{\"access_code\": \"XXX\", \"id_token\": \"XXX\"}" dir=back]
|
||||
u5 -> sp5 [weight=0 xlabel = "HTTP 302; Location: /secure" dir=back]
|
||||
u6 -> sp6 [weight=0 xlabel = "GET /secure"]
|
||||
|
||||
// bind nodes to levels
|
||||
{rank=same;useragent_top;sp_top;idp_top}
|
||||
{rank=same;u0;sp0}
|
||||
{rank=same;u1;sp1}
|
||||
{rank=same;u2;idp0}
|
||||
{rank=same;u3;idp2}
|
||||
{rank=same;u4;sp2}
|
||||
{rank=same;sp3;idp3}
|
||||
{rank=same;sp4;idp4}
|
||||
{rank=same;u5;sp5}
|
||||
{rank=same;u6;sp6}
|
||||
{rank=same;useragent_bottom;sp_bottom;idp_bottom }
|
||||
}
|
||||
|
||||
OpenID Connect is different from any SAML2.0 flow because the negotiation is not
|
||||
@ -382,46 +611,92 @@ and exchange it for an ID token.
|
||||
OpenID Connect with keystone and horizon
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. seqdiag::
|
||||
.. graphviz::
|
||||
:name: oidc-keystone-horizon
|
||||
:alt: Diagram of the OpenID Connect WebSSO auth flow specific to horizon,
|
||||
keystone, and the HTTPD module acting as service provider.
|
||||
|
||||
seqdiag {
|
||||
edge_length = 200
|
||||
default_fontsize = 13;
|
||||
useragent [label = "User Agent"]; horizon [label = "Horizon"]; httpd [label = "HTTPD", color = "lightgrey"]; keystone [label = "Keystone", color = "lightgrey"]; idp [label = "Identity Provider"];
|
||||
useragent -> horizon [label = "POST /auth/login"];
|
||||
useragent <- horizon [label = "HTTP 302
|
||||
Location:
|
||||
/v3/auth/OS-FEDERATION
|
||||
/websso/openid"];
|
||||
useragent -> httpd [label = "GET /v3/auth/OS-FEDERATION/websso/openid"];
|
||||
useragent <- httpd [label = "HTTP 302
|
||||
Location:
|
||||
https://idp/auth?
|
||||
client_id=XXX&
|
||||
redirect_uri=https://sp/v3/auth/OS-FEDERATION/websso"];
|
||||
useragent -> idp [label = "GET /auth?client_id=XXX&
|
||||
redirect_uri=https://sp/v3/auth/OS-FEDERATION/websso"];
|
||||
idp -> idp [label = "Authenticate"];
|
||||
useragent <- idp [label = "HTTP 302
|
||||
Location: https://sp/v3/auth/OS-FEDERATION/websso"];
|
||||
useragent -> httpd [label = "GET /v3/auth/OS-FEDERATION/websso"];
|
||||
httpd -> idp [label = "POST https://idp/token
|
||||
code=XXX&
|
||||
redirect_uri=https://sp/v3/auth/OS-FEDERATION/websso"];
|
||||
httpd <- idp [label = "HTTP 200
|
||||
{\"access_code\": \"XXX\",
|
||||
\"id_token\": \"XXX\"}"];
|
||||
useragent <- httpd [label = "HTTP 302
|
||||
Location: /v3/auth/OS-FEDERATION/websso/mapped"];
|
||||
useragent -> keystone [label = "GET /v3/auth/OS-FEDERATION/websso/mapped"];
|
||||
keystone -> keystone [label = "Issue token"];
|
||||
useragent <- keystone [label = "HTTP 200
|
||||
HTML form containing unscoped token"];
|
||||
useragent -> horizon [label = "POST /auth/websso"];
|
||||
useragent <- horizon [label = "successful login"];
|
||||
digraph {
|
||||
nodesep=1
|
||||
node [shape=point]
|
||||
|
||||
// first column
|
||||
useragent_top [label = "User Agent" shape="box"]
|
||||
useragent_bottom [label = "User Agent" shape="box"]
|
||||
// chain rows of the column
|
||||
useragent_top -> u0 [arrowhead="none" style="dashed"]
|
||||
u0 -> u1 -> u2 -> u3 -> u4 -> u5 -> u6 -> u7 -> u8 -> u9 -> u10 -> u11 [arrowhead="none" style="bold"]
|
||||
u11 -> useragent_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// second column
|
||||
h_top [label = "Horizon" shape="box"]
|
||||
h_bottom [label = "Horizon" shape="box"]
|
||||
h_top -> h0 [arrowhead="none" style="dashed"]
|
||||
h0 -> h1 [arrowhead="none" style="bold"]
|
||||
h1 -> h2 [arrowhead="none" style="dashed"]
|
||||
h2 -> h3 [arrowhead="none" style="bold"]
|
||||
h3 -> h_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
http_top [label = "Httpd" shape="box"]
|
||||
http_bottom [label = "Httpd" shape="box"]
|
||||
http_top -> http0 [arrowhead="none" style="dashed"]
|
||||
http0 -> http1 [arrowhead="none" style="bold"]
|
||||
http1 -> http2 [arrowhead="none" style="dashed"]
|
||||
http2 -> http3 -> http4 -> http5 [arrowhead="none" style="bold"]
|
||||
http5 -> http_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
k_top [label = "Keystone" shape="box"]
|
||||
k_bottom [label = "Keystone" shape="box"]
|
||||
k_top -> k0 [arrowhead="none" style="dashed"]
|
||||
k0 -> k1 -> k2 [arrowhead="none" style="bold"]
|
||||
k2 -> k_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
idp_top [label = "Identity Provider" shape="box"]
|
||||
idp_bottom [label = "Identity Provider" shape="box"]
|
||||
idp_top -> idp0 [arrowhead="none" style="dashed"]
|
||||
idp0 -> idp1 -> idp2 [arrowhead="none" style="bold"]
|
||||
idp2 -> idp3 [arrowhead="none" style="dashed"]
|
||||
idp3 -> idp4 [arrowhead="none" style="bold"]
|
||||
idp4 -> idp_bottom [arrowhead="none" style="dashed"]
|
||||
|
||||
// Order columns
|
||||
useragent_top -> h_top -> http_top -> k_top -> idp_top [style="invis"]
|
||||
|
||||
// Event links
|
||||
u0 -> h0 [weight=0 xlabel = "POST /v3/auth/tokens"]
|
||||
u1 -> h1 [weight=0 xlabel = "HTTP 302\nLocation: /v3/auth/OS-FEDERATION/webssol/openid" dir=back]
|
||||
u2 -> http0 [weight=0 xlabel = "GET /v3/auth/OS-FEDERATION/websso/openid"]
|
||||
u3 -> http1 [weight=0 xlabel = "HTTP 302\nLocation: https://idp/auth?client_id=XXX&redirect_uri=https://sp/v3/auth/OS-FEDERATION/websso" dir=back]
|
||||
u4 -> idp0 [weight=0 xlabel = "GET /auth?client_id=XXX&redirect_uri=https://sp/v3/auth/OS-FEDERATION/websso"]
|
||||
idp1 -> idp1 [weight=0 xlabel = "Authenticate"]
|
||||
u5 -> idp2 [weight=0 xlabel = "HTTP 203\nLocation: https://sp/v3/auth/OS-FEDERATION/websso" dir=back]
|
||||
u6 -> http2 [weight=0 xlabel = "GET /v3/auth/OS-FEDERATION/websso"]
|
||||
http3 -> idp3 [weight=0 xlabel = "POST https://idp/tokencode=XXX&redirect_uri=https://sp/v3/auth/OS-FEDERATION/websso"]
|
||||
http4 -> idp4 [weight=0 xlabel = "HTTP 200\n{\"access_code\": \"XXX\"\n\"id_token\": \"XXX\"}" dir=back]
|
||||
u7 -> http5 [weight=0 xlabel = "HTTP 302\nLocation: /v3/auth/OS-FEDERATION/websso/mapped" dir=back]
|
||||
u8 -> k0 [weight=0 xlabel="GET /v3/auth/OS-FEDERATION/websso/mapped"]
|
||||
k1 -> k1 [weight=0 xlabel="Issue token"]
|
||||
u9 -> k2 [weight=0 xlabel="HTTP 200\nHTML form containing unscoped token" dir=back]
|
||||
u10 -> h2 [weight=0 xlabel="POST /auth/websso"]
|
||||
u11 -> h3 [weight=0 xlabel="successful login" dir=back]
|
||||
|
||||
// bind nodes to levels
|
||||
{rank=same;useragent_top;h_top;http_top;k_top;idp_top}
|
||||
{rank=same;u0;h0 }
|
||||
{rank=same;u1;h1 }
|
||||
{rank=same;u2;http0 }
|
||||
{rank=same;u3;http1 }
|
||||
{rank=same;u4;idp0 }
|
||||
{rank=same;u5;idp2 }
|
||||
{rank=same;u6;http2 }
|
||||
{rank=same;http3;idp3 }
|
||||
{rank=same;http4;idp4 }
|
||||
{rank=same;u7;http5 }
|
||||
{rank=same;u8;k0 }
|
||||
{rank=same;u9;k2 }
|
||||
{rank=same;u10;h2}
|
||||
{rank=same;u11;h3}
|
||||
{rank=same;useragent_bottom;h_bottom;http_bottom;k_bottom;idp_bottom}
|
||||
}
|
||||
|
||||
From horizon and keystone's point of view, the authentication flow is the same
|
||||
|
@ -174,10 +174,11 @@ child of project `Alpha`. All projects assume a default limit of 10 cores via a
|
||||
registered limit. The labels in the diagrams below use shorthand notation for
|
||||
`limit` and `usage` as `l` and `u`, respectively:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha [label="Alpha (u=0)"];
|
||||
Beta [label=" Beta (u=0)"];
|
||||
@ -188,10 +189,11 @@ Each project may use up to 10 cores because of the registered limit and none of
|
||||
the projects have an override. Using flat enforcement, you're allowed to
|
||||
``UPDATE LIMIT on Alpha to 20``:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha [label="Alpha (l=20, u=0)", textcolor = "#00af00"];
|
||||
Beta [label=" Beta (u=0)"];
|
||||
@ -202,10 +204,11 @@ the projects have an override. Using flat enforcement, you're allowed to
|
||||
You're also allowed to ``UPDATE LIMIT on Charlie to 30``, even though `Charlie`
|
||||
is a sub-project of both `Beta` and `Alpha`.
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha [label="Alpha (l=20, u=0)"];
|
||||
Beta [label=" Beta (u=0)"];
|
||||
@ -220,10 +223,11 @@ Conversely, you can simulate hierarchical enforcement by adjusting limits
|
||||
through the project tree manually. For example, let's still assume 10 is the
|
||||
default limit imposed by an existing registered limit:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha [label="Alpha (u=0)"];
|
||||
Beta [label=" Beta (u=0)"];
|
||||
@ -232,10 +236,11 @@ default limit imposed by an existing registered limit:
|
||||
|
||||
You may set a project-specific override to ``UPDATE LIMIT on Alpha to 30``:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha [label="Alpha (l=30, u=0)", textcolor = "#00af00"];
|
||||
Beta [label=" Beta (u=0)"];
|
||||
@ -244,10 +249,11 @@ You may set a project-specific override to ``UPDATE LIMIT on Alpha to 30``:
|
||||
|
||||
Next you can ``UPDATE LIMIT on Beta to 20``:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha [label="Alpha (l=30, u=0)"];
|
||||
Beta [label=" Beta (l=20, u=0)", textcolor = "#00af00"];
|
||||
@ -258,10 +264,11 @@ Theoretically, the entire project tree consisting of `Alpha`, `Beta`, and
|
||||
`Charlie` is limited to 60 cores. If you'd like to ensure only 30 cores are
|
||||
used within the entire hierarchy, you can ``UPDATE LIMIT on Alpha to 0``:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha [label="Alpha (l=0, u=0)", textcolor = "#00af00"];
|
||||
Beta [label=" Beta (l=20, u=0)"];
|
||||
@ -322,10 +329,11 @@ is cores and the default registered limit for cores is 10. Also assume we have
|
||||
the following project hierarchy where `Alpha` has a limit of 20 cores and its
|
||||
usage is currently 4:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -337,10 +345,11 @@ usage is currently 4:
|
||||
|
||||
Technically, both `Beta` and `Charlie` can use up to 8 cores each:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -356,10 +365,11 @@ and check the usage of each project in the hierarchy to see that the total
|
||||
usage of `Alpha`, `Beta`, and `Charlie` is equal to the limit of the tree, set
|
||||
by `Alpha.limit`:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -372,10 +382,11 @@ by `Alpha.limit`:
|
||||
Despite the usage of the tree being equal to the limit, we can still add
|
||||
children to the tree:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -390,10 +401,11 @@ children to the tree:
|
||||
Even though the project can be created, the current usage of cores across the
|
||||
tree prevents `Delta` from claiming any cores:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -408,10 +420,11 @@ tree prevents `Delta` from claiming any cores:
|
||||
Creating a grandchild of project `Alpha` is forbidden because it violates the
|
||||
two-level hierarchical constraint:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -434,10 +447,11 @@ but may be implemented with a separate model.
|
||||
Granting `Beta` the ability to claim more cores can be done by giving `Beta` a
|
||||
project-specific override for cores
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -451,10 +465,11 @@ Note that regardless of this update, any subsequent requests to claim more
|
||||
cores in the tree will be rejected since the usage is equal to the limit of the
|
||||
`Alpha`. `Beta` can claim cores if they are released from `Alpha` or `Charlie`:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -464,10 +479,11 @@ cores in the tree will be rejected since the usage is equal to the limit of the
|
||||
Charlie [label="Charlie (u=6)", textcolor = "#00af00"];
|
||||
}
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -482,10 +498,11 @@ able to claim any more cores because the total usage of the tree is equal to
|
||||
the limit of `Alpha`, thus preventing `Charlie` from reclaiming the cores it
|
||||
had:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -502,10 +519,11 @@ is forbidden. Even though it is possible for the sum of all limits under
|
||||
limit of the parent would result in strange user experience and be misleading
|
||||
since the total usage of the tree would be capped at the limit of the parent:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -515,10 +533,11 @@ since the total usage of the tree would be capped at the limit of the parent:
|
||||
Charlie [label="Charlie (u=0)"];
|
||||
}
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
Alpha -> Charlie;
|
||||
@ -533,10 +552,11 @@ since the total usage of the tree would be capped at the limit of the parent:
|
||||
Finally, let's still assume the default registered limit for cores is 10, but
|
||||
we're going to create project `Alpha` with a limit of 6 cores.
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha;
|
||||
|
||||
@ -548,10 +568,11 @@ API ensures that project `Beta` doesn't assume the default of 10, despite the
|
||||
registered limit of 10 cores. Instead, the child assumes the parent's limit
|
||||
since no single child limit should exceed the limit of the parent:
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
orientation = portrait;
|
||||
node [shape=box]
|
||||
|
||||
Alpha -> Beta;
|
||||
|
||||
@ -562,9 +583,10 @@ since no single child limit should exceed the limit of the parent:
|
||||
This behavior is consistent regardless of the number of children added under
|
||||
project `Alpha`.
|
||||
|
||||
.. blockdiag::
|
||||
.. graphviz::
|
||||
|
||||
blockdiag {
|
||||
digraph {
|
||||
node [shape=box]
|
||||
orientation = portrait;
|
||||
|
||||
Alpha -> Beta;
|
||||
|
@ -34,6 +34,7 @@
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.graphviz',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.todo',
|
||||
'oslo_config.sphinxconfiggen',
|
||||
@ -42,9 +43,7 @@ extensions = [
|
||||
'openstackdocstheme',
|
||||
'oslo_policy.sphinxext',
|
||||
'sphinxcontrib.apidoc',
|
||||
'sphinxcontrib.seqdiag',
|
||||
'sphinx_feature_classification.support_matrix',
|
||||
'sphinxcontrib.blockdiag',
|
||||
]
|
||||
|
||||
blockdiag_html_image_format = 'SVG'
|
||||
|
Loading…
Reference in New Issue
Block a user