memcached (openstack) is no longer in use
[mirror/dsa-puppet.git] / 3rdparty / modules / keystone / lib / puppet / provider / keystone_user_role / openstack.rb
index 5b9a1b5..e670a67 100644 (file)
@@ -1,4 +1,5 @@
 require 'puppet/provider/keystone'
+require 'puppet/provider/keystone/util'
 
 Puppet::Type.type(:keystone_user_role).provide(
   :openstack,
@@ -7,26 +8,33 @@ Puppet::Type.type(:keystone_user_role).provide(
 
   desc "Provider to manage keystone role assignments to users."
 
+  @credentials = Puppet::Provider::Openstack::CredentialsV3.new
+
+  def initialize(value={})
+    super(value)
+    @property_flush = {}
+  end
+
   def create
-    properties = []
-    properties << '--project' << get_project
-    properties << '--user' << get_user
     if resource[:roles]
       resource[:roles].each do |role|
-        request('role', 'add', role, resource[:auth], properties)
+        self.class.request('role', 'add', [role] + properties)
+      end
+    end
+  end
+
+  def destroy
+    if @property_hash[:roles]
+      @property_hash[:roles].each do |role|
+        self.class.request('role', 'remove', [role] + properties)
       end
     end
+    @property_hash[:ensure] = :absent
   end
 
   def exists?
-    # If we just ran self.instances, no need to make the request again
-    # instance() will find it cached in @user_role_hash
-    if self.class.user_role_hash
-      return ! instance(resource[:name]).empty?
-    # If we don't have the hash ready, we don't need to rebuild the
-    # whole thing just to check on one particular user/role
-    else
-      roles = request('user role', 'list', nil, resource[:auth], ['--project', get_project, get_user])
+    if self.class.user_role_hash.nil? || self.class.user_role_hash.empty?
+      roles = self.class.request('role', 'list', properties)
       # Since requesting every combination of users, roles, and
       # projects is so expensive, construct the property hash here
       # instead of in self.instances so it can be used in the role
@@ -40,23 +48,10 @@ Puppet::Type.type(:keystone_user_role).provide(
           role[:name]
         end
       end
-      return @property_hash[:ensure] == :present
-    end
-  end
-
-  def destroy
-    properties = []
-    properties << '--project' << get_project
-    properties << '--user' << get_user
-    if @property_hash[:roles]
-      @property_hash[:roles].each do |role|
-        request('role', 'remove', role, resource[:auth], properties)
-      end
     end
-    @property_hash[:ensure] = :absent
+    return @property_hash[:ensure] == :present
   end
 
-
   def roles
     @property_hash[:roles]
   end
@@ -66,17 +61,14 @@ Puppet::Type.type(:keystone_user_role).provide(
     # determine the roles to be added and removed
     remove = current_roles - Array(value)
     add    = Array(value) - current_roles
-    user = get_user
-    project = get_project
     add.each do |role_name|
-      request('role', 'add', role_name, resource[:auth], ['--project', project, '--user', user])
+      self.class.request('role', 'add', [role_name] + properties)
     end
     remove.each do |role_name|
-      request('role', 'remove', role_name, resource[:auth], ['--project', project, '--user', user])
+      self.class.request('role', 'remove', [role_name] + properties)
     end
   end
 
-
   def self.instances
     instances = build_user_role_hash
     instances.collect do |title, roles|
@@ -88,12 +80,21 @@ Puppet::Type.type(:keystone_user_role).provide(
     end
   end
 
-  def instance(name)
-    self.class.user_role_hash.select { |role_name, roles| role_name == name } || {}
-  end
-
   private
 
+  def properties
+    properties = []
+    if get_project_id
+      properties << '--project' << get_project_id
+    elsif get_domain
+      properties << '--domain' << get_domain
+    else
+      error("No project or domain specified for role")
+    end
+    properties << '--user' << get_user_id
+    properties
+  end
+
   def get_user
     resource[:name].rpartition('@').first
   end
@@ -102,58 +103,104 @@ Puppet::Type.type(:keystone_user_role).provide(
     resource[:name].rpartition('@').last
   end
 
-  # We split get_projects into class and instance methods
-  # so that the appropriate request method gets called
-  def get_projects
-    request('project', 'list', nil, resource[:auth]).collect do |project|
-      project[:name]
+  # if the role is for a domain, it will be specified as
+  # user@::domain - the "project" part will be empty
+  def get_domain
+    # use defined because @domain may be nil
+    return @domain if defined?(@domain)
+    projname, domname = Util.split_domain(get_project)
+    if projname.nil?
+      @domain = domname # no project specified, so must be a domain
+    else
+      @domain = nil # not a domain specific role
     end
+    @domain
   end
 
-  def self.get_projects
-    request('project', 'list', nil, nil).collect do |project|
-      project[:name]
-    end
+  def get_user_id
+    @user_id ||= Puppet::Resource.indirection.find("Keystone_user/#{get_user}")[:id]
   end
 
-  def get_users(project)
-    request('user', 'list', nil, resource[:auth], ['--project', project]).collect do |user|
-      user[:name]
+  def get_project_id
+    # use defined because @project_id may be nil
+    return @project_id if defined?(@project_id)
+    projname, domname = Util.split_domain(get_project)
+    if projname.nil?
+      @project_id = nil
+    else
+      @project_id ||= Puppet::Resource.indirection.find("Keystone_tenant/#{get_project}")[:id]
     end
+    @project_id
   end
 
-  def self.get_users(project)
-    request('user', 'list', nil, nil, ['--project', project]).collect do |user|
-      user[:name]
+  def self.get_projects
+    request('project', 'list', '--long').collect do |project|
+      {
+        :id        => project[:id],
+        :name      => project[:name],
+        :domain_id => project[:domain_id],
+        :domain    => domain_name_from_id(project[:domain_id])
+      }
     end
   end
 
-  # Class methods for caching user_role_hash so both class and instance
-  # methods can access the value
-  def self.set_user_role_hash(user_role_hash)
-    @user_role_hash = user_role_hash
+  def self.get_users(project_id=nil, domain_id=nil)
+    properties = ['--long']
+    if project_id
+      properties << '--project' << project_id
+    elsif domain_id
+      properties << '--domain' << domain_id
+    end
+    request('user', 'list', properties).collect do |user|
+      {
+        :id        => user[:id],
+        :name      => user[:name],
+        # note - column is "Domain" but it is really the domain id
+        :domain_id => user[:domain],
+        :domain    => domain_name_from_id(user[:domain])
+      }
+    end
   end
 
   def self.user_role_hash
     @user_role_hash
   end
 
+  def self.set_user_role_hash(user_role_hash)
+    @user_role_hash = user_role_hash
+  end
+
   def self.build_user_role_hash
-    hash = user_role_hash || {}
+    # The new hash will have the property that if the
+    # given key does not exist, create it with an empty
+    # array as the value for the hash key
+    hash = @user_role_hash || Hash.new{|h,k| h[k] = []}
     return hash unless hash.empty?
-    projects = get_projects
-    projects.each do |project|
-      users = get_users(project)
-      users.each do |user|
-        user_roles = request('user role', 'list', nil, nil, ['--project', project, user])
-        hash["#{user}@#{project}"] = []
-        user_roles.each do |role|
-          hash["#{user}@#{project}"] << role[:name]
+    # Need a mapping of project id to names.
+    project_hash = {}
+    Puppet::Type.type(:keystone_tenant).provider(:openstack).instances.each do |project|
+      project_hash[project.id] = project.name
+    end
+    # Need a mapping of user id to names.
+    user_hash = {}
+    Puppet::Type.type(:keystone_user).provider(:openstack).instances.each do |user|
+      user_hash[user.id] = user.name
+    end
+    # need a mapping of role id to name
+    role_hash = {}
+    request('role', 'list').each {|role| role_hash[role[:id]] = role[:name]}
+    # now, get all role assignments
+    request('role assignment', 'list').each do |assignment|
+      if assignment[:user]
+        if assignment[:project]
+          hash["#{user_hash[assignment[:user]]}@#{project_hash[assignment[:project]]}"] << role_hash[assignment[:role]]
+        else
+          domainname = domain_id_to_name(assignment[:domain])
+          hash["#{user_hash[assignment[:user]]}@::#{domainname}"] << role_hash[assignment[:role]]
         end
       end
     end
     set_user_role_hash(hash)
     hash
   end
-
 end