Cookbook : identity

Description

This cookbook installs the OpenStack Identity Service Keystone as part of the OpenStack reference deployment Chef for OpenStack. The http://github.com/mattray/chef-openstack-repo contains documentation for using this cookbook in the context of a full OpenStack deployment. Keystone is installed from packages, creating the default user, tenant, and roles. It also registers the identity service and identity endpoint.

http://keystone.openstack.org/

Requirements

Chef 0.10.0 or higher required (for Chef environment use)

Cookbooks

The following cookbooks are dependencies:

Usage

server

Installs and Configures Keystone Service

"run_list": [
    "recipe[openstack-identity::server]"
]

Resources/Providers

These resources provide an abstraction layer for interacting with the keystone server's API, allowing for other nodes to register any required users, tenants, roles, services, or endpoints.

register

Register users, tenants, roles, services and endpoints with Keystone

Actions

General Attributes

:create_tenant Specific Attributes

:create_user Specific Attributes

:create_role Specific Attributes

:grant_role Specific Attributes

:create_service Specific Attributes

:create_endpoint Specific Attributes

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

credentials

Create EC2 credentials for a given user in the specified tenant

Actions

General Attributes

:create_ec2 Specific Attributes

Examples

openstack_identity_credentials "Create EC2 credentials for 'admin' user" do
  auth_host "192.168.1.10"
  auth_port "35357"
  auth_protocol "http"
  api_ver "/v2.0"
  auth_token "123456789876"
  user_name "admin"
  tenant_name "openstack"
end

Attributes

Testing

This cookbook uses bundler, berkshelf, and strainer to isolate dependencies and run tests.

Tests are defined in Strainerfile.

To run tests:

$ bundle install # install gem dependencies
$ bundle exec berks install # install cookbook dependencies
$ bundle exec strainer test # run tests

License and Author

Author:: Justin Shepherd (justin.shepherd@rackspace.com) Author:: Jason Cannavale (jason.cannavale@rackspace.com) Author:: Ron Pedde (ron.pedde@rackspace.com) Author:: Joseph Breu (joseph.breu@rackspace.com) Author:: William Kelly (william.kelly@rackspace.com) Author:: Darren Birkett (darren.birkett@rackspace.co.uk) Author:: Evan Callicoat (evan.callicoat@rackspace.com) Author:: Matt Ray (matt@opscode.com) Author:: Jay Pipes (jaypipes@att.com) Author:: John Dewey (jdewey@att.com) Author:: Sean Gallagher (sean.gallagher@att.com) Author:: Ionut Artarisi (iartarisi@suse.cz)

Copyright 2012, Rackspace US, Inc. Copyright 2012-2013, Opscode, Inc. Copyright 2012-2013, AT&T Services, Inc. Copyright 2013, SUSE Linux GmbH

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.

Cookbook Documentation

Recipes Summary

Lightweight Resources

identity_register

Providers

identity_register

Recipe Details

identity::server

Installs and Configures Keystone Service



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'recipes/server.rb', line 1

#
# Cookbook Name:: openstack-identity
# Recipe:: server
#
# Copyright 2012, Rackspace US, Inc.
# Copyright 2012-2013, Opscode, 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.
#

require "uri"

class ::Chef::Recipe
  include ::Openstack
end

if node["openstack"]["identity"]["syslog"]["use"]
  include_recipe "openstack-common::logging"
end

platform_options = node["openstack"]["identity"]["platform"]

##### NOTE #####
# https://bugs.launchpad.net/ubuntu/+source/keystone/+bug/931236
################

db_type = node['openstack']['db']['identity']['db_type']
platform_options["#{db_type}_python_packages"].each do |pkg|
  package pkg do
    action :install
  end
end

platform_options["memcache_python_packages"].each do |pkg|
  package pkg do
    action :install
  end
end

platform_options["keystone_packages"].each do |pkg|
  package pkg do
    options platform_options["package_options"]

    action :upgrade
  end
end

execute "Keystone: sleep" do
  command "sleep 10s"

  action :nothing
end

service "keystone" do
  service_name platform_options["keystone_service"]
  supports :status => true, :restart => true

  action [ :enable ]

  notifies :run, "execute[Keystone: sleep]", :immediately
end

directory "/etc/keystone" do
  owner node["openstack"]["identity"]["user"]
  group node["openstack"]["identity"]["group"]
  mode  00700
end

directory node["openstack"]["identity"]["signing"]["basedir"] do
  owner node["openstack"]["identity"]["user"]
  group node["openstack"]["identity"]["group"]
  mode  00700

  only_if { node["openstack"]["auth"]["strategy"] == "pki" }
end

file "/var/lib/keystone/keystone.db" do
  action :delete
end

execute "keystone-manage pki_setup" do
  user node["openstack"]["identity"]["user"]

  only_if { node["openstack"]["auth"]["strategy"] == "pki" }
  not_if { ::FileTest.exists? node["openstack"]["identity"]["signing"]["keyfile"] }
end

identity_admin_endpoint = endpoint "identity-admin"
identity_endpoint = endpoint "identity-api"
compute_endpoint = endpoint "compute-api"
ec2_endpoint = endpoint "compute-ec2-api"
image_endpoint = endpoint "image-api"
network_endpoint = endpoint "network-api"
volume_endpoint = endpoint "volume-api"

db_user = node["openstack"]["identity"]["db"]["username"]
db_pass = db_password "keystone"
sql_connection = db_uri("identity", db_user, db_pass)

bootstrap_token = secret "secrets", "openstack_identity_bootstrap_token"

ip_address = address_for node["openstack"]["identity"]["bind_interface"]

# If the search role is set, we search for memcache
# servers via a Chef search. If not, we look at the
# memcache.servers attribute.
memcache_servers = memcached_servers.join ","  # from openstack-common lib

uris = {
  'identity-admin' => identity_admin_endpoint.to_s.gsub('%25','%'),
  'identity' => identity_endpoint.to_s.gsub('%25','%'),
  'image' => image_endpoint.to_s.gsub('%25','%'),
  'compute' => compute_endpoint.to_s.gsub('%25','%'),
  'ec2' => ec2_endpoint.to_s.gsub('%25','%'),
  'network' => network_endpoint.to_s.gsub('%25','%'),
  'volume' => volume_endpoint.to_s.gsub('%25','%')
}

# These configuration endpoints must not have the path (v2.0, etc)
# added to them, as these values are used in returning the version
# listing information from the root / endpoint.
ie = identity_endpoint
public_endpoint = "#{ie.scheme}://#{ie.host}:#{ie.port}/"
ae = identity_admin_endpoint
admin_endpoint = "#{ae.scheme}://#{ae.host}:#{ae.port}/"

template "/etc/keystone/keystone.conf" do
  source "keystone.conf.erb"
  owner node["openstack"]["identity"]["user"]
  group node["openstack"]["identity"]["group"]
  mode   00644
  variables(
    :sql_connection => sql_connection,
    :ip_address => ip_address,
    "bootstrap_token" => bootstrap_token,
    "memcache_servers" => memcache_servers,
    "uris" => uris,
    "public_endpoint" => public_endpoint,
    "admin_endpoint" => admin_endpoint
  )

  notifies :restart, "service[keystone]", :immediately
end

template "/etc/keystone/default_catalog.templates" do
  source "default_catalog.templates.erb"
  owner node["openstack"]["identity"]["user"]
  group node["openstack"]["identity"]["group"]
  mode   00644
  variables(
    "uris" => uris
  )

  notifies :restart, "service[keystone]", :immediately
  only_if { node["openstack"]["identity"]["catalog"]["backend"] == "templated" }
end

# sync db after keystone.conf is generated
execute "keystone-manage db_sync" do
  only_if { node["openstack"]["identity"]["db"]["migrate"] }
end

identity::default



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'recipes/default.rb', line 1

#
# Cookbook Name:: openstack-identity
# Recipe:: default
#
# Copyright 2012-2013, AT&T Services, 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.
#

identity::registration

Adds user, tenant, role and endpoint records to Keystone



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'recipes/registration.rb', line 1

#
# Cookbook Name:: openstack-identity
# Recipe:: setup
#
# Copyright 2012, Rackspace US, Inc.
# Copyright 2012-2013, Opscode, 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.
#

require "uri"

class ::Chef::Recipe
  include ::Openstack
end

identity_admin_endpoint = endpoint "identity-admin"
identity_endpoint = endpoint "identity-api"

admin_tenant_name = node["openstack"]["identity"]["admin_tenant_name"]
admin_user = node["openstack"]["identity"]["admin_user"]
admin_pass = user_password node["openstack"]["identity"]["admin_user"]
auth_uri = ::URI.decode identity_admin_endpoint.to_s

bootstrap_token = secret "secrets", "openstack_identity_bootstrap_token"

# We need to bootstrap the keystone admin user so that calls
# to keystone_register will succeed, since those provider calls
# use the admin tenant/user/pass to get an admin token.
bash "bootstrap-keystone-admin" do
  # A shortcut bootstrap command was added to python-keystoneclient
  # in early Grizzly timeframe... but we need to do all the commands
  # here manually since the python-keystoneclient package included
  # in CloudArchive (for now) doesn't have it...
  insecure = node["openstack"]["auth"]["validate_certs"] ? "" : " --insecure"
  base_ks_cmd = "keystone#{insecure} --endpoint=#{auth_uri} --token=#{bootstrap_token}"
  code <<-EOF
set -x
function get_id () {
    echo `"$@" | grep ' id ' | awk '{print $4}'`
}
#{base_ks_cmd} tenant-list | grep #{admin_tenant_name}
if [[ $? -eq 1 ]]; then
  ADMIN_TENANT=$(get_id #{base_ks_cmd} tenant-create --name=#{admin_tenant_name})
else
  ADMIN_TENANT=$(#{base_ks_cmd} tenant-list | grep #{admin_tenant_name} | awk '{print $2}')
fi
#{base_ks_cmd} role-list | grep admin
if [[ $? -eq 1 ]]; then
  ADMIN_ROLE=$(get_id #{base_ks_cmd} role-create --name=admin)
else
  ADMIN_ROLE=$(#{base_ks_cmd} role-list | grep admin | awk '{print $2}')
fi
#{base_ks_cmd} user-list | grep #{admin_user}
if [[ $? -eq 1 ]]; then
  ADMIN_USER=$(get_id #{base_ks_cmd} user-create --name=#{admin_user} --pass="#{admin_pass}" --email=#{admin_user}@example.com)
else
  ADMIN_USER=$(#{base_ks_cmd} user-list | grep #{admin_user} | awk '{print $2}')
fi
#{base_ks_cmd} user-role-list --user-id=$ADMIN_USER --tenant-id=$ADMIN_TENANT | grep admin
if [[ $? -eq 1 ]]; then
  #{base_ks_cmd} user-role-add --user-id $ADMIN_USER --role-id $ADMIN_ROLE --tenant-id $ADMIN_TENANT
fi
exit 0
EOF
end

node["openstack"]["identity"]["tenants"].each do |tenant_name|
  ## Add openstack tenant ##
  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"
    tenant_enabled true # Not required as this is the default

    action :create_tenant
  end
end

node["openstack"]["identity"]["roles"].each do |role_key|
  openstack_identity_register "Register '#{role_key.to_s}' Role" do
    auth_uri auth_uri
    bootstrap_token bootstrap_token
    role_name role_key

    action :create_role
  end
end

node["openstack"]["identity"]["users"].each do |username, |
  openstack_identity_register "Register '#{username}' User" do
    auth_uri auth_uri
    bootstrap_token bootstrap_token
    user_name username
    user_pass ["password"]
    tenant_name ["default_tenant"]
    user_enabled true # Not required as this is the default

    action :create_user
  end

  ["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

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
end

node.set["openstack"]["identity"]["adminURL"] = identity_admin_endpoint.to_s
node.set["openstack"]["identity"]["internalURL"] = identity_endpoint.to_s
node.set["openstack"]["identity"]["publicURL"] = identity_endpoint.to_s

Chef::Log.info "Keystone AdminURL: #{identity_admin_endpoint.to_s}"
Chef::Log.info "Keystone InternalURL: #{identity_endpoint.to_s}"
Chef::Log.info "Keystone PublicURL: #{identity_endpoint.to_s}"

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"]["adminURL"]
  endpoint_publicurl node["openstack"]["identity"]["publicURL"]

  action :create_endpoint
end

node["openstack"]["identity"]["users"].each do |username, |
  openstack_identity_register "Create EC2 credentials for '#{username}' user" do
    auth_uri auth_uri
    bootstrap_token bootstrap_token
    user_name username
    tenant_name ["default_tenant"]

    action :create_ec2_credentials
  end
end

Action Details

create_service  (Chef::Provider::IdentityRegister)



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'providers/register.rb', line 65

action :create_service do
  if node["openstack"]["identity"]["catalog"]["backend"] == "templated"
    Chef::Log.info("Skipping service creation - templated catalog backend in use.")
    new_resource.updated_by_last_action(false)
  else
    begin
      service_uuid = identity_uuid new_resource, "service", "type", new_resource.service_type

      unless service_uuid
        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)
      else
        Chef::Log.info("Service Type '#{new_resource.service_type}' already exists.. Not creating.")
        Chef::Log.info("Service UUID: #{service_uuid}")
        new_resource.updated_by_last_action(false)
      end
    rescue Exception => e
      Chef::Log.error("Unable to create service '#{new_resource.service_name}'")
      Chef::Log.error("Error was: #{e.message}")
      new_resource.updated_by_last_action(false)
    end
  end
end

create_endpoint  (Chef::Provider::IdentityRegister)



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'providers/register.rb', line 93

action :create_endpoint do
  if node["openstack"]["identity"]["catalog"]["backend"] == "templated"
    Chef::Log.info("Skipping endpoint creation - templated catalog backend in use.")
    new_resource.updated_by_last_action(false)
  else
    begin
      service_uuid = identity_uuid new_resource, "service", "type", new_resource.service_type
      unless service_uuid
        Chef::Log.error("Unable to find service type '#{new_resource.service_type}'")
        new_resource.updated_by_last_action(false)
        next
      end

      endpoint_uuid = identity_uuid new_resource, "endpoint", "service_id", service_uuid
      unless endpoint_uuid
        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)
      else
        Chef::Log.info("Endpoint already exists for Service Type '#{new_resource.service_type}' already exists.. Not creating.")
        new_resource.updated_by_last_action(false)
      end
    rescue Exception => e
      Chef::Log.error("Unable to create endpoint for service type '#{new_resource.service_type}'")
      Chef::Log.error("Error was: #{e.message}")
      new_resource.updated_by_last_action(false)
    end
  end
end

create_tenant  (Chef::Provider::IdentityRegister)



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'providers/register.rb', line 128

action :create_tenant do
  begin
    tenant_uuid = identity_uuid new_resource, "tenant", "name", new_resource.tenant_name

    unless tenant_uuid
      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)
    else
      Chef::Log.info("Tenant '#{new_resource.tenant_name}' already exists.. Not creating.")
      Chef::Log.info("Tenant UUID: #{tenant_uuid}") if tenant_uuid
      new_resource.updated_by_last_action(false)
    end
  rescue Exception => e
    Chef::Log.error("Unable to create tenant '#{new_resource.tenant_name}'")
    Chef::Log.error("Error was: #{e.message}")
    new_resource.updated_by_last_action(false)
  end
end

create_role  (Chef::Provider::IdentityRegister)



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'providers/register.rb', line 151

action :create_role do
  begin
    role_uuid = identity_uuid new_resource, "role", "name", new_resource.role_name

    unless role_uuid
      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)
    else
      Chef::Log.info("Role '#{new_resource.role_name}' already exists.. Not creating.")
      Chef::Log.info("Role UUID: #{role_uuid}")
      new_resource.updated_by_last_action(false)
    end
  rescue Exception => e
    Chef::Log.error("Unable to create role '#{new_resource.role_name}'")
    Chef::Log.error("Error was: #{e.message}")
    new_resource.updated_by_last_action(false)
  end
end

create_user  (Chef::Provider::IdentityRegister)



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'providers/register.rb', line 172

action :create_user do
  begin
    tenant_uuid = identity_uuid new_resource, "tenant", "name", new_resource.tenant_name
    unless tenant_uuid
      Chef::Log.error("Unable to find tenant '#{new_resource.tenant_name}'")
      new_resource.updated_by_last_action(false)
      next
    end

    output = identity_command new_resource, "user-list", {'tenant-id' => tenant_uuid}
    users = prettytable_to_array output
    user_found = false
    users.each { |user|
      if user['name'] == new_resource.user_name
        user_found = true
      end
    }

    if user_found
      Chef::Log.info("User '#{new_resource.user_name}' already exists for tenant '#{new_resource.tenant_name}'")
      new_resource.updated_by_last_action(false)
      next
    end

    identity_command new_resource, "user-create",
      { 'name' => new_resource.user_name,
        'tenant-id' => tenant_uuid,
        '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 Exception => e
    Chef::Log.error("Unable to create user '#{new_resource.user_name}' for tenant '#{new_resource.tenant_name}'")
    Chef::Log.error("Error was: #{e.message}")
    new_resource.updated_by_last_action(false)
  end
end

grant_role  (Chef::Provider::IdentityRegister)



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'providers/register.rb', line 210

action :grant_role do
  begin
    tenant_uuid = identity_uuid new_resource, "tenant", "name", new_resource.tenant_name
    unless tenant_uuid
      Chef::Log.error("Unable to find tenant '#{new_resource.tenant_name}'")
      new_resource.updated_by_last_action(false)
      next
    end

    user_uuid = identity_uuid new_resource, "user", "name", new_resource.user_name
    unless tenant_uuid
      Chef::Log.error("Unable to find user '#{new_resource.user_name}'")
      new_resource.updated_by_last_action(false)
      next
    end

    role_uuid = identity_uuid new_resource, "role", "name", new_resource.role_name
    unless tenant_uuid
      Chef::Log.error("Unable to find role '#{new_resource.role_name}'")
      new_resource.updated_by_last_action(false)
      next
    end

    assigned_role_uuid = identity_uuid new_resource, "user-role", "name", new_resource.role_name,
      { 'tenant-id' => tenant_uuid,
        'user-id' => user_uuid }
    unless role_uuid == assigned_role_uuid
      identity_command new_resource, "user-role-add",
        { 'tenant-id' => tenant_uuid,
          'role-id' => role_uuid,
          'user-id' => user_uuid }
      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)
    else
      Chef::Log.info("Role '#{new_resource.role_name}' already granted to User '#{new_resource.user_name}' in Tenant '#{new_resource.tenant_name}'")
      new_resource.updated_by_last_action(false)
    end
  rescue Exception => e
    Chef::Log.error("Unable to grant role '#{new_resource.role_name}' to user '#{new_resource.user_name}'")
    Chef::Log.error("Error was: #{e.message}")
    new_resource.updated_by_last_action(false)
  end
end

create_ec2_credentials  (Chef::Provider::IdentityRegister)



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'providers/register.rb', line 254

action :create_ec2_credentials do
  begin
    tenant_uuid = identity_uuid new_resource, "tenant", "name", new_resource.tenant_name
    unless tenant_uuid
      Chef::Log.error("Unable to find tenant '#{new_resource.tenant_name}'")
      new_resource.updated_by_last_action(false)
      next
    end

    user_uuid = identity_uuid new_resource, "user", "name", new_resource.user_name, {'tenant-id' => tenant_uuid}
    unless tenant_uuid
      Chef::Log.error("Unable to find user '#{new_resource.user_name}'")
      new_resource.updated_by_last_action(false)
      next
    end

    # 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"
    unless access
     output = identity_command new_resource, "ec2-credentials-create",
        { 'user-id' => user_uuid,
          'tenant-id' => tenant_uuid }
      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
        Chef::Log.error("Got bad data when creating ec2 credentials for #{new_resource.user_name}")
        Chef::Log.error("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
    else
      Chef::Log.info("EC2 credentials already exist for '#{new_resource.user_name}' in tenant '#{new_resource.tenant_name}'")
      new_resource.updated_by_last_action(false)
    end
  rescue Exception => e
    Chef::Log.error("Unable to create EC2 Credentials for User '#{new_resource.user_name}' in Tenant '#{new_resource.tenant_name}'")
    Chef::Log.error("Error was: #{e.message}")
    new_resource.updated_by_last_action(false)
  end
end