From 1efc049dfc1cee42a2b13b8932274053aa129c07 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Wed, 22 Nov 2017 18:07:29 +0000 Subject: [PATCH 1/1] Modernise mysql LWRPs --- cookbooks/mysql/libraries/mysql.rb | 24 ++++---- cookbooks/mysql/providers/database.rb | 87 --------------------------- cookbooks/mysql/providers/user.rb | 72 ---------------------- cookbooks/mysql/resources/database.rb | 67 ++++++++++++++++++++- cookbooks/mysql/resources/user.rb | 58 ++++++++++++++++-- 5 files changed, 129 insertions(+), 179 deletions(-) delete mode 100644 cookbooks/mysql/providers/database.rb delete mode 100644 cookbooks/mysql/providers/user.rb diff --git a/cookbooks/mysql/libraries/mysql.rb b/cookbooks/mysql/libraries/mysql.rb index 7c45022fd..516c38a41 100644 --- a/cookbooks/mysql/libraries/mysql.rb +++ b/cookbooks/mysql/libraries/mysql.rb @@ -1,8 +1,8 @@ require "chef/mixin/shell_out" require "rexml/document" -class Chef - class MySQL +module OpenStreetMap + module MySQL include Chef::Mixin::ShellOut USER_PRIVILEGES = [ @@ -20,7 +20,7 @@ class Chef :execute, :event, :trigger ].freeze - def execute(options) + def mysql_execute(options) # Create argument array args = [] @@ -55,7 +55,7 @@ class Chef def query(sql, options = {}) # Run the query - result = execute(options.merge(:command => sql, :xml => true)) + result = mysql_execute(options.merge(:command => sql, :xml => true)) # Parse the output document = REXML::Document.new(result.stdout) @@ -84,8 +84,8 @@ class Chef records end - def users - @users ||= query("SELECT * FROM user").each_with_object({}) do |user, users| + def mysql_users + @mysql_users ||= query("SELECT * FROM user").each_with_object({}) do |user, users| name = "'#{user[:user]}'@'#{user[:host]}'" users[name] = USER_PRIVILEGES.each_with_object({}) do |privilege, privileges| @@ -94,15 +94,15 @@ class Chef end end - def databases - @databases ||= query("SHOW databases").each_with_object({}) do |database, databases| + def mysql_databases + @mysql_databases ||= query("SHOW databases").each_with_object({}) do |database, databases| databases[database[:database]] = { :permissions => {} } end query("SELECT * FROM db").each do |record| - database = @databases[record[:db]] + database = @mysql_databases[record[:db]] next unless database @@ -113,10 +113,10 @@ class Chef end end - @databases + @mysql_databases end - def canonicalise_user(user) + def mysql_canonicalise_user(user) local, host = user.split("@") host ||= "%" @@ -127,7 +127,7 @@ class Chef "#{local}@#{host}" end - def privilege_name(privilege) + def mysql_privilege_name(privilege) case privilege when :grant "GRANT OPTION" diff --git a/cookbooks/mysql/providers/database.rb b/cookbooks/mysql/providers/database.rb deleted file mode 100644 index 0e7e9091a..000000000 --- a/cookbooks/mysql/providers/database.rb +++ /dev/null @@ -1,87 +0,0 @@ -# -# Cookbook Name:: mysql -# Provider:: mysql_database -# -# Copyright 2013, OpenStreetMap Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use_inline_resources - -def load_current_resource - @mysql = Chef::MySQL.new - - @current_resource = Chef::Resource::MysqlDatabase.new(new_resource.name) - @current_resource.database(new_resource.database) - if (mysql_database = @mysql.databases[@current_resource.database]) - @current_resource.permissions(mysql_database[:permissions]) - end - @current_resource -end - -action :create do - unless @mysql.databases.include?(new_resource.database) - converge_by("create #{new_resource}") do - Chef::Log.info("Creating #{new_resource}") - @mysql.execute(:command => "CREATE DATABASE `#{new_resource.database}`") - end - end - - new_permissions = Hash[new_resource.permissions.collect do |user, privileges| - [@mysql.canonicalise_user(user), privileges] - end] - - @current_resource.permissions.each_key do |user| - next if new_permissions[user] - - converge_by("revoke all for #{user} on #{new_resource}") do - Chef::Log.info("Revoking all for #{user} on #{new_resource}") - @mysql.execute(:command => "REVOKE ALL ON `#{new_resource.database}`.* FROM #{user}") - end - end - - new_permissions.each do |user, new_privileges| - current_privileges = @current_resource.permissions[user] || {} - new_privileges = Array(new_privileges) - - if new_privileges.include?(:all) - new_privileges |= (Chef::MySQL::DATABASE_PRIVILEGES - [:grant]) - end - - Chef::MySQL::DATABASE_PRIVILEGES.each do |privilege| - if new_privileges.include?(privilege) - unless current_privileges.include?(privilege) - converge_by("grant #{privilege} for #{user} on mysql database #{new_resource}") do - Chef::Log.info("Granting #{privilege} for #{user} on mysql database #{new_resource}") - @mysql.execute(:command => "GRANT #{@mysql.privilege_name(privilege)} ON `#{new_resource.database}`.* TO #{user}") - end - end - elsif current_privileges.include?(privilege) - converge_by("revoke #{privilege} for #{user} on #{new_resource}") do - Chef::Log.info("Revoking #{privilege} for #{user} on #{new_resource}") - @mysql.execute(:command => "REVOKE #{@mysql.privilege_name(privilege)} ON `#{new_resource.database}`.* FROM #{user}") - end - end - end - end -end - -action :drop do - if @mysql.databases.include?(new_resource.database) - converge_by("drop #{new_resource}") do - Chef::Log.info("Dropping #{new_resource}") - @mysql.execute(:command => "DROP DATABASE `#{new_resource.database}`") - end - end -end diff --git a/cookbooks/mysql/providers/user.rb b/cookbooks/mysql/providers/user.rb deleted file mode 100644 index c2f5e58d2..000000000 --- a/cookbooks/mysql/providers/user.rb +++ /dev/null @@ -1,72 +0,0 @@ -# -# Cookbook Name:: mysql -# Provider:: mysql_user -# -# Copyright 2013, OpenStreetMap Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use_inline_resources - -def load_current_resource - @mysql = Chef::MySQL.new - - @current_resource = Chef::Resource::MysqlUser.new(new_resource.name) - @current_resource.user(new_resource.user) - if (mysql_user = @mysql.users[@current_resource.user]) - Chef::MySQL::USER_PRIVILEGES.each do |privilege| - @current_resource.send(privilege, mysql_user[privilege]) - end - end - @current_resource -end - -action :create do - user = @mysql.canonicalise_user(new_resource.user) - password = new_resource.password ? "IDENTIFIED BY '#{new_resource.password}'" : "" - - unless @mysql.users.include?(user) - converge_by("create #{new_resource}") do - Chef::Log.info("Creating #{new_resource}") - @mysql.execute(:command => "CREATE USER #{user} #{password}") - end - end - - Chef::MySQL::USER_PRIVILEGES.each do |privilege| - next if new_resource.send(privilege) == @current_resource.send(privilege) - - if new_resource.send(privilege) - converge_by("grant #{privilege} for #{new_resource}") do - Chef::Log.info("Granting #{privilege} for #{new_resource}") - @mysql.execute(:command => "GRANT #{@mysql.privilege_name(privilege)} ON *.* TO #{user}") - end - else - converge_by("revoke #{privilege} for #{new_resource}") do - Chef::Log.info("Revoking #{privilege} for #{new_resource}") - @mysql.execute(:command => "REVOKE #{@mysql.privilege_name(privilege)} ON *.* FROM #{user}") - end - end - end -end - -action :drop do - user = @mysql.canonicalise_user(new_resource.user) - - if @mysql.users.include?(user) - converge_by("drop #{new_resource}") do - Chef::Log.info("Dropping #{new_resource}") - @mysql.execute(:command => "DROP USER #{user}") - end - end -end diff --git a/cookbooks/mysql/resources/database.rb b/cookbooks/mysql/resources/database.rb index 60236d8dd..1cb81368c 100644 --- a/cookbooks/mysql/resources/database.rb +++ b/cookbooks/mysql/resources/database.rb @@ -17,8 +17,69 @@ # limitations under the License. # -actions :create, :drop default_action :create -attribute :database, :kind_of => String, :name_attribute => true -attribute :permissions, :kind_of => Hash, :default => {} +property :database, :kind_of => String, :name_attribute => true +property :permissions, :kind_of => Hash, :default => {} + +action :create do + unless mysql_databases.include?(new_resource.database) + converge_by("create #{new_resource}") do + Chef::Log.info("Creating #{new_resource}") + mysql_execute(:command => "CREATE DATABASE `#{new_resource.database}`") + end + end + + current_permissions = mysql_databases[new_resource.database]&.dig(:permissions) || {} + + new_permissions = Hash[new_resource.permissions.collect do |user, privileges| + [mysql_canonicalise_user(user), privileges] + end] + + current_permissions.each_key do |user| + next if new_permissions[user] + + converge_by("revoke all for #{user} on #{new_resource}") do + Chef::Log.info("Revoking all for #{user} on #{new_resource}") + mysql_execute(:command => "REVOKE ALL ON `#{new_resource.database}`.* FROM #{user}") + end + end + + new_permissions.each do |user, new_privileges| + current_privileges = current_permissions[user] || {} + new_privileges = Array(new_privileges) + + if new_privileges.include?(:all) + new_privileges |= (OpenStreetMap::MySQL::DATABASE_PRIVILEGES - [:grant]) + end + + OpenStreetMap::MySQL::DATABASE_PRIVILEGES.each do |privilege| + if new_privileges.include?(privilege) + unless current_privileges.include?(privilege) + converge_by("grant #{privilege} for #{user} on mysql database #{new_resource}") do + Chef::Log.info("Granting #{privilege} for #{user} on mysql database #{new_resource}") + mysql_execute(:command => "GRANT #{mysql_privilege_name(privilege)} ON `#{new_resource.database}`.* TO #{user}") + end + end + elsif current_privileges.include?(privilege) + converge_by("revoke #{privilege} for #{user} on #{new_resource}") do + Chef::Log.info("Revoking #{privilege} for #{user} on #{new_resource}") + mysql_execute(:command => "REVOKE #{mysql_privilege_name(privilege)} ON `#{new_resource.database}`.* FROM #{user}") + end + end + end + end +end + +action :drop do + if mysql_databases.include?(new_resource.database) + converge_by("drop #{new_resource}") do + Chef::Log.info("Dropping #{new_resource}") + mysql_execute(:command => "DROP DATABASE `#{new_resource.database}`") + end + end +end + +action_class do + include OpenStreetMap::MySQL +end diff --git a/cookbooks/mysql/resources/user.rb b/cookbooks/mysql/resources/user.rb index 45436c703..329778cb9 100644 --- a/cookbooks/mysql/resources/user.rb +++ b/cookbooks/mysql/resources/user.rb @@ -17,12 +17,60 @@ # limitations under the License. # -actions :create, :drop default_action :create -attribute :user, :kind_of => String, :name_attribute => true -attribute :password, :kind_of => String +property :user, :kind_of => String, :name_attribute => true +property :password, :kind_of => String -Chef::MySQL::USER_PRIVILEGES.each do |privilege| - attribute privilege, :default => false +OpenStreetMap::MySQL::USER_PRIVILEGES.each do |privilege| + property privilege, :default => false +end + +action :create do + user = mysql_canonicalise_user(new_resource.user) + password = new_resource.password ? "IDENTIFIED BY '#{new_resource.password}'" : "" + + unless mysql_users.include?(user) + converge_by("create #{new_resource}") do + Chef::Log.info("Creating #{new_resource}") + mysql_execute(:command => "CREATE USER #{user} #{password}") + end + end + + current_privileges = mysql_users.fetch(new_resource.user, {}) + + new_privileges = Hash[OpenStreetMap::MySQL::USER_PRIVILEGES.collect do |privilege| + [privilege, new_resource.send(privilege)] + end] + + new_privileges.each do |privilege, new_enabled| + old_enabled = current_privileges.fetch(privilege, false) + + if new_enabled && !old_enabled + converge_by("grant #{privilege} for #{new_resource}") do + Chef::Log.info("Granting #{privilege} for #{new_resource}") + mysql_execute(:command => "GRANT #{mysql_privilege_name(privilege)} ON *.* TO #{user}") + end + elsif old_enabled && !new_enabled + converge_by("revoke #{privilege} for #{new_resource}") do + Chef::Log.info("Revoking #{privilege} for #{new_resource}") + mysql_execute(:command => "REVOKE #{mysql_privilege_name(privilege)} ON *.* FROM #{user}") + end + end + end +end + +action :drop do + user = mysql_canonicalise_user(new_resource.user) + + if mysql_users.include?(user) + converge_by("drop #{new_resource}") do + Chef::Log.info("Dropping #{new_resource}") + mysql_execute(:command => "DROP USER #{user}") + end + end +end + +action_class do + include OpenStreetMap::MySQL end -- 2.43.2