1 require 'puppet/provider/keystone'
3 Puppet::Type.type(:keystone_user).provide(
5 :parent => Puppet::Provider::Keystone
8 desc "Provider to manage keystone users."
10 @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
12 def initialize(value={})
18 properties = [resource[:name]]
19 if resource[:enabled] == :true
20 properties << '--enable'
21 elsif resource[:enabled] == :false
22 properties << '--disable'
24 if resource[:password]
25 properties << '--password' << resource[:password]
28 properties << '--project' << resource[:tenant]
31 properties << '--email' << resource[:email]
33 self.class.request('user', 'create', properties)
34 @property_hash[:ensure] = :present
38 self.class.request('user', 'delete', @property_hash[:id])
44 if @property_flush && !@property_flush.empty?
45 options << '--enable' if @property_flush[:enabled] == :true
46 options << '--disable' if @property_flush[:enabled] == :false
47 # There is a --description flag for the set command, but it does not work if the value is empty
48 options << '--password' << resource[:password] if @property_flush[:password]
49 options << '--email' << resource[:email] if @property_flush[:email]
50 # project handled in tenant= separately
52 options << @property_hash[:id]
53 self.class.request('user', 'set', options)
60 @property_hash[:ensure] == :present
65 bool_to_sym(@property_hash[:enabled])
69 @property_flush[:enabled] = value
73 @property_hash[:email]
77 @property_flush[:email] = value
86 return res if resource[:password] == nil
87 if resource[:enabled] == :false || resource[:replace_password] == :false
89 res = resource[:password]
92 credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
93 credentials.auth_url = self.class.get_endpoint
94 credentials.password = resource[:password]
95 credentials.project_name = resource[:tenant]
96 credentials.username = resource[:name]
98 token = Puppet::Provider::Openstack.request('token', 'issue', ['--format', 'value'], credentials)
99 rescue Puppet::Error::OpenstackUnauthorizedError
100 # password is invalid
102 res = resource[:password] unless token.empty?
109 @property_flush[:password] = value
113 @property_hash[:replace_password]
116 def replace_password=(value)
117 @property_flush[:replace_password] = value
121 return resource[:tenant] if sym_to_bool(resource[:ignore_default_tenant])
122 # use the one returned from instances
123 tenant_name = @property_hash[:project]
124 if tenant_name.nil? or tenant_name.empty?
125 # if none (i.e. ldap backend) use the given one
126 tenant_name = resource[:tenant]
130 if tenant_name.nil? or tenant_name.empty?
131 return nil # nothing found, nothing given
133 # If the user list command doesn't report the project, it might still be there
134 # We don't need to know exactly what it is, we just need to know whether it's
135 # the one we're trying to set.
136 roles = self.class.request('user role', 'list', [resource[:name], '--project', tenant_name])
145 self.class.request('user', 'set', [resource[:name], '--project', value])
146 rescue Puppet::ExecutionFailure => e
147 if e.message =~ /You are not authorized to perform the requested action: LDAP user update/
148 # read-only LDAP identity backend - just fall through
152 # note: read-write ldap will silently fail, not raise an exception
154 @property_hash[:tenant] = self.class.set_project(value, resource[:name])
158 list = request('user', 'list', '--long')
159 list.collect do |user|
161 :name => user[:name],
163 :enabled => user[:enabled].downcase.chomp == 'true' ? true : false,
164 :password => user[:password],
165 :project => user[:project],
166 :email => user[:email],
172 def self.prefetch(resources)
174 resources.keys.each do |name|
175 if provider = users.find{ |user| user.name == name }
176 resources[name].provider = provider
181 def self.set_project(newproject, name)
182 # some backends do not store the project/tenant in the user object, so we have to
183 # to modify the project/tenant instead
184 # First, see if the project actually needs to change
185 roles = request('user role', 'list', [name, '--project', newproject])
187 return # if already set, just skip
189 # Currently the only way to assign a user to a tenant not using user-create
190 # is to use user-role-add - this means we also need a role - there is usual
191 # a default role called _member_ which can be used for this purpose. What
192 # usually happens in a puppet module is that immediately after calling
193 # keystone_user, the module will then assign a role to that user. It is
194 # ok for a user to have the _member_ role and another role.
195 default_role = "_member_"
197 request('role', 'show', [default_role])
199 debug("Keystone role #{default_role} does not exist - creating")
200 request('role', 'create', [default_role])
202 request('role', 'add', [default_role, '--project', newproject, '--user', name])