Blame 0001-Implement-Keystone-domain-creation.patch

50534ad
From 3a38aa6eda5a57299f20bf0cabb10442e1a2cc89 Mon Sep 17 00:00:00 2001
50534ad
From: Martin Magr <mmagr@redhat.com>
50534ad
Date: Thu, 5 Jun 2014 14:24:47 +0200
50534ad
Subject: [PATCH] Implement Keystone domain creation
50534ad
50534ad
Keystone domain has to be created for Heat. This patch implements this
50534ad
via helper script [1] since we don't have support for Keystone v3 API
50534ad
in puppet-keystone yet. This implementation should be refactored as soon
50534ad
as we will have v3 API available in puppet-keystone. For more info
50534ad
please check [2].
50534ad
50534ad
[1] https://github.com/openstack/heat/blob/master/bin/heat-keystone-setup-domain
50534ad
[2] https://bugzilla.redhat.com/show_bug.cgi?id=1076172
50534ad
---
50534ad
 lib/puppet/provider/heat_domain_id_setter/ruby.rb | 183 ++++++++++++++++++++++
50534ad
 lib/puppet/type/heat_config.rb                    |   4 +
50534ad
 lib/puppet/type/heat_domain_id_setter.rb          |  31 ++++
50534ad
 manifests/keystone/domain.pp                      |  73 +++++++++
50534ad
 4 files changed, 291 insertions(+)
50534ad
 create mode 100644 lib/puppet/provider/heat_domain_id_setter/ruby.rb
50534ad
 create mode 100644 lib/puppet/type/heat_domain_id_setter.rb
50534ad
 create mode 100644 manifests/keystone/domain.pp
50534ad
50534ad
diff --git a/lib/puppet/provider/heat_domain_id_setter/ruby.rb b/lib/puppet/provider/heat_domain_id_setter/ruby.rb
50534ad
new file mode 100644
50534ad
index 0000000..8862fe5
50534ad
--- /dev/null
50534ad
+++ b/lib/puppet/provider/heat_domain_id_setter/ruby.rb
50534ad
@@ -0,0 +1,183 @@
50534ad
+## NB: This must work with Ruby 1.8!
50534ad
+
50534ad
+# This provider permits the stack_user_domain parameter in heat.conf
50534ad
+# to be set by providing a domain_name to the Puppet module and
50534ad
+# using the Keystone REST API to translate the name into the corresponding
50534ad
+# UUID.
50534ad
+#
50534ad
+# This requires that tenant names be unique.  If there are multiple matches
50534ad
+# for a given tenant name, this provider will raise an exception.
50534ad
+
50534ad
+require 'rubygems'
50534ad
+require 'net/http'
50534ad
+require 'json'
50534ad
+
50534ad
+class KeystoneError < Puppet::Error
50534ad
+end
50534ad
+
50534ad
+class KeystoneConnectionError < KeystoneError
50534ad
+end
50534ad
+
50534ad
+class KeystoneAPIError < KeystoneError
50534ad
+end
50534ad
+
50534ad
+# Provides common request handling semantics to the other methods in
50534ad
+# this module.
50534ad
+#
50534ad
+# +req+::
50534ad
+#   An HTTPRequest object
50534ad
+# +url+::
50534ad
+#   A parsed URL (returned from URI.parse)
50534ad
+def handle_request(req, url)
50534ad
+    begin
50534ad
+        res = Net::HTTP.start(url.host, url.port) {|http|
50534ad
+            http.request(req)
50534ad
+        }
50534ad
+
50534ad
+        if res.code != '200'
50534ad
+            raise KeystoneAPIError, "Received error response from Keystone server at #{url}: #{res.message}"
50534ad
+        end
50534ad
+    rescue Errno::ECONNREFUSED => detail
50534ad
+        raise KeystoneConnectionError, "Failed to connect to Keystone server at #{url}: #{detail}"
50534ad
+    rescue SocketError => detail
50534ad
+        raise KeystoneConnectionError, "Failed to connect to Keystone server at #{url}: #{detail}"
50534ad
+    end
50534ad
+
50534ad
+    res
50534ad
+end
50534ad
+
50534ad
+# Authenticates to a Keystone server and obtains an authentication token.
50534ad
+# It returns a 2-element +[token, authinfo]+, where +token+ is a token
50534ad
+# suitable for passing to openstack apis in the +X-Auth-Token+ header, and
50534ad
+# +authinfo+ is the complete response from Keystone, including the service
50534ad
+# catalog (if available).
50534ad
+#
50534ad
+# +auth_url+::
50534ad
+#   Keystone endpoint URL.  This function assumes API version
50534ad
+#   2.0 and an administrative endpoint, so this will typically look like
50534ad
+#   +http://somehost:35357/v2.0+.
50534ad
+#
50534ad
+# +username+::
50534ad
+#   Username for authentication.
50534ad
+#
50534ad
+# +password+::
50534ad
+#   Password for authentication
50534ad
+#
50534ad
+# +tenantID+::
50534ad
+#   Tenant UUID
50534ad
+#
50534ad
+# +tenantName+::
50534ad
+#   Tenant name
50534ad
+#
50534ad
+def keystone_v2_authenticate(auth_url,
50534ad
+                             username,
50534ad
+                             password,
50534ad
+                             tenantId=nil,
50534ad
+                             tenantName=nil)
50534ad
+
50534ad
+    post_args = {
50534ad
+        'auth' => {
50534ad
+            'passwordCredentials' => {
50534ad
+                'username' => username,
50534ad
+                'password' => password
50534ad
+            },
50534ad
+        }}
50534ad
+
50534ad
+    if tenantId
50534ad
+        post_args['auth']['tenantId'] = tenantId
50534ad
+    end
50534ad
+
50534ad
+    if tenantName
50534ad
+        post_args['auth']['tenantName'] = tenantName
50534ad
+    end
50534ad
+
50534ad
+    url = URI.parse("#{auth_url}/tokens")
50534ad
+    req = Net::HTTP::Post.new url.path
50534ad
+    req['content-type'] = 'application/json'
50534ad
+    req.body = post_args.to_json
50534ad
+
50534ad
+    res = handle_request(req, url)
50534ad
+    data = JSON.parse res.body
50534ad
+    return data['access']['token']['id'], data
50534ad
+end
50534ad
+
50534ad
+# Queries a Keystone server to a list of all tenants.
50534ad
+#
50534ad
+# +auth_url+::
50534ad
+#   Keystone endpoint.  See the notes for +auth_url+ in
50534ad
+#   +keystone_v2_authenticate+.
50534ad
+#
50534ad
+# +token+::
50534ad
+#   A Keystone token that will be passed in requests as the value of the
50534ad
+#   +X-Auth-Token+ header.
50534ad
+#
50534ad
+def keystone_v3_domains(auth_url,
50534ad
+                        token)
50534ad
+
50534ad
+    auth_url.sub!('v2.0', 'v3')
50534ad
+    url = URI.parse("#{auth_url}/domains")
50534ad
+    req = Net::HTTP::Get.new url.path
50534ad
+    req['content-type'] = 'application/json'
50534ad
+    req['x-auth-token'] = token
50534ad
+
50534ad
+    res = handle_request(req, url)
50534ad
+    data = JSON.parse res.body
50534ad
+    data['domains']
50534ad
+end
50534ad
+
50534ad
+Puppet::Type.type(:heat_domain_id_setter).provide(:ruby) do
50534ad
+    def authenticate
50534ad
+        token, authinfo = keystone_v2_authenticate(
50534ad
+            @resource[:auth_url],
50534ad
+            @resource[:auth_username],
50534ad
+            @resource[:auth_password],
50534ad
+            nil,
50534ad
+            @resource[:auth_tenant_name])
50534ad
+
50534ad
+        return token
50534ad
+    end
50534ad
+
50534ad
+    def find_domain_by_name(token)
50534ad
+        domains = keystone_v3_domains(
50534ad
+            @resource[:auth_url],
50534ad
+            token)
50534ad
+        domains.select{|domain| domain['name'] == @resource[:domain_name]}
50534ad
+    end
50534ad
+
50534ad
+    def exists?
50534ad
+        false
50534ad
+    end
50534ad
+
50534ad
+    def create
50534ad
+        config
50534ad
+    end
50534ad
+
50534ad
+    # This looks for the domain specified by the 'domain_name' parameter to
50534ad
+    # the resource and returns the corresponding UUID if there is a single
50534ad
+    # match.
50534ad
+    #
50534ad
+    # Raises a KeystoneAPIError if:
50534ad
+    #
50534ad
+    # - There are multiple matches, or
50534ad
+    # - There are zero matches
50534ad
+    def get_domain_id
50534ad
+        token = authenticate
50534ad
+        domains = find_domain_by_name(token)
50534ad
+
50534ad
+        if domains.length == 1
50534ad
+            return domains[0]['id']
50534ad
+        elsif domains.length > 1
50534ad
+            name = domains[0]['name']
50534ad
+            raise KeystoneAPIError, 'Found multiple matches for domain name "#{name}"'
50534ad
+        else
50534ad
+            raise KeystoneAPIError, 'Unable to find matching tenant'
50534ad
+        end
50534ad
+    end
50534ad
+
50534ad
+    def config
50534ad
+        Puppet::Type.type(:heat_config).new(
50534ad
+            {:name => 'DEFAULT/stack_user_domain', :value => "#{get_domain_id}"}
50534ad
+        ).create
50534ad
+    end
50534ad
+
50534ad
+end
50534ad
diff --git a/lib/puppet/type/heat_config.rb b/lib/puppet/type/heat_config.rb
50534ad
index 3534e22..131cfad 100644
50534ad
--- a/lib/puppet/type/heat_config.rb
50534ad
+++ b/lib/puppet/type/heat_config.rb
50534ad
@@ -16,4 +16,8 @@ Puppet::Type.newtype(:heat_config) do
50534ad
     end
50534ad
   end
50534ad
 
50534ad
+  def create
50534ad
+    provider.create
50534ad
+  end
50534ad
+
50534ad
 end
50534ad
diff --git a/lib/puppet/type/heat_domain_id_setter.rb b/lib/puppet/type/heat_domain_id_setter.rb
50534ad
new file mode 100644
50534ad
index 0000000..d6e1eee
50534ad
--- /dev/null
50534ad
+++ b/lib/puppet/type/heat_domain_id_setter.rb
50534ad
@@ -0,0 +1,31 @@
50534ad
+Puppet::Type.newtype(:heat_domain_id_setter) do
50534ad
+
50534ad
+    ensurable
50534ad
+
50534ad
+    newparam(:name, :namevar => true) do
50534ad
+        desc 'The name of the setting to update'
50534ad
+    end
50534ad
+
50534ad
+    newparam(:domain_name) do
50534ad
+        desc 'The heat domain name'
50534ad
+    end
50534ad
+
50534ad
+    newparam(:auth_url) do
50534ad
+        desc 'The Keystone endpoint URL'
50534ad
+        defaultto 'http://localhost:35357/v2.0'
50534ad
+    end
50534ad
+
50534ad
+    newparam(:auth_username) do
50534ad
+        desc 'Username with which to authenticate'
50534ad
+        defaultto 'admin'
50534ad
+    end
50534ad
+
50534ad
+    newparam(:auth_password) do
50534ad
+        desc 'Password with which to authenticate'
50534ad
+    end
50534ad
+
50534ad
+    newparam(:auth_tenant_name) do
50534ad
+        desc 'Tenant name with which to authenticate'
50534ad
+        defaultto 'admin'
50534ad
+    end
50534ad
+end
50534ad
diff --git a/manifests/keystone/domain.pp b/manifests/keystone/domain.pp
50534ad
new file mode 100644
50534ad
index 0000000..0ef4b6a
50534ad
--- /dev/null
50534ad
+++ b/manifests/keystone/domain.pp
50534ad
@@ -0,0 +1,73 @@
50534ad
+# == Class: heat::keystone::domain
50534ad
+#
50534ad
+# Configures heat domain in Keystone.
50534ad
+#
50534ad
+# Note: Implementation is done by heat-keystone-setup-domain script temporarily
50534ad
+#       because currently puppet-keystone does not support v3 API
50534ad
+#
50534ad
+# === Parameters
50534ad
+#
50534ad
+# [*auth_url*]
50534ad
+#   Keystone auth url
50534ad
+#
50534ad
+# [*keystone_admin*]
50534ad
+#   Keystone admin user
50534ad
+#
50534ad
+# [*keystone_password*]
50534ad
+#   Keystone admin password
50534ad
+#
50534ad
+# [*keystone_tenant*]
50534ad
+#   Keystone admin tenant name
50534ad
+#
50534ad
+# [*domain_name*]
50534ad
+#   Heat domain name. Defaults to 'heat'.
50534ad
+#
50534ad
+# [*domain_admin*]
50534ad
+#   Keystone domain admin user which will be created. Defaults to 'heat_admin'.
50534ad
+#
50534ad
+# [*domain_password*]
50534ad
+#   Keystone domain admin user password. Defaults to 'changeme'.
50534ad
+#
50534ad
+class heat::keystone::domain (
50534ad
+  $auth_url          = undef,
50534ad
+  $keystone_admin    = undef,
50534ad
+  $keystone_password = undef,
50534ad
+  $keystone_tenant   = undef,
50534ad
+  $domain_name       = 'heat',
50534ad
+  $domain_admin      = 'heat_admin',
50534ad
+  $domain_password   = 'changeme',
50534ad
+) {
50534ad
+
50534ad
+  include heat::params
50534ad
+
50534ad
+  $cmd_evn = [
50534ad
+    "OS_USERNAME=${keystone_admin}",
50534ad
+    "OS_PASSWORD=${keystone_password}",
50534ad
+    "OS_AUTH_URL=${auth_url}",
50534ad
+    "HEAT_DOMAIN=${domain_name}",
50534ad
+    "HEAT_DOMAIN_ADMIN=${domain_admin}",
50534ad
+    "HEAT_DOMAIN_PASSWORD=${domain_password}"
50534ad
+  ]
50534ad
+  exec { 'heat_domain_create':
50534ad
+    path        => '/usr/bin',
50534ad
+    command     => 'heat-keystone-setup-domain &>/dev/null',
50534ad
+    environment => $cmd_evn,
50534ad
+    require     => Package['heat-common'],
50534ad
+  }
50534ad
+
50534ad
+  heat_domain_id_setter { 'heat_domain_id':
50534ad
+    ensure           => present,
50534ad
+    domain_name      => $domain_name,
50534ad
+    auth_url         => $auth_url,
50534ad
+    auth_username    => $keystone_admin,
50534ad
+    auth_password    => $keystone_password,
50534ad
+    auth_tenant_name => $keystone_tenant,
50534ad
+    require          => Exec['heat_domain_create'],
50534ad
+  }
50534ad
+
50534ad
+  heat_config {
50534ad
+    'DEFAULT/stack_domain_admin': value => $domain_admin;
50534ad
+    'DEFAULT/stack_domain_admin_password': value => $domain_password;
50534ad
+  }
50534ad
+
50534ad
+}
50534ad
-- 
50534ad
1.9.3