]> git.donarmstrong.com Git - dsa-puppet.git/blobdiff - 3rdparty/modules/glance/lib/puppet/provider/glance.rb
try again, with puppetforge modules, correctly included now
[dsa-puppet.git] / 3rdparty / modules / glance / lib / puppet / provider / glance.rb
diff --git a/3rdparty/modules/glance/lib/puppet/provider/glance.rb b/3rdparty/modules/glance/lib/puppet/provider/glance.rb
new file mode 100644 (file)
index 0000000..ec4e1c0
--- /dev/null
@@ -0,0 +1,188 @@
+# Since there's only one glance type for now,
+# this probably could have all gone in the provider file.
+# But maybe this is good long-term.
+require 'puppet/util/inifile'
+class Puppet::Provider::Glance < Puppet::Provider
+
+  def self.glance_credentials
+    @glance_credentials ||= get_glance_credentials
+  end
+
+  def self.get_glance_credentials
+    if glance_file and glance_file['keystone_authtoken'] and
+      glance_file['keystone_authtoken']['auth_host'] and
+      glance_file['keystone_authtoken']['auth_port'] and
+      glance_file['keystone_authtoken']['auth_protocol'] and
+      glance_file['keystone_authtoken']['admin_tenant_name'] and
+      glance_file['keystone_authtoken']['admin_user'] and
+      glance_file['keystone_authtoken']['admin_password'] and
+      glance_file['DEFAULT']['os_region_name']
+
+        g = {}
+        g['auth_host'] = glance_file['keystone_authtoken']['auth_host'].strip
+        g['auth_port'] = glance_file['keystone_authtoken']['auth_port'].strip
+        g['auth_protocol'] = glance_file['keystone_authtoken']['auth_protocol'].strip
+        g['admin_tenant_name'] = glance_file['keystone_authtoken']['admin_tenant_name'].strip
+        g['admin_user'] = glance_file['keystone_authtoken']['admin_user'].strip
+        g['admin_password'] = glance_file['keystone_authtoken']['admin_password'].strip
+        g['os_region_name'] = glance_file['DEFAULT']['os_region_name'].strip
+
+        # auth_admin_prefix not required to be set.
+        g['auth_admin_prefix'] = (glance_file['keystone_authtoken']['auth_admin_prefix'] || '').strip
+
+        return g
+    else
+      raise(Puppet::Error, 'File: /etc/glance/glance-api.conf does not contain all required sections.')
+    end
+  end
+
+  def glance_credentials
+    self.class.glance_credentials
+  end
+
+  def self.auth_endpoint
+    @auth_endpoint ||= get_auth_endpoint
+  end
+
+  def self.get_auth_endpoint
+    g = glance_credentials
+    "#{g['auth_protocol']}://#{g['auth_host']}:#{g['auth_port']}#{g['auth_admin_prefix']}/v2.0/"
+  end
+
+  def self.glance_file
+    return @glance_file if @glance_file
+    @glance_file = Puppet::Util::IniConfig::File.new
+    @glance_file.read('/etc/glance/glance-api.conf')
+    @glance_file
+  end
+
+  def self.glance_hash
+    @glance_hash ||= build_glance_hash
+  end
+
+  def self.reset
+    @glance_hash        = nil
+    @glance_file        = nil
+    @glance_credentials = nil
+    @auth_endpoint      = nil
+  end
+
+  def glance_hash
+    self.class.glance_hash
+  end
+
+  def self.auth_glance(*args)
+    begin
+      g = glance_credentials
+      remove_warnings(glance('--os-tenant-name', g['admin_tenant_name'], '--os-username', g['admin_user'], '--os-password', g['admin_password'], '--os-region-name', g['os_region_name'], '--os-auth-url', auth_endpoint, args))
+    rescue Exception => e
+      if (e.message =~ /\[Errno 111\] Connection refused/) or (e.message =~ /\(HTTP 400\)/) or (e.message =~ /HTTP Unable to establish connection/)
+        sleep 10
+        remove_warnings(glance('--os-tenant-name', g['admin_tenant_name'], '--os-username', g['admin_user'], '--os-password', g['admin_password'], '--os-region-name', g['os_region_name'], '--os-auth-url', auth_endpoint, args))
+      else
+        raise(e)
+      end
+    end
+  end
+
+  def auth_glance(*args)
+    self.class.auth_glance(args)
+  end
+
+  def self.auth_glance_stdin(*args)
+    begin
+      g = glance_credentials
+      command = "glance --os-tenant-name #{g['admin_tenant_name']} --os-username #{g['admin_user']} --os-password #{g['admin_password']} --os-region-name #{g['os_region_name']} --os-auth-url #{auth_endpoint} #{args.join(' ')}"
+
+      # This is a horrible, horrible hack
+      # Redirect stderr to stdout in order to report errors
+      # Ignore good output
+      err = `#{command} 3>&1 1>/dev/null 2>&3`
+      if $? != 0
+        raise(Puppet::Error, err)
+      end
+    end
+  end
+
+  def auth_glance_stdin(*args)
+    self.class.auth_glance_stdin(args)
+  end
+
+  private
+    def self.list_glance_images
+      ids = []
+      (auth_glance('image-list').split("\n")[3..-2] || []).collect do |line|
+        ids << line.split('|')[1].strip()
+      end
+      return ids
+    end
+
+    def self.get_glance_image_attr(id, attr)
+      (auth_glance('image-show', id).split("\n") || []).collect do |line|
+        if line =~ /^#{attr}:/
+          return line.split(': ')[1..-1]
+        end
+      end
+    end
+
+    def self.get_glance_image_attrs(id)
+      attrs = {}
+      (auth_glance('image-show', id).split("\n")[3..-2] || []).collect do |line|
+        attrs[line.split('|')[1].strip()] = line.split('|')[2].strip()
+      end
+      return attrs
+    end
+
+    def parse_table(table)
+      # parse the table into an array of maps with a simplistic state machine
+      found_header = false
+      parsed_header = false
+      keys = nil
+      results = []
+      table.split("\n").collect do |line|
+        # look for the header
+        if not found_header
+          if line =~ /^\+[-|+]+\+$/
+            found_header = true
+            nil
+          end
+        # look for the key names in the table header
+        elsif not parsed_header
+          if line =~ /^(\|\s*[:alpha:]\s*)|$/
+            keys = line.split('|').map(&:strip)
+            parsed_header = true
+          end
+        # parse the values in the rest of the table
+        elsif line =~ /^|.*|$/
+          values = line.split('|').map(&:strip)
+          result = Hash[keys.zip values]
+          results << result
+        end
+      end
+      results
+    end
+
+    # Remove warning from the output. This is a temporary hack until
+    # things will be refactored to use the REST API
+    def self.remove_warnings(results)
+      found_header = false
+      in_warning = false
+      results.split("\n").collect do |line|
+        unless found_header
+          if line =~ /^\+[-\+]+\+$/ # Matches upper and lower box borders
+            in_warning = false
+            found_header = true
+            line
+          elsif line =~ /^WARNING/ or line =~ /UserWarning/ or in_warning
+            # warnings can be multi line, we have to skip all of them
+            in_warning = true
+            nil
+          else
+            line
+          end
+        else
+          line
+        end
+      end.compact.join("\n")
+    end
+end