From 426bbc611d233674bd42610333f763b3affc15a7 Mon Sep 17 00:00:00 2001 From: tphoney Date: Tue, 3 Oct 2017 17:55:51 +0100 Subject: [PATCH] FM_6450 adds the execute SQL task --- CHANGELOG.md | 7 ++++++ README.md | 4 +++ metadata.json | 2 +- spec/acceptance/sql_task_spec.rb | 23 +++++++++++++++++ spec/spec_helper_acceptance.rb | 42 ++++++++++++++++++++++++++++++++ tasks/sql.json | 22 +++++++++++++++++ tasks/sql.rb | 29 ++++++++++++++++++++++ 7 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 spec/acceptance/sql_task_spec.rb create mode 100644 tasks/sql.json create mode 100755 tasks/sql.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 2881e4a2f..f8f4e3688 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org). +## Supported Release [5.1.0] +### Summary +This release adds Tasks to the Mysql module. + +#### Added +- Adds the execute sql task. + ## Supported Release [5.0.0] ### Summary This is a major release that adds support for string translation. Currently the only supported language besides diff --git a/README.md b/README.md index a3d2f0008..f077fef35 100644 --- a/README.md +++ b/README.md @@ -1282,6 +1282,10 @@ Determines the MySQL version by parsing the output from `mysql --version` Generates a unique id, based on the node's MAC address, which can be used as `server_id`. This fact will *always* return `0` on nodes that have only loopback interfaces. Because those nodes aren't connected to the outside world, this shouldn't cause any conflicts. +### Tasks + +The MySQL module has an example task that allows a user to execute arbitary SQL against a database. Please refer to to the [PE documentation](https://puppet.com/docs/pe/2017.3/orchestrator/running_tasks.html) or [Bolt documentation](https://puppet.com/docs/bolt/latest/bolt.html) on how to execute a task. + ## Limitations This module has been tested on: diff --git a/metadata.json b/metadata.json index af8b34721..5a7d6303d 100644 --- a/metadata.json +++ b/metadata.json @@ -1,6 +1,6 @@ { "name": "puppetlabs-mysql", - "version": "5.0.0", + "version": "5.1.0", "author": "Puppet Labs", "summary": "Installs, configures, and manages the MySQL service.", "license": "Apache-2.0", diff --git a/spec/acceptance/sql_task_spec.rb b/spec/acceptance/sql_task_spec.rb new file mode 100644 index 000000000..fcf8ac02e --- /dev/null +++ b/spec/acceptance/sql_task_spec.rb @@ -0,0 +1,23 @@ +# run a test task +require 'spec_helper_acceptance' + +describe 'mysql tasks' do + describe 'execute some sql', if: pe_install? && puppet_version =~ %r{(5\.\d\.\d)} do + pp = <<-EOS + class { 'mysql::server': root_password => 'password' } + mysql::db { 'spec1': + user => 'root1', + password => 'password', + } + EOS + + it "sets up a mysql instance" do + apply_manifest(pp, catch_failures: true) + end + + it 'execute arbitary sql' do + result = run_task(task_name: 'mysql::sql', params: 'sql="show databases;" password=password') + expect_multiple_regexes(result: result, regexes: [%r{information_schema}, %r{performance_schema}, %r{Job completed. 1/1 nodes succeeded}]) + end + end +end diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index df07f773c..b1e6478b4 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -4,8 +4,17 @@ require 'beaker/module_install_helper' require 'beaker/i18n_helper' +def install_bolt_on(hosts) + on(hosts, "/opt/puppetlabs/puppet/bin/gem install --source http://rubygems.delivery.puppetlabs.net bolt -v '> 0.0.1'", acceptable_exit_codes: [0, 1]).stdout +end + +def pe_install? + ENV['PUPPET_INSTALL_TYPE'] =~ %r{pe}i +end + run_puppet_install_helper install_ca_certs unless ENV['PUPPET_INSTALL_TYPE'] =~ %r{pe}i +install_bolt_on(hosts) unless pe_install? install_module_on(hosts) install_module_dependencies_on(hosts) @@ -15,6 +24,38 @@ def puppet_version (on default, puppet('--version')).output.chomp end +DEFAULT_PASSWORD = if default[:hypervisor] == 'vagrant' + 'vagrant' + elsif default[:hypervisor] == 'vcloud' + 'Qu@lity!' + end + +def run_puppet_access_login(user:, password: '~!@#$%^*-/ aZ', lifetime: '5y') + on(master, puppet('access', 'login', '--username', user, '--lifetime', lifetime), stdin: password) +end + +def run_task(task_name:, params: nil, password: DEFAULT_PASSWORD) + if pe_install? + run_puppet_task(task_name: task_name, params: params) + else + run_bolt_task(task_name: task_name, params: params, password: password) + end +end + +def run_bolt_task(task_name:, params: nil, password: DEFAULT_PASSWORD) + on(master, "/opt/puppetlabs/puppet/bin/bolt task run #{task_name} --modules /etc/puppetlabs/code/modules/service --nodes localhost --password #{password} #{params}", acceptable_exit_codes: [0, 1]).stdout # rubocop:disable Metrics/LineLength +end + +def run_puppet_task(task_name:, params: nil) + on(master, puppet('task', 'run', task_name, '--nodes', fact_on(master, 'fqdn'), params.to_s), acceptable_exit_codes: [0, 1]).stdout +end + +def expect_multiple_regexes(result:, regexes:) + regexes.each do |regex| + expect(result).to match(regex) + end +end + RSpec.configure do |c| # Readable test descriptions c.formatter = :documentation @@ -27,6 +68,7 @@ def puppet_version # Configure all nodes in nodeset c.before :suite do + run_puppet_access_login(user: 'admin') if pe_install? hosts.each do |host| # This will be removed, this is temporary to test localisation. if (fact('osfamily') == 'Debian' || fact('osfamily') == 'RedHat') && (puppet_version >= '4.10.5' && puppet_version < '5.2.0') diff --git a/tasks/sql.json b/tasks/sql.json new file mode 100644 index 000000000..81f2e79fc --- /dev/null +++ b/tasks/sql.json @@ -0,0 +1,22 @@ +{ + "description": "Allows you to execute arbitary SQL", + "input_method": "stdin", + "parameters": { + "database": { + "description": "Database to connect to", + "type": "Optional[String[1]]" + }, + "user": { + "description": "The user", + "type": "Optional[String[1]]" + }, + "password": { + "description": "The password", + "type": "Optional[String[1]]" + }, + "sql": { + "description": "The SQL you want to execute", + "type": "String[1]" + } + } +} diff --git a/tasks/sql.rb b/tasks/sql.rb new file mode 100755 index 000000000..c7ddb917a --- /dev/null +++ b/tasks/sql.rb @@ -0,0 +1,29 @@ +#!/opt/puppetlabs/puppet/bin/ruby +require 'json' +require 'open3' +require 'puppet' + +def get(sql, database, user, password) + cmd_string = "mysql -e \"#{sql}\"" + cmd_string << " --database=#{database}" unless database.nil? + cmd_string << " --user=#{user}" unless user.nil? + cmd_string << " --password=#{password}" unless password.nil? + stdout, stderr, status = Open3.capture3(cmd_string) + raise Puppet::Error, _("stderr: '#{stderr}'") if status != 0 + { status: stdout.strip } +end + +params = JSON.parse(STDIN.read) +database = params['database'] +user = params['user'] +password = params['password'] +sql = params['sql'] + +begin + result = get(sql, database, user, password) + puts result.to_json + exit 0 +rescue Puppet::Error => e + puts({ status: 'failure', error: e.message }.to_json) + exit 1 +end