use_cookbook-openstackclient/identity_v3

- Removed v2 support
- Workover Endpoint creation
  Identity Endpoints now will be bootstrapped
- Removed bootstrap_token
- Added domain_creation
- Edited openrc to work with itendity_v3
- changed "tenant"-naming to project
- Removed unused files and functions
  providers/register.rb
  spec/register_spec.rb
  resources/register.rb
  libraries/machters.rb
- rewrote specs
- updated readme
- added apache_site disable keystone since
  ubuntu auto-enables it
- bumbed ubuntu version to 16.04

Change-Id: I0f8955f05de9b33711c54b9a198f45018cceb8e1
This commit is contained in:
Christoph Albers 2016-08-31 14:29:51 +02:00
parent 0751804867
commit 4dcd956337
16 changed files with 200 additions and 1749 deletions

View File

@ -4,3 +4,6 @@ metadata
cookbook "openstack-common",
github: "openstack/cookbook-openstack-common"
cookbook "openstackclient",
github: "cloudbau/cookbook-openstackclient"

140
README.md
View File

@ -30,7 +30,8 @@ Cookbooks
The following cookbooks are dependencies:
- 'apache2', '~> 3.1'
- 'openstack-common', '>= 13.0.0'
- 'openstack-common', '>= 14.0.0'
- 'openstackclient', '>= 0.1.0'
Attributes
==========
@ -64,142 +65,6 @@ Recipes
apache webserver. The recipe is documented in detail with inline comments
inside the recipe.
Resources
=========
## openstack_identity_register
### Actions
- create_ec2_credentials:
- create_endpoint:
- create_role:
- create_service:
- create_tenant:
- create_user:
- grant_role:
### Attribute Parameters
- auth_uri: The uri used to as authentication endpoint for requests
- bootstrap_token: The admin bootstrap_token used for authentication
- service_type: Type of service to create (e.g. 'identity' or 'volume')
- service_name: The name of the service to create (only for action
:create_service)
- service_description: The description for the service to create (only for
action :create_service)
- endpoint_region: The region to create the endpoint in (only for action
:create_endpoint) Defaults to <code>"RegionOne"</code>.
- endpoint_adminurl: The public url to register for the endpoint (only for
action :create_endpoint)
- endpoint_internalurl: The internal url to register for the endpoint (only for
action :create_endpoint)
- endpoint_publicurl: The public url to register for the endpoint (only for
action :create_endpoint)
- tenant_name: The name of the tenant to create or create the user in (only for
action :create_tenant and :create_user)
- tenant_description: The description of the tenant to create (only for action
:create_tenant)
- tenant_enabled: Enable or disable tenant to create (only for action
:create_tenant) Defaults to <code>true</code>.
- user_name: The name of the user to create (only for action :create_user)
- user_pass: The passwort of the user to create (only for action :create_user)
- user_enabled: Enable or disable user to create (only for action :create_user)
Defaults to <code>true</code>.
- role_name: The name of the role to create or grant to the user (only for
:create_role and :grant_role)
- admin_tenant_name: The name of the admin tenant (only for
:create_ec2_credentials)
- admin_user: The name of the admin user (only for :create_ec2_credentials)
- admin_pass: The password of the admin user (only for :create_ec2_credentials)
- identity_endpoint: The identity endpoint to use for user and ec2 creation. If
not specified, default endpoint will be used. (only for create_ec2_credentials
and create_user)
### Examples
```
# Create 'openstack' tenant
openstack_identity_register "Register 'openstack' Tenant" do
auth_host "192.168.1.10"
auth_port "35357"
auth_protocol "http"
api_ver "/v2.0"
auth_token "123456789876"
tenant_name "openstack"
tenant_description "Default Tenant"
tenant_enabled "true" # Not required as this is the default
action :create_tenant
end
# Create 'admin' user
openstack_identity_register "Register 'admin' User" do
auth_host "192.168.1.10"
auth_port "35357"
auth_protocol "http"
api_ver "/v2.0"
auth_token "123456789876"
tenant_name "openstack"
user_name "admin"
user_pass "secrete"
user_enabled "true" # Not required as this is the default
action :create_user
end
# Create 'admin' role
openstack_identity_register "Register 'admin' Role" do
auth_host "192.168.1.10"
auth_port "35357"
auth_protocol "http"
api_ver "/v2.0"
auth_token "123456789876"
role_name role_key
action :create_role
end
# Grant 'admin' role to 'admin' user in the 'openstack' tenant
openstack_identity_register "Grant 'admin' Role to 'admin' User" do
auth_host "192.168.1.10"
auth_port "35357"
auth_protocol "http"
api_ver "/v2.0"
auth_token "123456789876"
tenant_name "openstack"
user_name "admin"
role_name "admin"
action :grant_role
end
# Create 'identity' service
openstack_identity_register "Register Identity Service" do
auth_host "192.168.1.10"
auth_port "35357"
auth_protocol "http"
api_ver "/v2.0"
auth_token "123456789876"
service_name "keystone"
service_type "identity"
service_description "Keystone Identity Service"
action :create_service
end
# Create 'identity' endpoint
openstack_identity_register "Register Identity Endpoint" do
auth_host "192.168.1.10"
auth_port "35357"
auth_protocol "http"
api_ver "/v2.0"
auth_token "123456789876"
service_type "identity"
endpoint_region "RegionOne"
endpoint_adminurl "http://192.168.1.10:35357/v2.0"
endpoint_internalurl "http://192.168.1.10:5001/v2.0"
endpoint_publicurl "http://1.2.3.4:5001/v2.0"
action :create_endpoint
end
```
License and Author
==================
@ -218,6 +83,7 @@ Author:: Ionut Artarisi (<iartarisi@suse.cz>)
Author:: Chen Zhiwei (zhiwchen@cn.ibm.com)
Author:: Eric Zhou (zyouzhou@cn.ibm.com)
Author:: Jan Klare (j.klare@cloudbau.de)
Author:: Christoph Albers (<c.albers@x-ion.de>)
Copyright 2012, Rackspace US, Inc.
Copyright 2012-2013, Opscode, Inc.

View File

@ -30,7 +30,7 @@ default['openstack']['identity']['custom_template_banner'] =
# scheme for openstack admin/internal/public identity endpoint
default['openstack']['endpoints'][ep_type]['identity']['scheme'] = 'http'
# path for openstack admin/internal/public identity endpoint
default['openstack']['endpoints'][ep_type]['identity']['path'] = '/v2.0'
default['openstack']['endpoints'][ep_type]['identity']['path'] = '/v3'
end
# port for openstack public identity endpoint
@ -96,18 +96,14 @@ default['openstack']['identity']['syslog']['config_facility'] = 'local2'
# user to be created and used for identity service
default['openstack']['identity']['admin_user'] = 'admin'
# tenant to be created and used for identity service
default['openstack']['identity']['admin_tenant_name'] = 'admin'
default['openstack']['identity']['users'] = {
default['openstack']['identity']['admin_user'] => {
'default_tenant' => default['openstack']['identity']['admin_tenant_name'],
'roles' => {
'admin' => ['admin'],
'service' => ['admin']
}
}
}
# project to be created and used for identity service
default['openstack']['identity']['admin_project'] = 'admin'
# domain to be created and used for identity service project
default['openstack']['identity']['admin_project_domain'] = 'default'
# role to be created and used for identity service
default['openstack']['identity']['admin_role'] = 'admin'
# domain to be created and used for identity service user
default['openstack']['identity']['admin_domain_name'] = 'default'
# specify whether to enable SSL for Keystone API endpoint
default['openstack']['identity']['ssl']['enabled'] = false
@ -144,6 +140,8 @@ default['openstack']['identity']['fernet']['keys'] = [0, 1]
default['openstack']['identity']['auth']['external'] = 'keystone.auth.plugins.external.DefaultDomain'
# Default auth methods. (List value)
default['openstack']['identity']['auth']['methods'] = 'external, password, token, oauth1'
# Default auth_version for now
default['openstack']['identity']['auth']['version'] = 'v3'
# enable or disable the usage of the token flushing cronjob
default['openstack']['identity']['token_flush_cron']['enabled'] = true

View File

@ -1,51 +0,0 @@
# encoding: UTF-8
if defined?(ChefSpec)
def create_service_openstack_identity_register(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(
:openstack_identity_register,
:create_service,
resource_name)
end
def create_endpoint_openstack_identity_register(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(
:openstack_identity_register,
:create_endpoint,
resource_name)
end
def create_tenant_openstack_identity_register(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(
:openstack_identity_register,
:create_tenant,
resource_name)
end
def create_user_openstack_identity_register(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(
:openstack_identity_register,
:create_user,
resource_name)
end
def create_role_openstack_identity_register(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(
:openstack_identity_register,
:create_role,
resource_name)
end
def grant_role_openstack_identity_register(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(
:openstack_identity_register,
:grant_role,
resource_name)
end
def create_ec2_credentials_openstack_identity_register(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(
:openstack_identity_register,
:create_ec2_credentials,
resource_name)
end
end

View File

@ -14,3 +14,4 @@ end
depends 'apache2', '~> 3.1'
depends 'openstack-common', '>= 14.0.0'
depends 'openstackclient'

View File

@ -1,347 +0,0 @@
# encoding: UTF-8
#
# Cookbook Name:: openstack-identity
# Provider:: register
#
# Copyright 2012, Rackspace US, Inc.
# Copyright 2012-2013, AT&T Services, Inc.
# Copyright 2013, Opscode, Inc.
# Copyright 2013, Craig Tracey <craigtracey@gmail.com>
#
# Licensed 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.
require 'chef/mixin/shell_out'
include Chef::Mixin::ShellOut
include ::Openstack
use_inline_resources
# creates the defined service as new service for keystone
action :create_service do
new_resource.updated_by_last_action(false)
if node['openstack']['identity']['catalog']['backend'] == 'templated'
Chef::Log.info('Skipping service creation - templated catalog backend in use.')
else
begin
service_uuid = identity_uuid new_resource, 'service', 'type', new_resource.service_type
need_updated = false
if service_uuid
Chef::Log.info("Service Type '#{new_resource.service_type}' already exists..")
Chef::Log.info("Service UUID: #{service_uuid}")
need_updated = service_need_updated? new_resource
if need_updated
Chef::Log.info("Service Type '#{new_resource.service_type}' needs to be updated, delete it first.")
identity_command(new_resource, 'service-delete',
'' => service_uuid)
end
end
unless service_uuid && !need_updated
identity_command(new_resource, 'service-create',
'type' => new_resource.service_type,
'name' => new_resource.service_name,
'description' => new_resource.service_description)
Chef::Log.info("Created service '#{new_resource.service_name}'")
new_resource.updated_by_last_action(true)
end
rescue StandardError => e
raise "Unable to create service '#{new_resource.service_name}' Error:" + e.message
end
end
end
# registers all endpoints for the defined service in keystone
action :create_endpoint do
new_resource.updated_by_last_action(false)
if node['openstack']['identity']['catalog']['backend'] == 'templated'
Chef::Log.info('Skipping endpoint creation - templated catalog backend in use.')
else
begin
service_uuid = identity_uuid new_resource, 'service', 'type', new_resource.service_type
raise "Unable to find service type '#{new_resource.service_type}'" unless service_uuid
endpoint_uuid = identity_uuid new_resource, 'endpoint', 'service_id', service_uuid
need_updated = false
if endpoint_uuid
Chef::Log.info("Endpoint already exists for Service Type '#{new_resource.service_type}'.")
need_updated = endpoint_need_updated? new_resource, 'service_id', service_uuid
if need_updated
Chef::Log.info("Endpoint for Service Type '#{new_resource.service_type}' needs to be updated, delete it first.")
identity_command(new_resource, 'endpoint-delete',
'' => endpoint_uuid)
end
end
unless endpoint_uuid && !need_updated
identity_command(new_resource, 'endpoint-create',
'region' => new_resource.endpoint_region,
'service_id' => service_uuid,
'publicurl' => new_resource.endpoint_publicurl,
'internalurl' => new_resource.endpoint_internalurl,
'adminurl' => new_resource.endpoint_adminurl)
Chef::Log.info("Created endpoint for service type '#{new_resource.service_type}'")
new_resource.updated_by_last_action(true)
end
rescue StandardError => e
raise "Unable to create endpoint for service type '#{new_resource.service_type}' Error: " + e.message
end
end
end
# creates the defined tenant in keystone
action :create_tenant do
begin
new_resource.updated_by_last_action(false)
tenant_uuid = identity_uuid new_resource, 'tenant', 'name', new_resource.tenant_name
if tenant_uuid
Chef::Log.info("Tenant '#{new_resource.tenant_name}' already exists.. Not creating.")
Chef::Log.info("Tenant UUID: #{tenant_uuid}") if tenant_uuid
else
identity_command(new_resource, 'tenant-create',
'name' => new_resource.tenant_name,
'description' => new_resource.tenant_description,
'enabled' => new_resource.tenant_enabled)
Chef::Log.info("Created tenant '#{new_resource.tenant_name}'")
new_resource.updated_by_last_action(true)
end
rescue StandardError => e
raise "Unable to create tenant '#{new_resource.tenant_name}' Error: " + e.message
end
end
# creates the defined role in keystone
action :create_role do
begin
new_resource.updated_by_last_action(false)
role_uuid = identity_uuid new_resource, 'role', 'name', new_resource.role_name
if role_uuid
Chef::Log.info("Role '#{new_resource.role_name}' already exists.. Not creating.")
Chef::Log.info("Role UUID: #{role_uuid}")
else
identity_command(new_resource, 'role-create',
'name' => new_resource.role_name)
Chef::Log.info("Created Role '#{new_resource.role_name}'")
new_resource.updated_by_last_action(true)
end
rescue StandardError => e
raise "Unable to create role '#{new_resource.role_name}' Error: " + e.message
end
end
# creates the defined user in keystone
action :create_user do
begin
new_resource.updated_by_last_action(false)
output = identity_command(new_resource, 'user-list')
users = prettytable_to_array output
user_found = false
users.each do |user|
user_found = true if user['name'] == new_resource.user_name
end
if user_found
Chef::Log.info("User '#{new_resource.user_name}' already exists")
begin
# Check if password is already updated by getting a token
identity_command(new_resource, 'token-get', {}, 'user')
rescue StandardError => e
Chef::Log.debug('Get token error:' + e.message)
Chef::Log.info("Sync password for user '#{new_resource.user_name}'")
identity_command(new_resource, 'user-password-update',
'pass' => new_resource.user_pass,
'' => new_resource.user_name)
new_resource.updated_by_last_action(true)
end
next
end
identity_command(new_resource, 'user-create',
'name' => new_resource.user_name,
'tenant' => new_resource.tenant_name,
'pass' => new_resource.user_pass,
'enabled' => new_resource.user_enabled)
Chef::Log.info("Created user '#{new_resource.user_name}' for tenant '#{new_resource.tenant_name}'")
new_resource.updated_by_last_action(true)
rescue StandardError => e
raise "Unable to create user '#{new_resource.user_name}' for tenant '#{new_resource.tenant_name}' Error: " + e.message
end
end
# grants the defined role to a given user in a given tenant
action :grant_role do
begin
new_resource.updated_by_last_action(false)
role_uuid = identity_uuid new_resource, 'role', 'name', new_resource.role_name
raise "Unable to find role '#{new_resource.role_name}'" unless role_uuid
assigned_role_uuid = identity_uuid(new_resource, 'user-role', 'name',
new_resource.role_name,
'tenant' => new_resource.tenant_name,
'user' => new_resource.user_name)
if role_uuid == assigned_role_uuid
Chef::Log.info("Role '#{new_resource.role_name}' already granted to User '#{new_resource.user_name}' in Tenant '#{new_resource.tenant_name}'")
else
identity_command(new_resource, 'user-role-add',
'tenant' => new_resource.tenant_name,
'role-id' => role_uuid,
'user' => new_resource.user_name)
Chef::Log.info("Granted Role '#{new_resource.role_name}' to User '#{new_resource.user_name}' in Tenant '#{new_resource.tenant_name}'")
new_resource.updated_by_last_action(true)
end
rescue StandardError => e
raise "Unable to grant role '#{new_resource.role_name}' to user '#{new_resource.user_name}' Error: " + e.message
end
end
# creates ec2_credentials for a given user in a given tenant
action :create_ec2_credentials do
begin
new_resource.updated_by_last_action(false)
tenant_uuid = identity_uuid new_resource, 'tenant', 'name', new_resource.tenant_name
raise "Unable to find tenant '#{new_resource.tenant_name}'" unless tenant_uuid
user_uuid = identity_uuid(new_resource, 'user', 'name',
new_resource.user_name,
'tenant-id' => tenant_uuid)
raise "Unable to find user '#{new_resource.user_name}' with tenant '#{new_resource.tenant_name}'" unless user_uuid
# this is not really a uuid, but this will work nonetheless
access = identity_uuid new_resource, 'ec2-credentials', 'tenant', new_resource.tenant_name, { 'user-id' => user_uuid }, 'access'
if access
Chef::Log.info("EC2 credentials already exist for '#{new_resource.user_name}' in tenant '#{new_resource.tenant_name}'")
else
output = identity_command(new_resource, 'ec2-credentials-create',
{ 'user-id' => user_uuid,
'tenant-id' => tenant_uuid },
'admin')
Chef::Log.info("Created EC2 Credentials for User '#{new_resource.user_name}' in Tenant '#{new_resource.tenant_name}'")
data = prettytable_to_array(output)
if data.length != 1
raise "Got bad data when creating ec2 credentials for #{new_resource.user_name} Data: #{data}"
else
# Update node attributes
node.set['credentials']['EC2'][new_resource.user_name]['access'] = data[0]['access']
node.set['credentials']['EC2'][new_resource.user_name]['secret'] = data[0]['secret']
node.save unless Chef::Config[:solo]
new_resource.updated_by_last_action(true)
end
end
rescue StandardError => e
raise "Unable to create EC2 Credentials for User '#{new_resource.user_name}' in Tenant '#{new_resource.tenant_name}' Error: " + e.message
end
end
private
def generate_boot_creds(resource)
{
'OS_SERVICE_ENDPOINT' => resource.auth_uri,
'OS_SERVICE_TOKEN' => resource.bootstrap_token
}
end
def generate_admin_creds(resource)
identity_endpoint = resource.identity_endpoint
identity_endpoint = admin_endpoint('identity').to_s unless identity_endpoint
{
'OS_USERNAME' => resource.admin_user,
'OS_PASSWORD' => resource.admin_pass,
'OS_TENANT_NAME' => resource.admin_tenant_name,
'OS_AUTH_URL' => identity_endpoint
}
end
def generate_user_creds(resource)
identity_endpoint = resource.identity_endpoint
identity_endpoint = public_endpoint('identity').to_s unless identity_endpoint
{
'OS_USERNAME' => resource.user_name,
'OS_PASSWORD' => resource.user_pass,
'OS_TENANT_NAME' => resource.tenant_name,
'OS_AUTH_URL' => identity_endpoint
}
end
def get_env(resource, env = 'boot')
case env
when 'boot'
generate_boot_creds(resource)
when 'user'
generate_user_creds(resource)
when 'admin'
generate_admin_creds(resource)
end
end
def identity_command(resource, cmd, args = {}, env = 'boot')
keystonecmd = build_keystone_cmd(cmd, args)
cmd_env = get_env(resource, env)
Chef::Log.debug("Running identity command: #{keystonecmd} env: " + cmd_env.to_s)
rc = shell_out(keystonecmd, env: cmd_env)
raise "#{rc.stderr} (#{rc.exitstatus})" if rc.exitstatus != 0
rc.stdout
end
def build_keystone_cmd(cmd, args)
keystonecmd = ['keystone'] << '--insecure' << cmd
args.each do |key, val|
keystonecmd << "--#{key}" unless key.empty?
keystonecmd << val.to_s
end
keystonecmd
end
def identity_uuid(resource, type, key, value, args = {}, uuid_field = 'id')
rc = nil
begin
output = identity_command resource, "#{type}-list", args
output = prettytable_to_array(output)
rc = (type == 'endpoint') ? search_uuid(output, uuid_field, key => value, 'region' => resource.endpoint_region) : search_uuid(output, uuid_field, key => value)
rescue RuntimeError => e
raise "Could not lookup uuid for #{type}:#{key}=>#{value}. Error was #{e.message}"
end
rc
end
def search_uuid(output, uuid_field, required_hash = {})
rc = nil
output.each do |obj|
rc = obj[uuid_field] if obj.key?(uuid_field) && required_hash.values - obj.values_at(*required_hash.keys) == []
end
rc
end
def service_need_updated?(resource, args = {}, uuid_field = 'id')
begin
output = identity_command resource, 'service-list', args
output = prettytable_to_array(output)
return search_uuid(output, uuid_field, 'name' => resource.service_name).nil?
rescue RuntimeError => e
raise "Could not check service attributes for service: type => #{resource.service_type}, name => #{resource.service_name}. Error was #{e.message}"
end
false
end
def endpoint_need_updated?(resource, key, value, args = {}, uuid_field = 'id')
begin
output = identity_command resource, 'endpoint-list', args
output = prettytable_to_array(output)
return search_uuid(output, uuid_field, key => value, 'region' => resource.endpoint_region, 'publicurl' => resource.endpoint_publicurl, 'internalurl' => resource.endpoint_internalurl, 'adminurl' => resource.endpoint_adminurl).nil?
rescue RuntimeError => e
raise "Could not check endpoint attributes for endpoint:#{key}=>#{value}. Error was #{e.message}"
end
false
end

View File

@ -24,25 +24,15 @@ class ::Chef::Recipe
include ::Openstack
end
# check attributes before searching
if node['openstack']['identity'] && node['openstack']['identity']['admin_tenant_name'] && node['openstack']['identity']['admin_user']
ksadmin_tenant_name = node['openstack']['identity']['admin_tenant_name']
ksadmin_user = node['openstack']['identity']['admin_user']
else
identity_service_role = node['openstack']['identity_service_chef_role']
keystone = search_for(identity_service_role).first
if keystone.nil?
Chef::Log.warn("openrc not created, identity role node not found: #{identity_service_role}")
return
end
ksadmin_tenant_name = keystone['openstack']['identity']['admin_tenant_name']
ksadmin_user = keystone['openstack']['identity']['admin_user']
end
ksadmin_project = node['openstack']['identity']['admin_project']
project_domain_name = node['openstack']['identity']['admin_project_domain']
ksadmin_user = node['openstack']['identity']['admin_user']
admin_domain_name = node['openstack']['identity']['admin_domain_name']
auth_api_version = node['openstack']['api']['auth']['version']
ksadmin_pass = get_password 'user', ksadmin_user
identity_public_endpoint = public_endpoint 'identity'
auth_url = auth_uri_transform identity_public_endpoint.to_s, auth_api_version
directory node['openstack']['openrc']['path'] do
owner node['openstack']['openrc']['user']
@ -59,8 +49,11 @@ template "#{node['openstack']['openrc']['path']}/#{node['openstack']['openrc']['
sensitive true
variables(
user: ksadmin_user,
tenant: ksadmin_tenant_name,
user_domain_name: admin_domain_name,
project: ksadmin_project,
project_domain_name: project_domain_name,
api_version: '3',
password: ksadmin_pass,
identity_endpoint: identity_public_endpoint
identity_endpoint: auth_url
)
end

View File

@ -24,92 +24,65 @@
# comments inside the recipe.
require 'uri'
require 'chef/mixin/shell_out'
class ::Chef::Recipe
include ::Openstack
end
# define the endpoints to register for the keystone identity service
identity_admin_endpoint = admin_endpoint 'identity'
identity_internal_endpoint = internal_endpoint 'identity'
identity_public_endpoint = public_endpoint 'identity'
auth_uri = ::URI.decode identity_admin_endpoint.to_s
auth_url = ::URI.decode identity_admin_endpoint.to_s
# define the credentials to use for the initial admin user
admin_tenant_name = node['openstack']['identity']['admin_tenant_name']
admin_project = node['openstack']['identity']['admin_project']
admin_user = node['openstack']['identity']['admin_user']
admin_pass = get_password 'user', node['openstack']['identity']['admin_user']
admin_role = node['openstack']['identity']['admin_role']
admin_domain = node['openstack']['identity']['admin_domain_name']
region = node['openstack']['identity']['region']
bootstrap_token = get_password 'token', 'openstack_identity_bootstrap_token'
# register all the tenants specified in the users hash
identity_tenants = node['openstack']['identity']['users'].values.map do |user_info|
user_info['roles'].values.push(user_info['default_tenant'])
execute 'bootstrap_keystone' do
command "keystone-manage bootstrap \\
--bootstrap-password #{admin_pass} \\
--bootstrap-username #{admin_user} \\
--bootstrap-project-name #{admin_project} \\
--bootstrap-role-name #{admin_role} \\
--bootstrap-service-name keystone \\
--bootstrap-region-id #{region} \\
--bootstrap-admin-url #{identity_admin_endpoint} \\
--bootstrap-public-url #{identity_public_endpoint} \\
--bootstrap-internal-url #{identity_internal_endpoint}"
end
identity_tenants.flatten.uniq.each do |tenant_name|
openstack_identity_register "Register '#{tenant_name}' Tenant" do
auth_uri auth_uri
bootstrap_token bootstrap_token
tenant_name tenant_name
tenant_description "#{tenant_name} Tenant"
connection_params = {
openstack_auth_url: "#{auth_url}/auth/tokens",
openstack_username: admin_user,
openstack_api_key: admin_pass,
openstack_project_name: admin_project,
openstack_domain_name: admin_domain
}
action :create_tenant
end
openstack_domain admin_domain do
connection_params connection_params
end
# register all the roles and users from the users hash
identity_roles = node['openstack']['identity']['users'].values.map do |user_info|
user_info['roles'].keys
openstack_user admin_user do
domain_name admin_domain
role_name admin_role
connection_params connection_params
action :grant_domain
end
identity_roles.flatten.uniq.each do |role_name|
openstack_identity_register "Register '#{role_name}' Role" do
auth_uri auth_uri
bootstrap_token bootstrap_token
role_name role_name
action :create_role
end
# create default service role
openstack_role 'service' do
connection_params connection_params
end
node['openstack']['identity']['users'].each do |username, user_info|
pwd = get_password 'user', username
openstack_identity_register "Register '#{username}' User" do
auth_uri auth_uri
bootstrap_token bootstrap_token
user_name username
user_pass pwd
tenant_name user_info['default_tenant']
user_enabled true # Not required as this is the default
action :create_user
end
user_info['roles'].each do |rolename, tenant_list|
tenant_list.each do |tenantname|
openstack_identity_register "Grant '#{rolename}' Role to '#{username}' User in '#{tenantname}' Tenant" do
auth_uri auth_uri
bootstrap_token bootstrap_token
user_name username
role_name rolename
tenant_name tenantname
action :grant_role
end
end
end
end
# register the identity service itself
openstack_identity_register 'Register Identity Service' do
auth_uri auth_uri
bootstrap_token bootstrap_token
service_name 'keystone'
service_type 'identity'
service_description 'Keystone Identity Service'
action :create_service
not_if { node['openstack']['identity']['catalog']['backend'] == 'templated' }
# create default role for horizon dashboard login
openstack_role '_member_' do
connection_params connection_params
end
node.set['openstack']['identity']['adminURL'] = identity_admin_endpoint.to_s
@ -119,32 +92,3 @@ node.set['openstack']['identity']['publicURL'] = identity_public_endpoint.to_s
Chef::Log.info "Keystone AdminURL: #{identity_admin_endpoint}"
Chef::Log.info "Keystone InternalURL: #{identity_internal_endpoint}"
Chef::Log.info "Keystone PublicURL: #{identity_public_endpoint}"
# register the identity service endpoints
openstack_identity_register 'Register Identity Endpoint' do
auth_uri auth_uri
bootstrap_token bootstrap_token
service_type 'identity'
endpoint_region node['openstack']['identity']['region']
endpoint_adminurl node['openstack']['identity']['adminURL']
endpoint_internalurl node['openstack']['identity']['internalURL']
endpoint_publicurl node['openstack']['identity']['publicURL']
action :create_endpoint
not_if { node['openstack']['identity']['catalog']['backend'] == 'templated' }
end
# create ec2 creadentials for the users from the users hash
node['openstack']['identity']['users'].each do |username, user_info|
openstack_identity_register "Create EC2 credentials for '#{username}' user" do
auth_uri auth_uri
bootstrap_token bootstrap_token
user_name username
tenant_name user_info['default_tenant']
admin_tenant_name admin_tenant_name
admin_user admin_user
admin_pass admin_pass
action :create_ec2_credentials
end
end

View File

@ -120,9 +120,6 @@ node.default['openstack']['identity']['conf_secrets']
.[]('database')['connection'] =
db_uri('identity', db_user, db_pass)
# define the admin keystone bootstrap token
bootstrap_token = get_password 'token', 'openstack_identity_bootstrap_token'
# search for memcache servers using the method from cookbook-openstack-common
memcache_servers = memcached_servers.join ','
@ -168,7 +165,6 @@ end
# set keystone config parameters for admin_token, endpoints and memcache
node.default['openstack']['identity']['conf'].tap do |conf|
conf['DEFAULT']['admin_token'] = bootstrap_token
conf['DEFAULT']['public_endpoint'] = public_endpoint
conf['DEFAULT']['admin_endpoint'] = admin_endpoint
conf['memcache']['servers'] = memcache_servers if memcache_servers
@ -334,6 +330,11 @@ wsgi_apps.each do |app, opt|
end
end
# disable keystone-site since ubuntu autoenables this
apache_site 'keystone' do
enable false
end
# wait for apache2 to be fully reloaded and the keystone endpoint to become
# available
execute 'Keystone: sleep' do

View File

@ -1,79 +0,0 @@
# encoding: UTF-8
#
# Cookbook Name:: openstack-identity
# Resource:: register
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed 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.
# These resources provide an abstraction layer for interacting with the keystone
# server's API, allowin for other nodes to register any required users, tenants,
# roles, services, or endpoints.
actions :create_service, :create_endpoint, :create_tenant, :create_user, :create_role, :grant_role, :create_ec2_credentials
# In earlier versions of Chef the LWRP DSL doesn't support specifying
# a default action, so you need to drop into Ruby.
def initialize(*args)
super
@action = :create
end
BOOLEAN = [TrueClass, FalseClass].freeze
# The uri used to as authentication endpoint for requests
attribute :auth_uri, kind_of: String
# The admin bootstrap_token used for authentication
attribute :bootstrap_token, kind_of: String
# The type of service to create (e.g. 'identity' or 'volume')
attribute :service_type, kind_of: String
# The name of the service to create (only for action :create_service)
attribute :service_name, kind_of: String
# The description for the service to create (only for action :create_service)
attribute :service_description, kind_of: String
# The region to create the endpoint in (only for action :create_endpoint)
attribute :endpoint_region, kind_of: String, default: 'RegionOne'
# The admin url to register for the endpoint (only for action :create_endpoint)
attribute :endpoint_adminurl, kind_of: String
# The internal url to register for the endpoint (only for action
# :create_endpoint)
attribute :endpoint_internalurl, kind_of: String
# The public url to register for the endpoint (only for action :create_endpoint)
attribute :endpoint_publicurl, kind_of: String
# The name of the tenant to create or create the user in (only for action
# :create_tenant and :create_user)
attribute :tenant_name, kind_of: String
# The description of the tenant to create (only for action :create_tenant)
attribute :tenant_description, kind_of: String
# Enable or disable tenant to create (only for action :create_tenant)
attribute :tenant_enabled, kind_of: BOOLEAN, default: true
# The name of the user to create (only for action :create_user)
attribute :user_name, kind_of: String
# The passwort of the user to create (only for action :create_user)
attribute :user_pass, kind_of: String
# Enable or disable user to create (only for action :create_user)
attribute :user_enabled, kind_of: BOOLEAN, default: true
# The name of the role to create or grant to the user (only for :create_role and
# :grant_role)
attribute :role_name, kind_of: String
# The name of the admin tenant (only for :create_ec2_credentials)
attribute :admin_tenant_name, kind_of: String
# The name of the admin user (only for :create_ec2_credentials)
attribute :admin_user, kind_of: String
# The password of the admin user (only for :create_ec2_credentials)
attribute :admin_pass, kind_of: String
# The identity endpoint to use for user and ec2 creation. If not specified,
# default endpoint will be used. (only for create_ec2_credentials and
# create_user)
attribute :identity_endpoint, kind_of: String

View File

@ -33,9 +33,12 @@ describe 'openstack-identity::openrc' do
it 'contains auth environment variables' do
[
/^export OS_USERNAME=admin$/,
/^export OS_TENANT_NAME=admin$/,
/^export OS_USER_DOMAIN_NAME=default$/,
/^export OS_PASSWORD=admin$/,
%r{^export OS_AUTH_URL=http://127.0.0.1:5000/v2.0$},
/^export OS_PROJECT_NAME=admin$/,
/^export OS_PROJECT_DOMAIN_NAME=default$/,
/^export OS_IDENTITY_API_VERSION=3$/,
%r{^export OS_AUTH_URL=http://127.0.0.1:5000/v3$},
/^export OS_REGION_NAME=RegionOne$/
].each do |line|
expect(chef_run).to render_file(file.name).with_content(line)
@ -51,11 +54,19 @@ describe 'openstack-identity::openrc' do
end
it 'contains overridden auth environment variables' do
node.set['openstack']['identity']['admin_tenant_name'] = 'admin-tenant-name-override'
node.set['openstack']['identity']['admin_user'] = 'admin-user-override'
node.set['openstack']['identity']['admin_project'] =
'admin-project-name-override'
node.set['openstack']['identity']['admin_user'] =
'identity_admin'
node.set['openstack']['identity']['admin_domain_id'] =
'admin-domain-override'
node.set['openstack']['endpoints']['public']['identity']['uri'] =
'https://public.identity:1234/v3'
[
/^export OS_USERNAME=admin-user-override$/,
/^export OS_TENANT_NAME=admin-tenant-name-override$/
/^export OS_USERNAME=identity_admin$/,
/^export OS_PROJECT_NAME=admin-project-name-override$/,
/^export OS_PASSWORD=identity_admin_pass$/,
%r{^export OS_AUTH_URL=https://public.identity:1234/v3$}
].each do |line|
expect(chef_run).to render_file(file.name).with_content(line)
end

View File

@ -1,748 +0,0 @@
# encoding: UTF-8
require_relative 'spec_helper'
describe 'openstack-identity::default' do
describe 'ubuntu' do
let(:runner) { ChefSpec::SoloRunner.new(UBUNTU_OPTS) }
let(:node) { runner.node }
let(:chef_run) { runner.converge(described_recipe) }
let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:cookbook_collection) { Chef::CookbookCollection.new([]) }
let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) }
# needed to create the provider class OpenstackIdentityRegister by chef magic
before { chef_run }
describe 'tenant_create' do
let(:resource) do
r = Chef::Resource::OpenstackIdentityRegister.new('tenant1',
run_context)
r.tenant_name('tenant1')
r.tenant_description('tenant1 Tenant')
r
end
let(:provider) do
Chef::Provider::OpenstackIdentityRegister.new(resource, run_context)
end
context 'when tenant does not already exist' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'tenant', 'name', 'tenant1')
allow(provider).to receive(:identity_command)
.with(resource, 'tenant-create',
'name' => 'tenant1',
'description' => 'tenant1 Tenant',
'enabled' => true)
.and_return(true)
end
it 'should create a tenant' do
provider.run_action(:create_tenant)
expect(resource).to be_updated
end
end
context 'when tenant does already exist' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'tenant', 'name', 'tenant1')
.and_return('1234567890ABCDEFGH')
end
it 'should not create a tenant' do
provider.run_action(:create_tenant)
expect(resource).to_not be_updated
end
end
context 'when keystone tenant command fails' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'tenant', 'name', 'tenant1')
.and_raise('Error!')
end
it 'should raise error' do
expect { provider.run_action(:create_tenant) }.to raise_error
end
end
end
describe 'service_create' do
let(:resource) do
r = Chef::Resource::OpenstackIdentityRegister.new('service1',
run_context)
r.service_type('compute')
r.service_name('service1')
r.service_description('service1 Service')
r
end
let(:provider) do
Chef::Provider::OpenstackIdentityRegister.new(resource, run_context)
end
context 'catalog.backend is sql' do
before do
node.set['openstack']['identity']['catalog']['backend'] = 'sql'
end
context 'when service does not already exist' do
it 'should create a service' do
allow(provider).to receive(:identity_uuid)
.with(resource, 'service', 'type', 'compute')
allow(provider).to receive(:identity_command)
.with(resource, 'service-create',
'type' => 'compute',
'name' => 'service1',
'description' => 'service1 Service')
.and_return(true)
provider.run_action(:create_service)
expect(resource).to be_updated
end
end
context 'when service does already exist' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'service', 'type', 'compute')
.and_return('1234567890ABCDEFGH')
allow(provider).to receive(:service_need_updated?)
.with(resource)
.and_return(false)
end
it 'should not create a service' do
provider.run_action(:create_service)
expect(resource).to_not be_updated
end
end
context 'when service does already exist and needs to be updated' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'service', 'type', 'compute')
.and_return('1234567890ABCDEFGH')
allow(provider).to receive(:service_need_updated?)
.with(resource)
.and_return(true)
allow(provider).to receive(:identity_command)
.with(resource, 'service-delete',
'' => '1234567890ABCDEFGH')
allow(provider).to receive(:identity_command)
.with(resource, 'service-create',
'type' => 'compute',
'name' => 'service1',
'description' => 'service1 Service')
end
it 'should update the service' do
provider.run_action(:create_service)
expect(resource).to be_updated
end
end
context '#service_need_updated?, when service exists and does not need to be updated' do
before do
output = ' | 1234567890ABCDEFGH | service1 | compute | service1 Service '
output_array = [{ 'id' => '1234567890ABCDEFGH', 'name' => 'service1', 'type' => 'compute', 'description' => 'service1 Service' }]
allow(provider).to receive(:identity_command)
.with(resource, 'service-list', {})
.and_return(output)
allow(provider).to receive(:prettytable_to_array)
.with(output)
.and_return(output_array)
end
it 'service should not be updated' do
expect(
provider.send(:service_need_updated?, resource)
).to eq(false)
end
end
context '#service_need_updated?, when service exists and needs to be updated' do
before do
output = ' | 1234567890ABCDEFGH | service11 | compute | service11 Service '
output_array = [{ 'id' => '1234567890ABCDEFGH', 'name' => 'service11', 'type' => 'compute', 'description' => 'service11 Service' }]
allow(provider).to receive(:identity_command)
.with(resource, 'service-list', {})
.and_return(output)
allow(provider).to receive(:prettytable_to_array)
.with(output)
.and_return(output_array)
end
it 'service should be updated' do
expect(
provider.send(:service_need_updated?, resource)
).to eq(true)
end
end
end
context 'when keystone service command fails' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'service', 'name', 'compute')
.and_raise('Error!')
end
it 'should raise error' do
expect { provider.run_action(:create_service) }.to raise_error
end
end
context 'catalog.backend is templated' do
before do
node.set['openstack']['identity']['catalog']['backend'] = 'templated'
end
it 'should not create a service if using a templated backend' do
provider.run_action(:create_service)
expect(resource).to_not be_updated
end
end
end
describe 'endpoint_create' do
let(:resource) do
r = Chef::Resource::OpenstackIdentityRegister.new('endpoint1',
run_context)
r.endpoint_region('Region One')
r.service_type('compute')
r.endpoint_publicurl('http://public')
r.endpoint_internalurl('http://internal')
r.endpoint_adminurl('http://admin')
r
end
let(:provider) do
Chef::Provider::OpenstackIdentityRegister.new(resource, run_context)
end
context 'catalog.backend is sql' do
before do
node.set['openstack']['identity']['catalog']['backend'] = 'sql'
end
context 'when endpoint does not already exist' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'service', 'type', 'compute')
.and_return('1234567890ABCDEFGH')
allow(provider).to receive(:identity_uuid)
.with(resource, 'endpoint', 'service_id', '1234567890ABCDEFGH')
allow(provider).to receive(:identity_command)
.with(resource, 'endpoint-create',
'region' => 'Region One',
'service_id' => '1234567890ABCDEFGH',
'publicurl' => 'http://public',
'internalurl' => 'http://internal',
'adminurl' => 'http://admin')
end
it 'should create an endpoint' do
provider.run_action(:create_endpoint)
expect(resource).to be_updated
end
end
context 'when endpoint does already exist' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'service', 'type', 'compute')
.and_return('1234567890ABCDEFGH')
allow(provider).to receive(:identity_uuid)
.with(resource, 'endpoint', 'service_id', '1234567890ABCDEFGH')
.and_return('0987654321HGFEDCBA')
allow(provider).to receive(:endpoint_need_updated?)
.with(resource, 'service_id', '1234567890ABCDEFGH')
.and_return(false)
end
it 'should not update an endpoint' do
provider.run_action(:create_endpoint)
expect(resource).not_to be_updated
end
end
context 'when endpoint does already exist and need to be updated' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'service', 'type', 'compute')
.and_return('1234567890ABCDEFGH')
allow(provider).to receive(:identity_uuid)
.with(resource, 'endpoint', 'service_id', '1234567890ABCDEFGH')
.and_return('0987654321HGFEDCBA')
allow(provider).to receive(:endpoint_need_updated?)
.with(resource, 'service_id', '1234567890ABCDEFGH')
.and_return(true)
allow(provider).to receive(:identity_command)
.with(resource, 'endpoint-delete',
'' => '0987654321HGFEDCBA')
allow(provider).to receive(:identity_command)
.with(resource, 'endpoint-create',
'region' => 'Region One',
'service_id' => '1234567890ABCDEFGH',
'publicurl' => 'http://public',
'internalurl' => 'http://internal',
'adminurl' => 'http://admin')
end
it 'should update an endpoint' do
provider.run_action(:create_endpoint)
expect(resource).to be_updated
end
end
context '#identity_uuid, when service id for Region One already exist' do
before do
output = ' | 000d9c447d124754a197fc612f9d63d7 | Region One | http://public | http://internal | http://admin | f9511a66e0484f3dbd1584065e8bab1c '
output_array = [{ 'id' => '000d9c447d124754a197fc612f9d63d7', 'region' => 'Region One', 'publicurl' => 'http://public', 'internalurl' => 'http://internal', 'adminurl' => 'http://admin', 'service_id' => 'f9511a66e0484f3dbd1584065e8bab1c' }]
allow(provider).to receive(:identity_command)
.with(resource, 'endpoint-list', {})
.and_return(output)
allow(provider).to receive(:prettytable_to_array)
.with(output)
.and_return(output_array)
end
it 'endpoint uuid should be returned' do
expect(
provider.send(:identity_uuid, resource, 'endpoint',
'service_id', 'f9511a66e0484f3dbd1584065e8bab1c')
).to eq('000d9c447d124754a197fc612f9d63d7')
end
end
context '#identity_uuid, when service id for Region Two does not exist' do
before do
output = ' | 000d9c447d124754a197fc612f9d63d7 | Region Two | http://public | http://internal | http://admin | f9511a66e0484f3dbd1584065e8bab1c '
output_array = [{ 'id' => '000d9c447d124754a197fc612f9d63d7', 'region' => 'Region Two', 'publicurl' => 'http://public', 'internalurl' => 'http://internal', 'adminurl' => 'http://admin', 'service_id' => 'f9511a66e0484f3dbd1584065e8bab1c' }]
allow(provider).to receive(:identity_command)
.with(resource, 'endpoint-list', {})
.and_return(output)
allow(provider).to receive(:prettytable_to_array)
.with(output)
.and_return(output_array)
end
it 'no endpoint uuid should be returned' do
expect(
provider.send(:identity_uuid, resource, 'endpoint',
'service_id', 'f9511a66e0484f3dbd1584065e8bab1c')
).to eq(nil)
end
end
context '#search_uuid' do
it 'required_hash only has key id' do
output_array = [{ 'id' => '000d9c447d124754a197fc612f9d63d7', 'region' => 'Region Two', 'publicurl' => 'http://public' }]
expect(
provider.send(:search_uuid, output_array, 'id',
'id' => '000d9c447d124754a197fc612f9d63d7')
).to eq('000d9c447d124754a197fc612f9d63d7')
expect(
provider.send(:search_uuid, output_array, 'id', 'id' => 'abc')
).to eq(nil)
end
it 'required_hash has key id and region' do
output_array = [{ 'id' => '000d9c447d124754a197fc612f9d63d7', 'region' => 'Region Two', 'publicurl' => 'http://public' }]
expect(
provider.send(:search_uuid, output_array, 'id',
'id' => '000d9c447d124754a197fc612f9d63d7',
'region' => 'Region Two')
).to eq('000d9c447d124754a197fc612f9d63d7')
expect(
provider.send(:search_uuid, output_array, 'id',
'id' => '000d9c447d124754a197fc612f9d63d7',
'region' => 'Region One')
).to eq(nil)
expect(
provider.send(:search_uuid, output_array, 'id',
'id' => '000d9c447d124754a197fc612f9d63d7',
'region' => 'Region Two', 'key' => 'value')
).to eq(nil)
end
end
context '#endpoint_need_updated?, when endpoint exist and not need to be updated' do
before do
output = ' | 000d9c447d124754a197fc612f9d63d7 | Region One | http://public | http://internal | http://admin | f9511a66e0484f3dbd1584065e8bab1c '
output_array = [{ 'id' => '000d9c447d124754a197fc612f9d63d7', 'region' => 'Region One', 'publicurl' => 'http://public', 'internalurl' => 'http://internal', 'adminurl' => 'http://admin', 'service_id' => 'f9511a66e0484f3dbd1584065e8bab1c' }]
allow(provider).to receive(:identity_command)
.with(resource, 'endpoint-list', {})
.and_return(output)
allow(provider).to receive(:prettytable_to_array)
.with(output)
.and_return(output_array)
end
it 'endpoint should not be updated' do
expect(
provider.send(:endpoint_need_updated?, resource,
'service_id', 'f9511a66e0484f3dbd1584065e8bab1c')
).to eq(false)
end
end
context '#endpoint_need_updated?, when endpoint exist and need to be updated' do
before do
output = ' | 000d9c447d124754a197fc612f9d63d7 | Region One | https://public | https://internal | https://admin | f9511a66e0484f3dbd1584065e8bab1c '
output_array = [{ 'id' => '000d9c447d124754a197fc612f9d63d7', 'region' => 'Region One', 'publicurl' => 'https://public', 'internalurl' => 'https://internal', 'adminurl' => 'https://admin', 'service_id' => 'f9511a66e0484f3dbd1584065e8bab1c' }]
allow(provider).to receive(:identity_command)
.with(resource, 'endpoint-list', {})
.and_return(output)
allow(provider).to receive(:prettytable_to_array)
.with(output)
.and_return(output_array)
end
it 'endpoint should be updated' do
expect(
provider.send(:endpoint_need_updated?, resource,
'service_id', 'f9511a66e0484f3dbd1584065e8bab1c')
).to eq(true)
end
end
end
context 'catalog.backend is templated' do
before do
node.set['openstack']['identity']['catalog']['backend'] = 'templated'
end
it 'should not create an endpoint' do
provider.run_action(:create_endpoint)
expect(resource).to_not be_updated
end
end
context 'when keystone endpoint command fails' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'service', 'type', 'compute')
.and_raise('Error!')
end
it 'should raise error' do
expect { provider.run_action(:create_endpoint) }.to raise_error
end
end
end
describe 'role create' do
let(:resource) do
r = Chef::Resource::OpenstackIdentityRegister.new('role1', run_context)
r.role_name('role1')
r
end
let(:provider) do
Chef::Provider::OpenstackIdentityRegister.new(resource, run_context)
end
context 'when role does not already exist' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'role', 'name', 'role1')
allow(provider).to receive(:identity_command)
.with(resource, 'role-create',
'name' => 'role1')
end
it 'should create a role' do
provider.run_action(:create_role)
expect(resource).to be_updated
end
end
context 'when role already exist' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'role', 'name', 'role1')
.and_return('1234567890ABCDEFGH')
end
it 'should not create a role' do
provider.run_action(:create_role)
expect(resource).to_not be_updated
end
end
context 'when keystone role command fails' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'role', 'name', 'role1')
.and_raise('Error!')
end
it 'should raise error' do
expect { provider.run_action(:create_role) }.to raise_error
end
end
end
describe 'user create' do
let(:resource) do
r = Chef::Resource::OpenstackIdentityRegister.new('user1', run_context)
r.user_name('user1')
r.tenant_name('tenant1')
r.user_pass('password')
r
end
let(:provider) do
Chef::Provider::OpenstackIdentityRegister.new(resource, run_context)
end
context 'when user does not already exist' do
before do
allow(provider).to receive(:identity_command)
.with(resource, 'user-list')
allow(provider).to receive(:identity_command)
.with(resource, 'user-create',
'name' => 'user1',
'tenant' => 'tenant1',
'pass' => 'password',
'enabled' => true)
allow(provider).to receive(:prettytable_to_array)
.and_return([])
end
it 'should create a user' do
provider.run_action(:create_user)
expect(resource).to be_updated
end
end
context 'when user already exist with same password' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'tenant', 'name', 'tenant1')
.and_return('1234567890ABCDEFGH')
allow(provider).to receive(:identity_command)
.with(resource, 'user-list')
allow(provider).to receive(:prettytable_to_array)
.and_return([{ 'name' => 'user1' }])
allow(provider).to receive(:identity_uuid)
.with(resource, 'user', 'name', 'user1')
.and_return('HGFEDCBA0987654321')
allow(provider).to receive(:identity_command)
.with(resource, 'token-get', {}, 'user')
end
it 'should not create a user' do
provider.run_action(:create_user)
expect(resource).to_not be_updated
end
end
context 'when user already exist and changed password' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'tenant', 'name', 'tenant1')
.and_return('1234567890ABCDEFGH')
allow(provider).to receive(:identity_command)
.with(resource, 'user-list')
allow(provider).to receive(:prettytable_to_array)
.and_return([{ 'name' => 'user1' }])
allow(provider).to receive(:identity_uuid)
.with(resource, 'user', 'name', 'user1')
.and_return('HGFEDCBA0987654321')
allow(provider).to receive(:identity_command)
.with(resource, 'token-get', {}, 'user')
.and_raise('Error!')
allow(provider).to receive(:identity_command)
.with(resource, 'user-password-update',
'pass' => 'password',
'' => 'user1')
end
it 'should update user password' do
provider.run_action(:create_user)
expect(resource).to be_updated
end
end
describe '#identity_command' do
it 'should handle false values and long descriptions' do
allow(provider).to receive(:shell_out)
.with(['keystone', '--insecure', 'user-create', '--enabled',
'false', '--description', 'more than one word'],
env: {
'OS_SERVICE_ENDPOINT' => nil,
'OS_SERVICE_TOKEN' => nil })
.and_return double('shell_out', exitstatus: 0, stdout: 'good')
expect(
provider.send(:identity_command, resource, 'user-create',
'enabled' => false,
'description' => 'more than one word')
).to eq('good')
end
end
context 'when keystone user command fails' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'tenant', 'name', 'tenant1')
.and_raise('Error!')
end
it 'should raise error' do
expect { provider.run_action(:create_user) }.to raise_error
end
end
end
describe 'role grant' do
let(:resource) do
r = Chef::Resource::OpenstackIdentityRegister.new('grant1', run_context)
r.user_name('user1')
r.tenant_name('tenant1')
r.role_name('role1')
r
end
let(:provider) do
Chef::Provider::OpenstackIdentityRegister.new(resource, run_context)
end
context 'when role has not already been granted' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'role', 'name', 'role1')
.and_return('ABC1234567890DEF')
allow(provider).to receive(:identity_uuid)
.with(resource, 'user-role', 'name', 'role1',
'tenant' => 'tenant1',
'user' => 'user1')
.and_return('ABCD1234567890EFGH')
allow(provider).to receive(:identity_command)
.with(resource, 'user-role-add',
'tenant' => 'tenant1',
'role-id' => 'ABC1234567890DEF',
'user' => 'user1')
end
it 'should grant a role' do
provider.run_action(:grant_role)
expect(resource).to be_updated
end
end
context 'when role has already been granted' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'role', 'name', 'role1')
.and_return('ABC1234567890DEF')
allow(provider).to receive(:identity_uuid)
.with(resource, 'user-role', 'name', 'role1',
'tenant' => 'tenant1',
'user' => 'user1')
.and_return('ABC1234567890DEF')
allow(provider).to receive(:identity_command)
.with(resource, 'user-role-add',
'tenant' => 'tenant1',
'role-id' => 'ABC1234567890DEF',
'user' => 'user1')
end
it 'should not grant a role' do
provider.run_action(:grant_role)
expect(resource).to_not be_updated
end
end
context 'when keystone grant command fails' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'tenant', 'name', 'tenant1')
.and_raise('Error!')
end
it 'should raise error' do
expect { provider.run_action(:grant_role) }.to raise_error
end
end
end
describe 'ec2_credentials create' do
let(:resource) do
r = Chef::Resource::OpenstackIdentityRegister.new('ec2', run_context)
r.user_name('user1')
r.tenant_name('tenant1')
r.admin_tenant_name('admintenant1')
r.admin_user('adminuser1')
r.admin_pass('password')
r.identity_endpoint('http://admin')
r
end
let(:provider) do
Chef::Provider::OpenstackIdentityRegister.new(resource, run_context)
end
context 'when ec2 creds have not already been created' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'tenant', 'name', 'tenant1')
.and_return('1234567890ABCDEFGH')
allow(provider).to receive(:identity_uuid)
.with(resource, 'user', 'name', 'user1',
'tenant-id' => '1234567890ABCDEFGH')
.and_return('HGFEDCBA0987654321')
allow(provider).to receive(:identity_uuid)
.with(resource, 'ec2-credentials', 'tenant', 'tenant1',
{ 'user-id' => 'HGFEDCBA0987654321' }, 'access')
allow(provider).to receive(:identity_command)
.with(resource, 'ec2-credentials-create',
{ 'user-id' => 'HGFEDCBA0987654321',
'tenant-id' => '1234567890ABCDEFGH' },
'admin')
allow(provider).to receive(:prettytable_to_array)
.and_return([{ 'access' => 'access', 'secret' => 'secret' }])
end
it 'should grant ec2 creds' do
provider.run_action(:create_ec2_credentials)
expect(resource).to be_updated
end
end
context 'when ec2 creds have not already been created' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'tenant', 'name', 'tenant1')
.and_return('1234567890ABCDEFGH')
allow(provider).to receive(:identity_uuid)
.with(resource, 'user', 'name', 'user1',
'tenant-id' => '1234567890ABCDEFGH')
.and_return('HGFEDCBA0987654321')
allow(provider).to receive(:identity_uuid)
.with(resource, 'ec2-credentials', 'tenant', 'tenant1',
{ 'user-id' => 'HGFEDCBA0987654321' }, 'access')
.and_return('ABC1234567890DEF')
end
it 'should grant ec2 creds if they already exist' do
provider.run_action(:create_ec2_credentials)
expect(resource).to_not be_updated
end
end
context 'when keystone user command fails' do
before do
allow(provider).to receive(:identity_uuid)
.with(resource, 'tenant', 'name', 'tenant1')
.and_raise('Error!')
end
it 'should raise error' do
expect { provider.run_action(:create_ec2_credentials) }.to raise_error
end
end
end
end
end

View File

@ -8,282 +8,143 @@ describe 'openstack-identity::registration' do
let(:node) { runner.node }
let(:runner) { ChefSpec::SoloRunner.new(UBUNTU_OPTS) }
let(:chef_run) { runner.converge(described_recipe) }
let(:node_add_user) do
node.set_unless['openstack']['identity']['users'] = {
'user1' => {
'default_tenant' => 'default_tenant1',
'password' => 'secret1',
'roles' => {
'role1' => ['role_tenant1'],
'role2' => ['default_tenant1']
}
}
}
end
include_context 'identity_stubs'
describe 'tenant registration' do
context 'default tenants' do
['admin'].each do |tenant_name|
it "registers the #{tenant_name} tenant" do
expect(chef_run).to create_tenant_openstack_identity_register(
"Register '#{tenant_name}' Tenant"
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
tenant_name: tenant_name,
tenant_description: "#{tenant_name} Tenant"
)
end
connection_params = {
openstack_auth_url: 'http://127.0.0.1:35357/v3/auth/tokens',
openstack_username: 'admin',
openstack_api_key: 'admin',
openstack_project_name: 'admin',
openstack_domain_name: 'default'
}
service_name = 'keystone'
service_user = 'admin'
region = 'RegionOne'
project_name = 'admin'
role_name = 'admin'
password = 'admin'
domain_name = 'default'
admin_url = 'http://127.0.0.1:35357/v3'
public_url = 'http://127.0.0.1:5000/v3'
internal_url = 'http://127.0.0.1:5000/v3'
describe 'keystone bootstrap' do
context 'default values' do
it 'bootstrap with keystone-manage' do
expect(chef_run).to run_execute('bootstrap_keystone'
).with(command: "keystone-manage bootstrap \\
--bootstrap-password #{password} \\
--bootstrap-username #{service_user} \\
--bootstrap-project-name #{project_name} \\
--bootstrap-role-name #{role_name} \\
--bootstrap-service-name #{service_name} \\
--bootstrap-region-id #{region} \\
--bootstrap-admin-url #{admin_url} \\
--bootstrap-public-url #{public_url} \\
--bootstrap-internal-url #{internal_url}")
end
end
context 'configured tenants from users attribute' do
before { node_add_user }
['default_tenant1', 'role_tenant1'].each do |tenant_name|
it "registers the #{tenant_name} tenant" do
expect(chef_run).to create_tenant_openstack_identity_register(
"Register '#{tenant_name}' Tenant"
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
tenant_name: tenant_name,
tenant_description: "#{tenant_name} Tenant"
)
end
end
end
end
describe 'role registration' do
context 'default roles' do
%w(admin service).each do |role_name|
it "registers the #{role_name} role" do
expect(chef_run).to create_role_openstack_identity_register(
"Register '#{role_name}' Role"
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
role_name: role_name
)
end
end
end
context 'configured roles derived from users attribute' do
before { node_add_user }
['role1', 'role2'].each do |role_name|
it "registers the #{role_name} role" do
expect(chef_run).to create_role_openstack_identity_register(
"Register '#{role_name}' Role"
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
role_name: role_name
)
end
end
end
end
describe 'user registration' do
context 'default users' do
user_admin = [
'admin', 'admin',
['admin', 'service']
]
[user_admin].each do |user, tenant, roles|
context "#{user} user" do
it "registers the #{user} user" do
expect(chef_run).to create_user_openstack_identity_register(
"Register '#{user}' User"
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
user_name: user,
user_pass: 'admin',
tenant_name: tenant
)
end
roles.each do |role|
it "grants '#{role}' role to '#{user}' user in 'admin' tenant" do
expect(chef_run).to grant_role_openstack_identity_register(
"Grant '#{role}' Role to '#{user}' User in 'admin' Tenant"
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
user_name: user,
role_name: role,
tenant_name: 'admin',
action: [:grant_role]
)
end
end
it 'registers the admin user for ec2' do
expect(chef_run).to create_ec2_credentials_openstack_identity_register(
"Create EC2 credentials for 'admin' user"
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
user_name: user,
tenant_name: tenant,
admin_tenant_name: 'admin',
admin_user: 'admin',
admin_pass: 'admin'
)
end
end
end
end
context 'configured user' do
before { node_add_user }
it 'registers the user1 user' do
expect(chef_run).to create_user_openstack_identity_register(
"Register 'user1' User"
it "registers #{domain_name} domain" do
expect(chef_run).to create_openstack_domain(
domain_name
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
user_name: 'user1',
user_pass: 'secret1',
tenant_name: 'default_tenant1'
connection_params: connection_params
)
end
it "grants 'role1' role to 'user1' user in 'role_tenant1' tenant" do
expect(chef_run).to grant_role_openstack_identity_register(
"Grant 'role1' Role to 'user1' User in 'role_tenant1' Tenant"
it "grants #{service_user} user to #{domain_name} domain" do
expect(chef_run).to grant_domain_openstack_user(
service_user
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
user_name: 'user1',
role_name: 'role1',
tenant_name: 'role_tenant1'
domain_name: domain_name,
role_name: role_name,
connection_params: connection_params
)
end
it 'registers the user1 user for ec2' do
expect(chef_run).to create_ec2_credentials_openstack_identity_register(
"Create EC2 credentials for 'user1' user"
it 'create service role' do
expect(chef_run).to create_openstack_role(
'service'
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
user_name: 'user1',
tenant_name: 'default_tenant1',
admin_tenant_name: 'admin',
admin_user: 'admin',
admin_pass: 'admin'
connection_params: connection_params
)
end
it 'create service role' do
expect(chef_run).to create_openstack_role(
'_member_'
).with(
connection_params: connection_params
)
end
end
end
describe 'service registration' do
context 'with templated catalog backend' do
context 'all different values' do
connection_params_other = {
openstack_auth_url: 'https://admin.identity:1234/v3/auth/tokens',
openstack_username: 'identity_admin',
openstack_api_key: 'identity_admin_pass',
openstack_project_name: 'admin_project',
openstack_domain_name: 'identity_domain'
}
before do
node.set['openstack']['identity']['catalog']['backend'] = 'templated'
node.set['openstack']['endpoints']['admin']['identity']['uri'] =
'https://admin.identity:1234/v3'
node.set['openstack']['endpoints']['internal']['identity']['uri'] =
'https://internal.identity:5678/v3'
node.set['openstack']['endpoints']['public']['identity']['uri'] =
'https://public.identity:9753/v3'
node.set['openstack']['region'] = 'otherRegion'
node.set['openstack']['identity']['admin_project'] = 'admin_project'
node.set['openstack']['identity']['admin_user'] = 'identity_admin'
node.set['openstack']['identity']['admin_role'] = 'identity_role'
node.set['openstack']['identity']['admin_domain_name'] =
'identity_domain'
end
it 'does not register identity service' do
expect(chef_run).to_not create_service_openstack_identity_register(
'Register Identity Service'
)
it 'bootstrap with keystone-manage' do
expect(chef_run).to run_execute('bootstrap_keystone'
).with(command: "keystone-manage bootstrap \\
--bootstrap-password identity_admin_pass \\
--bootstrap-username identity_admin \\
--bootstrap-project-name admin_project \\
--bootstrap-role-name identity_role \\
--bootstrap-service-name #{service_name} \\
--bootstrap-region-id otherRegion \\
--bootstrap-admin-url https://admin.identity:1234/v3 \\
--bootstrap-public-url https://public.identity:9753/v3 \\
--bootstrap-internal-url https://internal.identity:5678/v3")
end
end
context 'with sql catalog backend' do
before do
node.set['openstack']['identity']['catalog']['backend'] = 'sql'
end
it 'registers identity service' do
expect(chef_run).to create_service_openstack_identity_register(
'Register Identity Service'
it 'registers identity_domain domain' do
expect(chef_run).to create_openstack_domain(
'identity_domain'
).with(
service_name: 'keystone',
service_type: 'identity',
service_description: 'Keystone Identity Service'
connection_params: connection_params_other
)
end
end
end
describe 'endpoint registration' do
context 'with templated catalog backend' do
before do
node.set['openstack']['identity']['catalog']['backend'] = 'templated'
end
it 'does not register identity endpoint' do
expect(chef_run).to_not create_endpoint_openstack_identity_register(
'Register Identity Endpoint'
)
end
end
context 'with sql catalog backend' do
before do
node.set['openstack']['identity']['catalog']['backend'] = 'sql'
end
it 'registers identity endpoints' do
expect(chef_run).to create_endpoint_openstack_identity_register(
'Register Identity Endpoint'
it 'grants identity_admin user to identity_domain domain' do
expect(chef_run).to grant_domain_openstack_user(
'identity_admin'
).with(
auth_uri: 'http://127.0.0.1:35357/v2.0',
bootstrap_token: 'bootstrap-token',
service_type: 'identity',
endpoint_region: 'RegionOne',
endpoint_adminurl: 'http://127.0.0.1:35357/v2.0',
endpoint_internalurl: 'http://127.0.0.1:5000/v2.0',
endpoint_publicurl: 'http://127.0.0.1:5000/v2.0'
domain_name: 'identity_domain',
role_name: 'identity_role',
connection_params: connection_params_other
)
end
it 'overrides identity endpoint region' do
node.set['openstack']['identity']['region'] = 'identityRegion'
expect(chef_run).to create_endpoint_openstack_identity_register(
'Register Identity Endpoint'
).with(endpoint_region: 'identityRegion')
end
it 'overrides identity endpoints' do
node.set['openstack']['endpoints']['admin']['identity']['host'] = '127.0.0.2'
node.set['openstack']['endpoints']['admin']['identity']['port'] = '5002'
node.set['openstack']['endpoints']['admin']['identity']['path'] = '/v2.2'
node.set['openstack']['endpoints']['internal']['identity']['host'] = '127.0.0.3'
node.set['openstack']['endpoints']['internal']['identity']['port'] = '5003'
node.set['openstack']['endpoints']['internal']['identity']['path'] = '/v2.3'
node.set['openstack']['endpoints']['public']['identity']['host'] = '127.0.0.4'
node.set['openstack']['endpoints']['public']['identity']['port'] = '5004'
node.set['openstack']['endpoints']['public']['identity']['path'] = '/v2.4'
expect(chef_run).to create_endpoint_openstack_identity_register(
'Register Identity Endpoint'
it 'create service role' do
expect(chef_run).to create_openstack_role(
'service'
).with(
endpoint_adminurl: 'http://127.0.0.2:5002/v2.2',
endpoint_internalurl: 'http://127.0.0.3:5003/v2.3',
endpoint_publicurl: 'http://127.0.0.4:5004/v2.4'
connection_params: connection_params_other
)
end
it 'register endpoint with all different URLs' do
public_url = 'https://public.host:789/public_path'
internal_url = 'http://internal.host:456/internal_path'
admin_url = 'https://admin.host:123/admin_path'
node.set['openstack']['endpoints']['public']['identity']['uri'] = public_url
node.set['openstack']['endpoints']['internal']['identity']['uri'] = internal_url
node.set['openstack']['endpoints']['admin']['identity']['uri'] = admin_url
expect(chef_run).to create_endpoint_openstack_identity_register(
'Register Identity Endpoint'
it 'create service role' do
expect(chef_run).to create_openstack_role(
'_member_'
).with(
endpoint_adminurl: admin_url,
endpoint_internalurl: internal_url,
endpoint_publicurl: public_url
connection_params: connection_params_other
)
end
end

View File

@ -135,11 +135,6 @@ describe 'openstack-identity::server-apache' do
end
describe '[DEFAULT] section' do
it 'has admin token' do
r = line_regexp('admin_token = bootstrap-token')
expect(chef_run).to render_config_file(path).with_section_content('DEFAULT', r)
end
describe 'syslog configuration' do
log_file = %r{^log_dir = /var/log/keystone$}
log_conf = %r{^log_config_append = /\w+}

View File

@ -12,7 +12,7 @@ REDHAT_OPTS = {
}.freeze
UBUNTU_OPTS = {
platform: 'ubuntu',
version: '14.04',
version: '16.04',
log_level: LOG_LEVEL
}.freeze
@ -47,8 +47,8 @@ shared_context 'identity_stubs' do
.with('user', 'user1')
.and_return('secret1')
allow_any_instance_of(Chef::Recipe).to receive(:get_password)
.with('token', 'openstack_identity_bootstrap_token')
.and_return('bootstrap-token')
.with('user', 'identity_admin')
.and_return('identity_admin_pass')
stub_command('/usr/sbin/apache2 -t')
allow_any_instance_of(Chef::Recipe).to receive(:search_for)
.with('os-identity').and_return(

View File

@ -2,8 +2,11 @@
# COMMON OPENSTACK ENVS
export OS_USERNAME=<%= @user %>
export OS_USER_DOMAIN_NAME=<%= @user_domain_name %>
export OS_PASSWORD=<%= @password %>
export OS_TENANT_NAME=<%= @tenant %>
export OS_PROJECT_NAME=<%= @project %>
export OS_PROJECT_DOMAIN_NAME=<%= @project_domain_name %>
export OS_IDENTITY_API_VERSION=<%= @api_version %>
export OS_AUTH_URL=<%= @identity_endpoint %>
export OS_REGION_NAME=<%= node['openstack']['region'] %>