]> git.openstreetmap.org Git - chef.git/blobdiff - cookbooks/mysql/libraries/mysql.rb
Add a load more cookbooks
[chef.git] / cookbooks / mysql / libraries / mysql.rb
diff --git a/cookbooks/mysql/libraries/mysql.rb b/cookbooks/mysql/libraries/mysql.rb
new file mode 100644 (file)
index 0000000..c0da28f
--- /dev/null
@@ -0,0 +1,146 @@
+require "chef/mixin/command"
+require "rexml/document"
+
+class Chef
+  class MySQL
+    include Chef::Mixin::Command
+
+    USER_PRIVILEGES = [
+      :select, :insert, :update, :delete, :create, :drop, :reload,
+      :shutdown, :process, :file, :grant, :references, :index, :alter,
+      :show_db, :super, :create_tmp_table, :lock_tables, :execute,
+      :repl_slave, :repl_client, :create_view, :show_view, :create_routine,
+      :alter_routine, :create_user, :event, :trigger, :create_tablespace
+    ]
+
+    DATABASE_PRIVILEGES = [
+      :select, :insert, :update, :delete, :create, :drop, :grant,
+      :references, :index, :alter, :create_tmp_table, :lock_tables,
+      :create_view, :show_view, :create_routine, :alter_routine,
+      :execute, :event, :trigger
+    ]
+
+    def execute(options)
+      # Create argument array
+      args = []
+
+      # Work out how to authenticate
+      if options[:user]
+        args.push("--username=#{options[:user]}")
+        args.push("--password=#{options[:password]}") if options[:password]
+      else
+        args.push("--defaults-file=/etc/mysql/debian.cnf")
+      end
+
+      # Build the other arguments
+      args.push("--execute=\"#{options[:command]}\"") if options[:command]
+
+      # Get the database to use
+      database = options[:database] || "mysql"
+
+      # Build the command to run
+      command = "/usr/bin/mysql #{args.join(' ')} #{database}"
+
+      # Escape backticks in the command
+      command.gsub!(/`/, "\\\\`")
+
+      # Run the command
+      run_command(:command => command, :user => "root", :group => "root")
+    end
+
+    def query(sql, options = {})
+      # Get the database to use
+      database = options[:database] || "mysql"
+
+      # Construct the command string
+      command = "/usr/bin/mysql --defaults-file=/etc/mysql/debian.cnf --xml --execute='#{sql}' #{database}"
+
+      # Run the query
+      status, stdout, stderr = output_of_command(command, :user => "root", :group => "root")
+      handle_command_failures(status, "STDOUT: #{stdout}\nSTDERR: #{stderr}", :output_on_failure => true)
+
+      # Parse the output
+      document = REXML::Document.new(stdout)
+
+      # Create
+      records = []
+
+      # Loop over the rows in the result set
+      document.root.each_element("/resultset/row") do |row|
+        # Create a record
+        record = {}
+
+        # Loop over the fields, adding them to the record
+        row.each_element("field") do |field|
+          name = field.attributes["name"].downcase
+          value = field.text
+
+          record[name.to_sym] = value
+        end
+
+        # Add the record to the record list
+        records << record
+      end
+
+      # Return the record list
+      records
+    end
+
+    def users
+      @users ||= query("SELECT * FROM user").inject({}) do |users,user|
+        name = "'#{user[:user]}'@'#{user[:host]}'"
+
+        users[name] = USER_PRIVILEGES.inject({}) do |privileges,privilege|
+          privileges[privilege] = user["#{privilege}_priv".to_sym] == "Y"
+          privileges
+        end
+
+        users
+      end
+    end
+
+    def databases
+      @databases ||= query("SHOW databases").inject({}) do |databases,database|
+        databases[database[:database]] = {
+          :permissions => {}
+        }
+        databases
+      end
+
+      query("SELECT * FROM db").each do |record|
+        if database = @databases[record[:db]]
+          user = "'#{record[:user]}'@'#{record[:host]}'"
+
+          database[:permissions][user] = DATABASE_PRIVILEGES.inject([]) do |privileges,privilege|
+            privileges << privilege if record["#{privilege}_priv".to_sym] == "Y"
+            privileges
+          end
+        end
+      end
+
+      @databases
+    end
+
+    def canonicalise_user(user)
+      local, host = user.split("@")
+
+      host = "%" unless host
+
+      local = "'#{local}'" unless local =~ /^'.*'$/
+      host = "'#{host}'" unless host =~ /^'.*'$/
+
+      "#{local}@#{host}"
+    end
+
+    def privilege_name(privilege)
+      case privilege
+      when :grant
+        "GRANT OPTION"
+      when :create_tmp_table
+        "CREATE TEMPORARY TABLES"
+      else
+        privilege.to_s.upcase.tr("_", " ")
+      end
+    end
+  end
+end