Allow omitting admin/internal endpoint

Keystone v3 API does not require that all the three endpoint types are
given and allows using only specific endpoint types(eg. only public, or
public and internal). This allows users to omit specific endpoint types
by setting endpoint url options to ''.

Change-Id: Ifef2070ad25cadf961466ca9f384965d03c08f81
This commit is contained in:
Takashi Kajinami 2024-02-26 12:41:52 +09:00
parent 50b5260cc6
commit 274ecb90d4
12 changed files with 248 additions and 49 deletions

View File

@ -60,18 +60,18 @@
# #
class keystone::bootstrap ( class keystone::bootstrap (
String[1] $password, String[1] $password,
String[1] $username = 'admin', String[1] $username = 'admin',
String[1] $email = 'admin@localhost', String[1] $email = 'admin@localhost',
String[1] $project_name = 'admin', String[1] $project_name = 'admin',
String[1] $service_project_name = 'services', String[1] $service_project_name = 'services',
String[1] $role_name = 'admin', String[1] $role_name = 'admin',
String[1] $service_name = 'keystone', String[1] $service_name = 'keystone',
Stdlib::HTTPUrl $admin_url = 'http://127.0.0.1:5000', Keystone::KeystoneEndpointUrl $admin_url = 'http://127.0.0.1:5000',
Stdlib::HTTPUrl $public_url = 'http://127.0.0.1:5000', Keystone::KeystonePublicEndpointUrl $public_url = 'http://127.0.0.1:5000',
Optional[Stdlib::HTTPUrl] $internal_url = undef, Optional[Keystone::KeystoneEndpointUrl] $internal_url = undef,
String[1] $region = 'RegionOne', String[1] $region = 'RegionOne',
String[1] $interface = 'public', String[1] $interface = 'public',
Boolean $bootstrap = true, Boolean $bootstrap = true,
) inherits keystone::params { ) inherits keystone::params {
include keystone::deps include keystone::deps
@ -88,22 +88,32 @@ class keystone::bootstrap (
} }
if $bootstrap { if $bootstrap {
$bootstrap_adminurl_env = $admin_url ? {
'' => undef,
default => "OS_BOOTSTRAP_ADMIN_URL=${admin_url}",
}
$bootstrap_internalurl_env = $internal_url_real ? {
'' => undef,
default => "OS_BOOTSTRAP_INTERNAL_URL=${internal_url_real}",
}
$bootstrap_env = delete_undef_values([
"OS_BOOTSTRAP_USERNAME=${username}",
"OS_BOOTSTRAP_PASSWORD=${password}",
"OS_BOOTSTRAP_PROJECT_NAME=${project_name}",
"OS_BOOTSTRAP_ROLE_NAME=${role_name}",
"OS_BOOTSTRAP_SERVICE_NAME=${service_name}",
"OS_BOOTSTRAP_PUBLIC_URL=${public_url}",
"OS_BOOTSTRAP_REGION_ID=${region}",
$bootstrap_adminurl_env,
$bootstrap_internalurl_env,
])
# The initial bootstrap that creates all resources required but # The initial bootstrap that creates all resources required but
# only subscribes to notifies from the keystone::dbsync::end anchor # only subscribes to notifies from the keystone::dbsync::end anchor
# which means this is not guaranteed to execute on each run. # which means this is not guaranteed to execute on each run.
exec { 'keystone bootstrap': exec { 'keystone bootstrap':
command => 'keystone-manage bootstrap', command => 'keystone-manage bootstrap',
environment => [ environment => $bootstrap_env,
"OS_BOOTSTRAP_USERNAME=${username}",
"OS_BOOTSTRAP_PASSWORD=${password}",
"OS_BOOTSTRAP_PROJECT_NAME=${project_name}",
"OS_BOOTSTRAP_ROLE_NAME=${role_name}",
"OS_BOOTSTRAP_SERVICE_NAME=${service_name}",
"OS_BOOTSTRAP_ADMIN_URL=${admin_url}",
"OS_BOOTSTRAP_PUBLIC_URL=${public_url}",
"OS_BOOTSTRAP_INTERNAL_URL=${internal_url_real}",
"OS_BOOTSTRAP_REGION_ID=${region}",
],
user => $keystone_user, user => $keystone_user,
path => '/usr/bin', path => '/usr/bin',
refreshonly => true, refreshonly => true,
@ -174,6 +184,9 @@ class keystone::bootstrap (
'internal' => $internal_url_real, 'internal' => $internal_url_real,
default => $public_url default => $public_url
} }
if $auth_url_real == '' {
fail("The ${interface} endpoint should not be empty to be used by the interface parameter.")
}
ensure_resource('file', '/etc/openstack', { ensure_resource('file', '/etc/openstack', {
'ensure' => 'directory', 'ensure' => 'directory',

View File

@ -110,28 +110,28 @@
# Defaults to undef (use the keystone server default domain) # Defaults to undef (use the keystone server default domain)
# #
define keystone::resource::service_identity( define keystone::resource::service_identity(
Enum['present', 'absent'] $ensure = 'present', Enum['present', 'absent'] $ensure = 'present',
Optional[String[1]] $admin_url = undef, Optional[Keystone::EndpointUrl] $admin_url = undef,
Optional[String[1]] $internal_url = undef, Optional[Keystone::EndpointUrl] $internal_url = undef,
Optional[String[1]] $password = undef, Optional[String[1]] $password = undef,
Optional[String[1]] $public_url = undef, Optional[Keystone::PublicEndpointUrl] $public_url = undef,
String[1] $auth_name = $name, String[1] $auth_name = $name,
Optional[String[1]] $service_name = $auth_name, Optional[String[1]] $service_name = $auth_name,
Optional[String[1]] $service_type = undef, Optional[String[1]] $service_type = undef,
Boolean $configure_endpoint = true, Boolean $configure_endpoint = true,
Boolean $configure_user = true, Boolean $configure_user = true,
Boolean $configure_user_role = true, Boolean $configure_user_role = true,
Boolean $configure_service = true, Boolean $configure_service = true,
String $email = "${name}@localhost", String $email = "${name}@localhost",
String[1] $region = 'RegionOne', String[1] $region = 'RegionOne',
String $service_description = "${name} service", String $service_description = "${name} service",
String[1] $tenant = 'services', String[1] $tenant = 'services',
Array[String[1]] $roles = ['admin'], Array[String[1]] $roles = ['admin'],
String[1] $system_scope = 'all', String[1] $system_scope = 'all',
Array[String[1]] $system_roles = [], Array[String[1]] $system_roles = [],
Optional[String[1]] $default_domain = undef, Optional[String[1]] $default_domain = undef,
Optional[String[1]] $user_domain = $default_domain, Optional[String[1]] $user_domain = $default_domain,
Optional[String[1]] $project_domain = $default_domain, Optional[String[1]] $project_domain = $default_domain,
) { ) {
include keystone::deps include keystone::deps

View File

@ -0,0 +1,10 @@
---
features:
- |
The ``keystone::boostrap`` class now supports omitting internal endpoint
and/or admin endpoint. Set the url parameter(s) to ``''`` (empty string).
- |
The ``keystone::resource::service_identity`` defined type now allows
omitting internal endpiint and/or admin endpoint. Set the url parameter(s)
to ``''`` (empty string).

View File

@ -19,10 +19,10 @@ describe 'keystone::bootstrap' do
"OS_BOOTSTRAP_PROJECT_NAME=admin", "OS_BOOTSTRAP_PROJECT_NAME=admin",
"OS_BOOTSTRAP_ROLE_NAME=admin", "OS_BOOTSTRAP_ROLE_NAME=admin",
"OS_BOOTSTRAP_SERVICE_NAME=keystone", "OS_BOOTSTRAP_SERVICE_NAME=keystone",
"OS_BOOTSTRAP_ADMIN_URL=http://127.0.0.1:5000",
"OS_BOOTSTRAP_PUBLIC_URL=http://127.0.0.1:5000", "OS_BOOTSTRAP_PUBLIC_URL=http://127.0.0.1:5000",
"OS_BOOTSTRAP_INTERNAL_URL=http://127.0.0.1:5000",
"OS_BOOTSTRAP_REGION_ID=RegionOne", "OS_BOOTSTRAP_REGION_ID=RegionOne",
"OS_BOOTSTRAP_ADMIN_URL=http://127.0.0.1:5000",
"OS_BOOTSTRAP_INTERNAL_URL=http://127.0.0.1:5000",
], ],
:user => platform_params[:user], :user => platform_params[:user],
:path => '/usr/bin', :path => '/usr/bin',
@ -131,10 +131,10 @@ describe 'keystone::bootstrap' do
"OS_BOOTSTRAP_PROJECT_NAME=adminproj", "OS_BOOTSTRAP_PROJECT_NAME=adminproj",
"OS_BOOTSTRAP_ROLE_NAME=adminrole", "OS_BOOTSTRAP_ROLE_NAME=adminrole",
"OS_BOOTSTRAP_SERVICE_NAME=servicename", "OS_BOOTSTRAP_SERVICE_NAME=servicename",
"OS_BOOTSTRAP_ADMIN_URL=http://admin:1234",
"OS_BOOTSTRAP_PUBLIC_URL=http://public:4321", "OS_BOOTSTRAP_PUBLIC_URL=http://public:4321",
"OS_BOOTSTRAP_INTERNAL_URL=http://internal:1342",
"OS_BOOTSTRAP_REGION_ID=RegionTwo", "OS_BOOTSTRAP_REGION_ID=RegionTwo",
"OS_BOOTSTRAP_ADMIN_URL=http://admin:1234",
"OS_BOOTSTRAP_INTERNAL_URL=http://internal:1342",
], ],
:user => platform_params[:user], :user => platform_params[:user],
:path => '/usr/bin', :path => '/usr/bin',
@ -290,6 +290,74 @@ describe 'keystone::bootstrap' do
:interface => 'internal', :interface => 'internal',
)} )}
end end
context 'when admin endpoint is omitted' do
let :params do
{
:password => 'secret',
:admin_url => '',
}
end
it { is_expected.to contain_exec('keystone bootstrap').with(
:command => 'keystone-manage bootstrap',
:environment => [
"OS_BOOTSTRAP_USERNAME=admin",
"OS_BOOTSTRAP_PASSWORD=secret",
"OS_BOOTSTRAP_PROJECT_NAME=admin",
"OS_BOOTSTRAP_ROLE_NAME=admin",
"OS_BOOTSTRAP_SERVICE_NAME=keystone",
"OS_BOOTSTRAP_PUBLIC_URL=http://127.0.0.1:5000",
"OS_BOOTSTRAP_REGION_ID=RegionOne",
"OS_BOOTSTRAP_INTERNAL_URL=http://127.0.0.1:5000",
],
:user => platform_params[:user],
:path => '/usr/bin',
:refreshonly => true,
:subscribe => 'Anchor[keystone::dbsync::end]',
:notify => 'Anchor[keystone::service::begin]',
:tag => 'keystone-bootstrap',
)}
it { is_expected.to contain_keystone_endpoint('RegionOne/keystone::identity').with(
:ensure => 'present',
:public_url => 'http://127.0.0.1:5000',
:internal_url => 'http://127.0.0.1:5000',
)}
end
context 'when internal endpoint is omitted' do
let :params do
{
:password => 'secret',
:internal_url => '',
}
end
it { is_expected.to contain_exec('keystone bootstrap').with(
:command => 'keystone-manage bootstrap',
:environment => [
"OS_BOOTSTRAP_USERNAME=admin",
"OS_BOOTSTRAP_PASSWORD=secret",
"OS_BOOTSTRAP_PROJECT_NAME=admin",
"OS_BOOTSTRAP_ROLE_NAME=admin",
"OS_BOOTSTRAP_SERVICE_NAME=keystone",
"OS_BOOTSTRAP_PUBLIC_URL=http://127.0.0.1:5000",
"OS_BOOTSTRAP_REGION_ID=RegionOne",
"OS_BOOTSTRAP_ADMIN_URL=http://127.0.0.1:5000",
],
:user => platform_params[:user],
:path => '/usr/bin',
:refreshonly => true,
:subscribe => 'Anchor[keystone::dbsync::end]',
:notify => 'Anchor[keystone::service::begin]',
:tag => 'keystone-bootstrap',
)}
it { is_expected.to contain_keystone_endpoint('RegionOne/keystone::identity').with(
:ensure => 'present',
:public_url => 'http://127.0.0.1:5000',
:admin_url => 'http://127.0.0.1:5000',
)}
end
end end
on_supported_os({ on_supported_os({

View File

@ -0,0 +1,31 @@
require 'spec_helper'
describe 'Keystone::EndpointUrl' do
describe 'valid types' do
context 'with valid types' do
[
'http://127.0.0.1:5000',
'https://[::1]:5000',
'ws://127.0.0.1:5000',
'wss://[::1]:5000',
''
].each do |value|
describe value.inspect do
it { is_expected.to allow_value(value) }
end
end
end
end
describe 'invalid types' do
context 'with garbage inputs' do
[
'ftp://127.0.0.1:5000',
].each do |value|
describe value.inspect do
it { is_expected.not_to allow_value(value) }
end
end
end
end
end

View File

@ -0,0 +1,31 @@
require 'spec_helper'
describe 'Keystone::KeystoneEndpointUrl' do
describe 'valid types' do
context 'with valid types' do
[
'http://127.0.0.1:5000',
'https://[::1]:5000',
''
].each do |value|
describe value.inspect do
it { is_expected.to allow_value(value) }
end
end
end
end
describe 'invalid types' do
context 'with garbage inputs' do
[
'ws://127.0.0.1:5000',
'wss://[::1]:5000',
'ftp://127.0.0.1:5000',
].each do |value|
describe value.inspect do
it { is_expected.not_to allow_value(value) }
end
end
end
end
end

View File

@ -0,0 +1,31 @@
require 'spec_helper'
describe 'Keystone::PublicEndpointUrl' do
describe 'valid types' do
context 'with valid types' do
[
'http://127.0.0.1:5000',
'https://[::1]:5000',
'ws://127.0.0.1:5000',
'wss://[::1]:5000',
].each do |value|
describe value.inspect do
it { is_expected.to allow_value(value) }
end
end
end
end
describe 'invalid types' do
context 'with garbage inputs' do
[
'ftp://127.0.0.1:5000',
''
].each do |value|
describe value.inspect do
it { is_expected.not_to allow_value(value) }
end
end
end
end
end

4
types/endpointurl.pp Normal file
View File

@ -0,0 +1,4 @@
type Keystone::EndpointUrl = Variant[
Keystone::PublicEndpointUrl,
Keystone::OmittedEndpointUrl
]

View File

@ -0,0 +1,4 @@
type Keystone::KeystoneEndpointUrl = Variant[
Keystone::KeystonePublicEndpointUrl,
Keystone::OmittedEndpointUrl
]

View File

@ -0,0 +1 @@
type Keystone::KeystonePublicEndpointUrl = Stdlib::HTTPUrl

View File

@ -0,0 +1 @@
type Keystone::OmittedEndpointUrl = String[0, 0]

View File

@ -0,0 +1,5 @@
type Keystone::PublicEndpointUrl = Variant[
Stdlib::HTTPUrl,
# NOTE(tkajinam): This is required by Zaqar
Pattern[/(?i:\Awss?:\/\/.*\z)/],
]