]> git.donarmstrong.com Git - dsa-puppet.git/blob - 3rdparty/modules/keystone/lib/puppet/provider/keystone_user/openstack.rb
try with modules from master
[dsa-puppet.git] / 3rdparty / modules / keystone / lib / puppet / provider / keystone_user / openstack.rb
1 require 'puppet/provider/keystone'
2
3 Puppet::Type.type(:keystone_user).provide(
4   :openstack,
5   :parent => Puppet::Provider::Keystone
6 ) do
7
8   desc "Provider to manage keystone users."
9
10   @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
11
12   def initialize(value={})
13     super(value)
14     @property_flush = {}
15   end
16
17   def create
18     properties = [resource[:name]]
19     if resource[:enabled] == :true
20       properties << '--enable'
21     elsif resource[:enabled] == :false
22       properties << '--disable'
23     end
24     if resource[:password]
25       properties << '--password' << resource[:password]
26     end
27     if resource[:tenant]
28       properties << '--project' << resource[:tenant]
29     end
30     if resource[:email]
31       properties << '--email' << resource[:email]
32     end
33     self.class.request('user', 'create', properties)
34     @property_hash[:ensure] = :present
35   end
36
37   def destroy
38     self.class.request('user', 'delete', @property_hash[:id])
39     @property_hash.clear
40   end
41
42   def flush
43     options = []
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
51       unless options.empty?
52         options << @property_hash[:id]
53         self.class.request('user', 'set', options)
54       end
55       @property_flush.clear
56     end
57   end
58
59   def exists?
60     @property_hash[:ensure] == :present
61   end
62
63   # Types properties
64   def enabled
65     bool_to_sym(@property_hash[:enabled])
66   end
67
68   def enabled=(value)
69     @property_flush[:enabled] = value
70   end
71
72   def email
73     @property_hash[:email]
74   end
75
76   def email=(value)
77     @property_flush[:email] = value
78   end
79
80   def id
81     @property_hash[:id]
82   end
83
84   def password
85     res = nil
86     return res if resource[:password] == nil
87     if resource[:enabled] == :false || resource[:replace_password] == :false
88       # Unchanged password
89       res = resource[:password]
90     else
91       # Password validation
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]
97       begin
98         token = Puppet::Provider::Openstack.request('token', 'issue', ['--format', 'value'], credentials)
99       rescue Puppet::Error::OpenstackUnauthorizedError
100         # password is invalid
101       else
102         res = resource[:password] unless token.empty?
103       end
104     end
105     return res
106   end
107
108   def password=(value)
109     @property_flush[:password] = value
110   end
111
112   def replace_password
113     @property_hash[:replace_password]
114   end
115
116   def replace_password=(value)
117     @property_flush[:replace_password] = value
118   end
119
120   def tenant
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]
127     else
128       return tenant_name
129     end
130     if tenant_name.nil? or tenant_name.empty?
131       return nil # nothing found, nothing given
132     end
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])
137     if roles.empty?
138       return nil
139     else
140       return tenant_name
141     end
142   end
143
144   def tenant=(value)
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
149       else
150         raise e
151       end
152       # note: read-write ldap will silently fail, not raise an exception
153     else
154     @property_hash[:tenant] = self.class.set_project(value, resource[:name])
155   end
156
157   def self.instances
158     list = request('user', 'list', '--long')
159     list.collect do |user|
160       new(
161         :name        => user[:name],
162         :ensure      => :present,
163         :enabled     => user[:enabled].downcase.chomp == 'true' ? true : false,
164         :password    => user[:password],
165         :project     => user[:project],
166         :email       => user[:email],
167         :id          => user[:id]
168       )
169     end
170   end
171
172   def self.prefetch(resources)
173     users = instances
174     resources.keys.each do |name|
175        if provider = users.find{ |user| user.name == name }
176         resources[name].provider = provider
177       end
178     end
179   end
180
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])
186     unless roles.empty?
187       return # if already set, just skip
188     end
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_"
196     begin
197       request('role', 'show', [default_role])
198     rescue
199       debug("Keystone role #{default_role} does not exist - creating")
200       request('role', 'create', [default_role])
201     end
202     request('role', 'add', [default_role, '--project', newproject, '--user', name])
203   end
204 end