Skip to content

Commit

Permalink
WIP: Rewrite proxy_mysql_galera_hostgroup type
Browse files Browse the repository at this point in the history
  • Loading branch information
alexjfisher committed May 20, 2019
1 parent 9da4477 commit 93fccff
Show file tree
Hide file tree
Showing 11 changed files with 434 additions and 174 deletions.
27 changes: 12 additions & 15 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ You can configure users\hostgroups\rules\schedulers using class parameters
mysql_galera_hostgroups => [
{
'galera hostgroup 1' => {
'writer_hostgroup' => 1,
'backup_writer_hostgroup' => 2,
'reader_hostgroup' => 3,
'offline_hostgroup' => 4,
'writer' => 1,
'backup' => 2,
'reader' => 3,
'offline' => 4,
}
},
],
Expand Down Expand Up @@ -508,38 +508,35 @@ Optional comment.
##### `ensure`
Whether the resource is present. Valid values are 'present', 'absent'. Defaults to 'present'.

##### `name`
Name to describe the hostgroup config. Must be in a '`writer_hostgroup`-`backup_writer_hostgroup`-`reader_hostgroup`-`offline_hostgroup`' format.

##### `load_to_runtime`
Specifies wheter the resource should be immediately loaded to the active runtime. Boolean, defaults to 'true'.

##### `save_to_disk`
Specifies wheter the resource should be immediately save to disk. Boolean, defaults to 'true'.

##### `writer_hostgroup`
Id of the writer hostgroup. Required.
Id of the writer hostgroup. Required if the title of the resource doesn't match the '`writer_hostgroup`-`backup_writer_hostgroup`-`reader_hostgroup`-`offline_hostgroup`' format.

##### `backup_writer_hostgroup`
Id of the backup writer hostgroup. Required.
Id of the backup writer hostgroup. Required if the title of the resource doesn't match the '`writer_hostgroup`-`backup_writer_hostgroup`-`reader_hostgroup`-`offline_hostgroup`' format.

##### `reader_hostgroup`
Id of the reader hostgroup. Required.
Id of the reader hostgroup. Required if the title of the resource doesn't match the '`writer_hostgroup`-`backup_writer_hostgroup`-`reader_hostgroup`-`offline_hostgroup`' format.

##### `offline_hostgroup`
Id of the offline hostgroup. Required.
Id of the offline hostgroup. Required if the title of the resource doesn't match the '`writer_hostgroup`-`backup_writer_hostgroup`-`reader_hostgroup`-`offline_hostgroup`' format.

##### `active`
Specifies wheter the resource is active or not. Integer, defaults to 1.
Specifies whether the resource is active or not. Integer. On creation defaults to proxysql default setting (1).

##### `max_writers`
Specifies how many active writers the resource has. Integer, defaults to 1.
Specifies how many active writers the resource has. Integer. On creation defaults to proxysql default setting (1).

##### `writer_is_also_reader`
Specifies if the writer is also a reader. Integer, defaults to 0.
Specifies if the writer is also a reader. Integer. On creation defaults to proxysql default setting (0).

##### `max_transactions_behind`
Specifies how many transactions a resource can be behind the "master" until shunned. Integer, defaults to 0.
Specifies how many transactions a resource can be behind the "master" until shunned. Integer. On creation defaults to proxysql default setting (0).

##### `comment`
Optional comment.
Expand Down
20 changes: 10 additions & 10 deletions examples/init.pp
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@
{ 'ro' => { 'password' => '*86935F2843252CFAAC4CE713C0D5FF80CF444F3B',
'default_hostgroup' => 2, } },
],
mysql_hostgroups => [ { 'hostgroup 1' => { 'writer_hostgroup' => 1,
'reader_hostgroup' => 2, } },
mysql_hostgroups => [ { 'hostgroup 1' => { 'writer' => 1,
'reader' => 2, } },
],
mysql_group_replication_hostgroups => [ { 'hostgroup 2' => { 'reader_hostgroup' => 10,
'writer_hostgroup' => 5,
'backup_writer_hostgroup' => 2,
'offline_hostgroup' => 11, } },
mysql_group_replication_hostgroups => [ { 'hostgroup 2' => { 'reader' => 10,
'writer' => 5,
'backup' => 2,
'offline' => 11, } },
],
mysql_galera_hostgroups => [ { 'hostgroup 2' => { 'reader_hostgroup' => 10,
'writer_hostgroup' => 5,
'backup_writer_hostgroup' => 2,
'offline_hostgroup' => 11, } },
mysql_galera_hostgroups => [ { 'hostgroup 2' => { 'reader' => 10,
'writer' => 5,
'backup' => 2,
'offline' => 11, } },
],
mysql_rules => [ { 'testable to test DB' => { 'rule_id' => 1,
'match_pattern' => 'testtable',
Expand Down
186 changes: 110 additions & 76 deletions lib/puppet/provider/proxy_mysql_galera_hostgroup/proxysql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,106 +3,140 @@
desc 'Manage galera hostgroup for a ProxySQL instance.'
commands mysql: 'mysql'

# Build a property_hash containing all the discovered information about MySQL
# Galera servers.
def initialize(value = {})
super(value)
@property_flush = {}
end

# Generates method for all properties of the property_hash
mk_resource_methods

def self.mysql_galera_hostgroup_properties
select = db_fields.map { |f| "`#{f}`" }.join(',')
begin
hostgroups = mysql([defaults_file, '-NBe', "SELECT #{select} FROM `mysql_galera_hostgroups`"].compact).split(%r{\n})
rescue Puppet::ExecutionFailure => e
Puppet.debug "#mysql_galera_hostgroup_properties had an error -> #{e.inspect}"
return {}
end

hostgroups.map do |hostgroup|
hostgroup_properties = {}
hostgroup_properties[:ensure] = :present
hostgroup_properties[:provider] = :proxysql

# insert each field returned by the query into the hash with the matching key
hostgroup.split(%r{\t}).each_with_index { |field, index| hostgroup_properties[db_fields[index]] = field }

# create :name from other hostgroup fields
hostgroup_properties[:name] = namevar_db_fields.map { |field| hostgroup_properties[field] }.join('-')

# Convert each integer field into a proper integer
integer_db_fields.each { |field| hostgroup_properties[field] = hostgroup_properties[field].to_i }
hostgroup_properties
end
end

def self.instances
instances = []
hostgroups = mysql([defaults_file, '-NBe',
'SELECT `writer_hostgroup`, `backup_writer_hostgroup`, `reader_hostgroup`, `offline_hostgroup`, `active`,`max_writers`,`writer_is_also_reader`,`max_transactions_behind`, `comment` FROM `mysql_galera_hostgroups`'].compact).split(%r{\n})

# To reduce the number of calls to MySQL we collect all the properties in
# one big swoop.
hostgroups.each do |line|
writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, comment = line.split(%r{\t})
name = "#{writer_hostgroup}-#{backup_writer_hostgroup}-#{reader_hostgroup}-#{offline_hostgroup}"

instances << new(
name: name,
ensure: :present,
writer_hostgroup: writer_hostgroup,
backup_writer_hostgroup: backup_writer_hostgroup,
reader_hostgroup: reader_hostgroup,
offline_hostgroup: offline_hostgroup,
active: active,
max_writers: max_writers,
writer_is_also_reader: writer_is_also_reader,
max_transactions_behind: max_transactions_behind,
comment: comment
)
mysql_galera_hostgroup_properties.map do |properties|
new(properties)
end
instances
end

# We iterate over each proxy_mysql_galera_hostgroup entry in the catalog and compare it against
# the contents of the property_hash generated by self.instances
def self.prefetch(resources)
hostgroups = instances
resources.keys.each do |name|
provider = hostgroups.find { |hostgroup| hostgroup.name == name }
resources[name].provider = provider if provider
instances.each do |prov|
if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition
resource.provider = prov
end
end
end

def create
_name = @resource[:name]
writer_hostgroup = @resource.value(:writer_hostgroup)
backup_writer_hostgroup = @resource.value(:backup_writer_hostgroup)
reader_hostgroup = @resource.value(:reader_hostgroup)
offline_hostgroup = @resource.value(:offline_hostgroup)
active = @resource.value(:active)
max_writers = @resource.value(:max_writers)
writer_is_also_reader = @resource.value(:writer_is_also_reader)
max_transactions_behind = @resource.value(:max_transactions_behind)
comment = @resource.value(:comment) || ''

query = 'INSERT INTO `mysql_galera_hostgroups` (`writer_hostgroup`, `backup_writer_hostgroup`, `reader_hostgroup`, `offline_hostgroup`, `active`,`max_writers`,`writer_is_also_reader`,`max_transactions_behind`, `comment`)'
query << " VALUES (#{writer_hostgroup}, #{backup_writer_hostgroup}, #{reader_hostgroup}, #{offline_hostgroup}, #{active}, #{max_writers}, #{writer_is_also_reader}, #{max_transactions_behind}, '#{comment}')"
mysql([defaults_file, '-e', query].compact)
@property_hash[:ensure] = :present
query_parameters = Hash[self.class.db_fields.map { |param| [param, resource[param]] }].reject { |_k, v| v.nil? }

exists? ? (return true) : (return false)
end
columns = query_parameters.keys.map { |k| "`#{k}`" }.join(',')
values = query_parameters.values.map { |value| make_sql_value(value) }.join(',')

def destroy
writer_hostgroup = @resource.value(:writer_hostgroup)
backup_writer_hostgroup = @resource.value(:backup_writer_hostgroup)
reader_hostgroup = @resource.value(:reader_hostgroup)
offline_hostgroup = @resource.value(:offline_hostgroup)
query = 'DELETE FROM `mysql_galera_hostgroups`'
query << " WHERE `writer_hostgroup` = #{writer_hostgroup} AND `backup_writer_hostgroup` = #{backup_writer_hostgroup} `reader_hostgroup` = #{reader_hostgroup} AND `offline_hostgroup` = #{offline_hostgroup}"
query = "INSERT INTO `mysql_galera_hostgroups` (#{columns}) VALUES (#{values})"
mysql([defaults_file, '-e', query].compact)

@property_hash.clear
exists? ? (return false) : (return true)
end

def exists?
@property_hash[:ensure] == :present || false
@property_hash[:ensure] == :present
end

def destroy
@property_flush[:ensure] = :absent
end

def flush
@property_hash.clear
load_to_runtime = @resource[:load_to_runtime]
mysql([defaults_file, '-NBe', 'LOAD MYSQL SERVERS TO RUNTIME'].compact) if load_to_runtime == :true
if @property_flush[:ensure] == :absent
delete_hostgroup
@property_flush.clear
@property_hash.clear
return
end

update_hostgroup unless @property_flush.empty?

mysql([defaults_file, '-NBe', 'LOAD MYSQL SERVERS TO RUNTIME'].compact) if resource.load_to_runtime?
mysql([defaults_file, '-NBe', 'SAVE MYSQL SERVERS TO DISK'].compact) if resource.save_to_disk?

save_to_disk = @resource[:save_to_disk]
mysql([defaults_file, '-NBe', 'SAVE MYSQL SERVERS TO DISK'].compact) if save_to_disk == :true
# Collect the resources again once they've been changed (that way `puppet
# resource` will show the correct values after changes have been made).
@property_hash = self.class.mysql_galera_hostgroup_properties.find { |hostgroup| hostgroup[:name] == resource[:name] }
Puppet.warning @property_hash
end

# Generates method for all properties of the property_hash
mk_resource_methods
# Create our own setters for all properties other than `ensure`
resource_type.validproperties.each do |property|
property = property.intern
next if property == :ensure

def comment=(value)
writer_hostgroup = @resource.value(:writer_hostgroup)
backup_writer_hostgroup = @resource.value(:backup_writer_hostgroup)
reader_hostgroup = @resource.value(:reader_hostgroup)
offline_hostgroup = @resource.value(:offline_hostgroup)
define_method(property.to_s + '=') do |value|
@property_flush[property] = value
@property_hash[property] = value
end
end

def update_hostgroup
updates = @property_flush.map do |k, v|
"`#{k}` = #{make_sql_value(v)}"
end.join(',')

query = "UPDATE mysql_galera_hostgroups SET #{updates} WHERE #{sql_where}"

query = "UPDATE mysql_galera_hostgroups SET `comment` = '#{value}'"
query << " WHERE `writer_hostgroup` = #{writer_hostgroup} AND `backup_writer_hostgroup` = #{backup_writer_hostgroup}AND `reader_hostgroup` = #{reader_hostgroup} AND `offline_hostgroup` = #{offline_hostgroup}"
mysql([defaults_file, '-e', query].compact)
end

def delete_hostgroup
query = "DELETE FROM mysql_galera_hostgroups WHERE #{sql_where}"
mysql([defaults_file, '-e', query].compact)
end

def sql_where
self.class.namevar_db_fields.map { |param| "`#{param}` = #{@resource.value(param)}" }.join(' AND ')
end

def self.namevar_db_fields
[
:writer_hostgroup,
:backup_writer_hostgroup,
:reader_hostgroup,
:offline_hostgroup
]
end

def self.integer_db_fields
namevar_db_fields + [
:active,
:max_writers,
:writer_is_also_reader,
:max_transactions_behind
]
end

@property_hash.clear
exists? ? (return false) : (return true)
def self.db_fields
integer_db_fields + [:comment]
end
end
Loading

0 comments on commit 93fccff

Please sign in to comment.