newer pg module
[mirror/dsa-puppet.git] / 3rdparty / modules / postgresql / lib / puppet / type / postgresql_psql.rb
index ab6af92..5b2702c 100644 (file)
@@ -10,32 +10,20 @@ Puppet::Type.newtype(:postgresql_psql) do
 
     defaultto { @resource[:name] }
 
-    def sync(refreshing = false)
-      # We're overriding 'sync' here in order to do some magic
-      # in support of providing a 'refreshonly' parameter.  This
-      # is kind of hacky because the logic for 'refreshonly' is
-      # spread between the type and the provider, but this is
-      # the least horrible way that I could determine to accomplish
-      # it.
-      #
-      # Note that our overridden version of 'sync' takes a parameter,
-      # 'refreshing', which the parent version doesn't take.  This
-      # allows us to call the sync method directly from the 'refresh'
-      # method, and then inside of the body of 'sync' we can tell
-      # whether or not we're refreshing.
-
-      if ((@resource[:refreshonly] == :false) || refreshing)
-        # If we're not in 'refreshonly' mode, or we're not currently
-        # refreshing, then we just call the parent method.
-        super()
+    # If needing to run the SQL command, return a fake value that will trigger
+    # a sync, else return the expected SQL command so no sync takes place
+    def retrieve
+      if @resource.should_run_sql
+        return :notrun
       else
-        # If we get here, it means we're in 'refreshonly' mode and
-        # we're not being called by the 'refresh' method, so we
-        # just no-op.  We'll be called again by the 'refresh'
-        # method momentarily.
-        nil
+        return self.should
       end
     end
+
+    def sync
+      output, status = provider.run_sql_command(value)
+      self.fail("Error executing SQL; psql returned #{status}: '#{output}'") unless status == 0
+    end
   end
 
   newparam(:unless) do
@@ -43,10 +31,51 @@ Puppet::Type.newtype(:postgresql_psql) do
         "this is generally intended to be used for idempotency, to check " +
         "for the existence of an object in the database to determine whether " +
         "or not the main SQL command needs to be executed at all."
+
+    # Return true if a matching row is found
+    def matches(value)
+      output, status = provider.run_unless_sql_command(value)
+      self.fail("Error evaluating 'unless' clause, returned #{status}: '#{output}'") unless status == 0
+
+      result_count = output.strip.to_i
+      self.debug("Found #{result_count} row(s) executing 'unless' clause")
+      result_count > 0
+    end
+  end
+
+  newparam(:onlyif) do
+    desc "An optional SQL command to execute prior to the main :command; " +
+        "this is generally intended to be used for idempotency, to check " +
+        "for the existence of an object in the database to determine whether " +
+        "or not the main SQL command needs to be executed at all."
+
+    # Return true if a matching row is found
+    def matches(value)
+      output, status = provider.run_unless_sql_command(value)
+      status = output.exitcode if status.nil?
+
+      self.fail("Error evaluating 'onlyif' clause, returned #{status}: '#{output}'") unless status == 0
+
+      result_count = output.strip.to_i
+      self.debug("Found #{result_count} row(s) executing 'onlyif' clause")
+      result_count > 0
+    end
+  end
+
+  newparam(:connect_settings) do
+    desc "Connection settings that will be used when connecting to postgres"
   end
 
   newparam(:db) do
-    desc "The name of the database to execute the SQL command against."
+    desc "The name of the database to execute the SQL command against, this overrides any PGDATABASE value in connect_settings"
+  end
+
+  newparam(:port) do
+    desc "The port of the database server to execute the SQL command against, this overrides any PGPORT value in connect_settings."
+  end
+
+  newparam(:search_path) do
+    desc "The schema search path to use when executing the SQL command"
   end
 
   newparam(:psql_path) do
@@ -69,16 +98,38 @@ Puppet::Type.newtype(:postgresql_psql) do
     defaultto("/tmp")
   end
 
-  newparam(:refreshonly) do
+  newparam(:environment) do
+    desc "Any additional environment variables you want to set for a
+      SQL command. Multiple environment variables should be
+      specified as an array."
+
+    validate do |values|
+      Array(values).each do |value|
+        unless value =~ /\w+=/
+          raise ArgumentError, "Invalid environment setting '#{value}'"
+        end
+      end
+    end
+  end
+
+  newparam(:refreshonly, :boolean => true) do
     desc "If 'true', then the SQL will only be executed via a notify/subscribe event."
 
     defaultto(:false)
+    newvalues(:true, :false)
+  end
+
+  def should_run_sql(refreshing = false)
+    onlyif_param = @parameters[:onlyif]
+    unless_param = @parameters[:unless]
+    return false if !onlyif_param.nil? && !onlyif_param.value.nil? && !onlyif_param.matches(onlyif_param.value)
+    return false if !unless_param.nil? && !unless_param.value.nil? && unless_param.matches(unless_param.value)
+    return false if !refreshing && @parameters[:refreshonly].value == :true
+    true
   end
 
-  def refresh()
-    # All of the magic for this type is attached to the ':command' property, so
-    # we just need to sync it to accomplish a 'refresh'.
-    self.property(:command).sync(true)
+  def refresh
+    self.property(:command).sync if self.should_run_sql(true)
   end
 
 end