]> git.openstreetmap.org Git - chef.git/blob - cookbooks/mysql/libraries/mysql.rb
Install the tile.openstreetmap.org certificate on tile servers
[chef.git] / cookbooks / mysql / libraries / mysql.rb
1 require "chef/mixin/command"
2 require "rexml/document"
3
4 class Chef
5   class MySQL
6     include Chef::Mixin::Command
7
8     USER_PRIVILEGES = [
9       :select, :insert, :update, :delete, :create, :drop, :reload,
10       :shutdown, :process, :file, :grant, :references, :index, :alter,
11       :show_db, :super, :create_tmp_table, :lock_tables, :execute,
12       :repl_slave, :repl_client, :create_view, :show_view, :create_routine,
13       :alter_routine, :create_user, :event, :trigger, :create_tablespace
14     ]
15
16     DATABASE_PRIVILEGES = [
17       :select, :insert, :update, :delete, :create, :drop, :grant,
18       :references, :index, :alter, :create_tmp_table, :lock_tables,
19       :create_view, :show_view, :create_routine, :alter_routine,
20       :execute, :event, :trigger
21     ]
22
23     def execute(options)
24       # Create argument array
25       args = []
26
27       # Work out how to authenticate
28       if options[:user]
29         args.push("--username=#{options[:user]}")
30         args.push("--password=#{options[:password]}") if options[:password]
31       else
32         args.push("--defaults-file=/etc/mysql/debian.cnf")
33       end
34
35       # Build the other arguments
36       args.push("--execute=\"#{options[:command]}\"") if options[:command]
37
38       # Get the database to use
39       database = options[:database] || "mysql"
40
41       # Build the command to run
42       command = "/usr/bin/mysql #{args.join(' ')} #{database}"
43
44       # Escape backticks in the command
45       command.gsub!(/`/, "\\\\`")
46
47       # Run the command
48       run_command(:command => command, :user => "root", :group => "root")
49     end
50
51     def query(sql, options = {})
52       # Get the database to use
53       database = options[:database] || "mysql"
54
55       # Construct the command string
56       command = "/usr/bin/mysql --defaults-file=/etc/mysql/debian.cnf --xml --execute='#{sql}' #{database}"
57
58       # Run the query
59       status, stdout, stderr = output_of_command(command, :user => "root", :group => "root")
60       handle_command_failures(status, "STDOUT: #{stdout}\nSTDERR: #{stderr}", :output_on_failure => true)
61
62       # Parse the output
63       document = REXML::Document.new(stdout)
64
65       # Create
66       records = []
67
68       # Loop over the rows in the result set
69       document.root.each_element("/resultset/row") do |row|
70         # Create a record
71         record = {}
72
73         # Loop over the fields, adding them to the record
74         row.each_element("field") do |field|
75           name = field.attributes["name"].downcase
76           value = field.text
77
78           record[name.to_sym] = value
79         end
80
81         # Add the record to the record list
82         records << record
83       end
84
85       # Return the record list
86       records
87     end
88
89     def users
90       @users ||= query("SELECT * FROM user").inject({}) do |users,user|
91         name = "'#{user[:user]}'@'#{user[:host]}'"
92
93         users[name] = USER_PRIVILEGES.inject({}) do |privileges,privilege|
94           privileges[privilege] = user["#{privilege}_priv".to_sym] == "Y"
95           privileges
96         end
97
98         users
99       end
100     end
101
102     def databases
103       @databases ||= query("SHOW databases").inject({}) do |databases,database|
104         databases[database[:database]] = {
105           :permissions => {}
106         }
107         databases
108       end
109
110       query("SELECT * FROM db").each do |record|
111         if database = @databases[record[:db]]
112           user = "'#{record[:user]}'@'#{record[:host]}'"
113
114           database[:permissions][user] = DATABASE_PRIVILEGES.inject([]) do |privileges,privilege|
115             privileges << privilege if record["#{privilege}_priv".to_sym] == "Y"
116             privileges
117           end
118         end
119       end
120
121       @databases
122     end
123
124     def canonicalise_user(user)
125       local, host = user.split("@")
126
127       host = "%" unless host
128
129       local = "'#{local}'" unless local =~ /^'.*'$/
130       host = "'#{host}'" unless host =~ /^'.*'$/
131
132       "#{local}@#{host}"
133     end
134
135     def privilege_name(privilege)
136       case privilege
137       when :grant
138         "GRANT OPTION"
139       when :create_tmp_table
140         "CREATE TEMPORARY TABLES"
141       else
142         privilege.to_s.upcase.tr("_", " ")
143       end
144     end
145   end
146 end