diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 5698ed7c..37b9b037 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2017-08-17 14:16:01 +0200 using RuboCop version 0.47.1. +# on 2017-11-26 11:38:53 -0800 using RuboCop version 0.49.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -11,30 +11,17 @@ Lint/NestedMethodDefinition: Exclude: - 'libraries/matchers.rb' -# Offense count: 11 -Metrics/AbcSize: - Max: 39 - -# Offense count: 44 -# Configuration parameters: CountComments, ExcludedMethods. -Metrics/BlockLength: - Max: 203 - # Offense count: 1 -Metrics/PerceivedComplexity: - Max: 13 - -# Offense count: 9 -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: nested, compact -Style/ClassAndModuleChildren: +# Cop supports --auto-correct. +# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles. +# SupportedStyles: predicate, comparison +Style/NumericPredicate: Exclude: - - 'libraries/cli.rb' - - 'libraries/config_helpers.rb' - - 'libraries/endpoints.rb' - - 'libraries/network.rb' - - 'libraries/parse.rb' - - 'libraries/passwords.rb' - - 'libraries/search.rb' - - 'libraries/uri.rb' - - 'libraries/wrappers.rb' + - 'spec/**/*' + - 'libraries/provider_database_mysql_user.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +Style/ZeroLengthPredicate: + Exclude: + - 'libraries/provider_database_mysql_user.rb' diff --git a/Berksfile b/Berksfile index 585cde3d..9972d51a 100644 --- a/Berksfile +++ b/Berksfile @@ -1,4 +1,4 @@ -source "https://supermarket.chef.io" +source 'https://supermarket.chef.io' metadata diff --git a/Rakefile b/Rakefile index fe1a116b..b00d5259 100644 --- a/Rakefile +++ b/Rakefile @@ -1,41 +1,41 @@ -task default: ["test"] +task default: ['test'] -task :test => [:syntax, :lint, :unit] +task test: [:syntax, :lint, :unit] -desc "Vendor the cookbooks in the Berksfile" +desc 'Vendor the cookbooks in the Berksfile' task :berks_prep do - sh %{chef exec berks vendor} + sh %(chef exec berks vendor) end -desc "Run FoodCritic (syntax) tests" +desc 'Run FoodCritic (syntax) tests' task :syntax do - sh %{chef exec foodcritic --exclude spec -f any .} + sh %(chef exec foodcritic --exclude spec -f any .) end -desc "Run RuboCop (lint) tests" +desc 'Run RuboCop (lint) tests' task :lint do - sh %{chef exec cookstyle} + sh %(chef exec cookstyle) end -desc "Run RSpec (unit) tests" -task :unit => :berks_prep do - sh %{chef exec rspec --format documentation} +desc 'Run RSpec (unit) tests' +task unit: :berks_prep do + sh %(chef exec rspec --format documentation) end -desc "Remove the berks-cookbooks directory and the Berksfile.lock" +desc 'Remove the berks-cookbooks directory and the Berksfile.lock' task :clean do rm_rf [ 'berks-cookbooks', - 'Berksfile.lock' + 'Berksfile.lock', ] end -desc "All-in-One Neutron build" -task :integration => :common_integration do +desc 'All-in-One Neutron build' +task integration: :common_integration do # Noop end -desc "Common task used by all cookbooks for integration test" +desc 'Common task used by all cookbooks for integration test' task :common_integration do # Use the berksfile support to make use of the existing patch clones. # Make a sym link from workspace/gate-cookbook-openstack-common-chef-rake-integration diff --git a/attributes/database.rb b/attributes/database.rb index c3432142..6b300cf6 100644 --- a/attributes/database.rb +++ b/attributes/database.rb @@ -109,7 +109,6 @@ default['openstack']['db']['options'] = { mysql: "?charset=#{node['openstack']['db']['charset']['mysql']}", 'percona-cluster' => "?charset=#{node['openstack']['db']['charset']['percona-cluster']}", mariadb: "?charset=#{node['openstack']['db']['charset']['mariadb']}", - postgresql: '', sqlite: '', nosql: '', galera: "?charset=#{node['openstack']['db']['charset']['galera']}", @@ -117,7 +116,7 @@ default['openstack']['db']['options'] = { # platform and DBMS-specific python client packages default['openstack']['db']['python_packages'] = { - postgresql: ['python-psycopg2'], + postgresql: [], sqlite: [], } case node['platform_family'] @@ -128,7 +127,7 @@ when 'rhel' default['openstack']['db']['python_packages']['percona-cluster'] = ['MySQL-python'] default['openstack']['db']['python_packages']['galera'] = ['MySQL-python'] when 'debian' - default['openstack']['db']['service_type'] = 'mysql' + default['openstack']['db']['service_type'] = 'mariadb' default['openstack']['db']['python_packages']['mysql'] = ['python-mysqldb'] default['openstack']['db']['python_packages']['mariadb'] = ['python-mysqldb'] default['openstack']['db']['python_packages']['percona-cluster'] = ['python-mysqldb'] @@ -140,7 +139,7 @@ case node['platform_family'] when 'rhel' default['openstack']['db']['socket'] = '/var/lib/mysql/mysql.sock' when 'debian' - default['openstack']['db']['socket'] = '/run/mysql-default/mysqld.sock' + default['openstack']['db']['socket'] = '/var/run/mysqld/mysqld.sock' end # Database used by the OpenStack services diff --git a/attributes/default.rb b/attributes/default.rb index 0436632f..81ce2b0b 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -292,11 +292,13 @@ default['openstack']['sysctl']['net.ipv4.conf.default.rp_filter'] = 0 case node['platform_family'] when 'rhel' default['openstack']['common']['platform'] = { + 'common_client_packages' => ['python-openstackclient'], 'package_overrides' => '', } when 'debian' default['openstack']['common']['platform'] = { - 'package_overrides' => "-o Dpkg::Options::='--force-confold' -o Dpkg::Options::='--force-confdef'", + 'common_client_packages' => ['python-openstackclient'], + 'package_overrides' => '', } end diff --git a/libraries/endpoints.rb b/libraries/endpoints.rb index 77c00e97..d565e4ce 100644 --- a/libraries/endpoints.rb +++ b/libraries/endpoints.rb @@ -68,8 +68,6 @@ module ::Openstack # Normalize to the SQLAlchemy standard db type identifier case type - when 'pgsql' - type = 'postgresql' when 'mariadb', 'galera', 'percona-cluster' type = 'mysql' end @@ -91,7 +89,7 @@ module ::Openstack # Find the specific endpoint type ('internal', 'admin' or # 'public') for the given service. %w(public internal admin).each do |ep_type| - define_method "#{ep_type}_endpoint" do |service| + define_method("#{ep_type}_endpoint") do |service| uri_from_hash(node['openstack']['endpoints'][ep_type][service]) end end diff --git a/libraries/hashed_password.rb b/libraries/hashed_password.rb new file mode 100644 index 00000000..5fa23a69 --- /dev/null +++ b/libraries/hashed_password.rb @@ -0,0 +1,52 @@ +# +# Author:: Maksim Horbul () +# Cookbook:: openstack-common +# Library:: hashed_password +# +# Copyright:: 2016, Eligible, Inc. +# +# 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. + +# this file is originally from the database cookbook, preserved for legacy +# purposes until the functionality can be refactored into a custom resource. +# Original: https://github.com/chef-boneyard/database + +require File.join(File.dirname(__FILE__), 'resource_mysql_database_user') + +class HashedPassword + # Initializes an object of the MysqlPassword type + # @param [String] hashed_password mysql native hashed password + # @return [MysqlPassword] + def initialize(hashed_password) + @hashed_password = hashed_password + end + + # String representation of the object + # @return [String] hashed password string + def to_s + @hashed_password + end + + module Helpers + # helper method wrappers the string into a MysqlPassword object + # @param [String] hashed_password mysql native hashed password + # @return [MysqlPassword] object + def hashed_password(hashed_password) + HashedPassword.new hashed_password + end + # For backward compatibility, because method was renamed + alias_method :mysql_hashed_password, :hashed_password + end +end + +::Chef::Resource::MysqlDatabaseUser.send(:include, HashedPassword::Helpers) diff --git a/libraries/matchers.rb b/libraries/matchers.rb index 031ce5aa..89cc5824 100644 --- a/libraries/matchers.rb +++ b/libraries/matchers.rb @@ -95,4 +95,68 @@ if defined?(ChefSpec) def create_openstack_common_database(resource_name) ChefSpec::Matchers::ResourceMatcher.new(:openstack_common_database, :create, resource_name) end + + # database + # + ChefSpec.define_matcher :database + + def create_database(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:database, :create, resource_name) + end + + def drop_database(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:database, :drop, resource_name) + end + + def query_database(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:database, :query, resource_name) + end + + # database user + # + ChefSpec.define_matcher :database_user + + def create_database_user(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:database_user, :create, resource_name) + end + + def drop_database_user(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:database_user, :drop, resource_name) + end + + def grant_database_user(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:database_user, :grant, resource_name) + end + + # mysql database + # + ChefSpec.define_matcher :mysql_database + + def create_mysql_database(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_database, :create, resource_name) + end + + def drop_mysql_database(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_database, :drop, resource_name) + end + + def query_mysql_database(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_database, :query, resource_name) + end + + # mysql database user + # + ChefSpec.define_matcher :mysql_database_user + + def create_mysql_database_user(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_database_user, :create, resource_name) + end + + def drop_mysql_database_user(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_database_user, :drop, resource_name) + end + + def grant_mysql_database_user(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_database_user, :grant, resource_name) + end end diff --git a/libraries/passwords.rb b/libraries/passwords.rb index d25c0003..d7e7c815 100644 --- a/libraries/passwords.rb +++ b/libraries/passwords.rb @@ -43,13 +43,13 @@ module ::Openstack def encrypted_secret(bag_name, index) key_path = node['openstack']['secret']['key_path'] ::Chef::Log.info "Loading encrypted databag #{bag_name}.#{index} using key at #{key_path}" - secret = ::Chef::EncryptedDataBagItem.load_secret key_path - ::Chef::EncryptedDataBagItem.load(bag_name, index, secret)[index] + secret = ::Chef::EncryptedDataBagItem.load_secret key_path # ~FC086 + ::Chef::EncryptedDataBagItem.load(bag_name, index, secret)[index] # ~FC086 end def standard_secret(bag_name, index) ::Chef::Log.info "Loading databag #{bag_name}.#{index}" - ::Chef::DataBagItem.load(bag_name, index)[index] + ::Chef::DataBagItem.load(bag_name, index)[index] # ~FC086 end def vault_secret(bag_name, index) diff --git a/libraries/provider_database_mysql.rb b/libraries/provider_database_mysql.rb new file mode 100644 index 00000000..e90739c7 --- /dev/null +++ b/libraries/provider_database_mysql.rb @@ -0,0 +1,170 @@ +# +# Author:: Seth Chisamore () +# Author:: Sean OMeara () +# Copyright:: 2011-2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +# this file is originally from the database cookbook, preserved for legacy +# purposes until the functionality can be refactored into a custom resource. +# Original: https://github.com/chef-boneyard/database + +class Chef + class Provider + class Database + class Mysql < Chef::Provider::LWRPBase + use_inline_resources + + def whyrun_supported? + true + end + + action :create do + # test + schema_present = nil + + begin + test_sql = 'SHOW SCHEMAS;' + Chef::Log.debug("#{new_resource.name}: Performing query [#{test_sql}]") + test_sql_results = test_client.query(test_sql) + test_sql_results.each do |r| + schema_present = true if r['Database'] == new_resource.database_name + end + ensure + close_test_client + end + + # repair + unless schema_present + converge_by "Creating schema '#{new_resource.database_name}'" do + begin + repair_sql = "CREATE SCHEMA IF NOT EXISTS `#{new_resource.database_name}`" + repair_sql += " CHARACTER SET = #{new_resource.encoding}" if new_resource.encoding + repair_sql += " COLLATE = #{new_resource.collation}" if new_resource.collation + Chef::Log.debug("#{new_resource.name}: Performing query [#{repair_sql}]") + repair_client.query(repair_sql) + ensure + close_repair_client + end + end + end + end + + action :drop do + # test + schema_present = nil + + begin + test_sql = 'SHOW SCHEMAS;' + Chef::Log.debug("Performing query [#{test_sql}]") + test_sql_results = test_client.query(test_sql) + test_sql_results.each do |r| + schema_present = true if r['Database'] == new_resource.database_name + end + ensure + close_test_client + end + + # repair + if schema_present + converge_by "Dropping schema '#{new_resource.database_name}'" do + begin + repair_sql = "DROP SCHEMA IF EXISTS `#{new_resource.database_name}`" + Chef::Log.debug("Performing query [#{repair_sql}]") + repair_client.query(repair_sql) + ensure + close_repair_client + end + end + end + end + + action :query do + begin + query_sql = new_resource.sql_query + Chef::Log.debug("Performing query [#{query_sql}]") + query_client.query(query_sql) + ensure + close_query_client + end + end + + private + + def test_client + require 'mysql2' + @test_client ||= + Mysql2::Client.new( + host: new_resource.connection[:host], + socket: new_resource.connection[:socket], + username: new_resource.connection[:username], + password: new_resource.connection[:password], + port: new_resource.connection[:port], + default_file: new_resource.connection[:default_file], + default_group: new_resource.connection[:default_group] + ) + end + + def close_test_client + @test_client.close if @test_client + rescue Mysql2::Error + @test_client = nil + end + + def repair_client + require 'mysql2' + @repair_client ||= + Mysql2::Client.new( + host: new_resource.connection[:host], + socket: new_resource.connection[:socket], + username: new_resource.connection[:username], + password: new_resource.connection[:password], + port: new_resource.connection[:port], + default_file: new_resource.connection[:default_file], + default_group: new_resource.connection[:default_group] + ) + end + + def close_repair_client + @repair_client.close if @repair_client + rescue Mysql2::Error + @repair_client = nil + end + + def query_client + require 'mysql2' + @query_client ||= + Mysql2::Client.new( + host: new_resource.connection[:host], + socket: new_resource.connection[:socket], + username: new_resource.connection[:username], + password: new_resource.connection[:password], + port: new_resource.connection[:port], + default_file: new_resource.connection[:default_file], + default_group: new_resource.connection[:default_group], + flags: new_resource.connection[:flags], + database: new_resource.database_name + ) + end + + def close_query_client + @query_client.close if @query_client + rescue Mysql2::Error + @query_client = nil + end + end + end + end +end diff --git a/libraries/provider_database_mysql_user.rb b/libraries/provider_database_mysql_user.rb new file mode 100644 index 00000000..1b66258c --- /dev/null +++ b/libraries/provider_database_mysql_user.rb @@ -0,0 +1,388 @@ +# +# Author:: Seth Chisamore () +# Author:: Sean OMeara () +# Copyright:: 2011-2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +# this file is originally from the database cookbook, preserved for legacy +# purposes until the functionality can be refactored into a custom resource. +# Original: https://github.com/chef-boneyard/database + +require File.join(File.dirname(__FILE__), 'provider_database_mysql') + +class Chef + class Provider + class Database + class MysqlUser < Chef::Provider::Database::Mysql + use_inline_resources + + def whyrun_supported? + true + end + + action :create do + # test + user_present = nil + begin + test_sql = "SELECT User,Host from mysql.user WHERE User='#{new_resource.username}' AND Host='#{new_resource.host}';" + test_sql_results = test_client.query(test_sql) + test_sql_results.each do |r| + user_present = true if r['User'] == new_resource.username + end + + password_up_to_date = !user_present || test_user_password + ensure + close_test_client + end + + # repair + unless user_present + converge_by "Creating user '#{new_resource.username}'@'#{new_resource.host}'" do + begin + repair_sql = "CREATE USER '#{new_resource.username}'@'#{new_resource.host}'" + if new_resource.password + repair_sql += ' IDENTIFIED BY ' + repair_sql += if new_resource.password.is_a?(HashedPassword) + " PASSWORD '#{new_resource.password}'" + else + " '#{new_resource.password}'" + end + end + repair_client.query(repair_sql) + ensure + close_repair_client + end + end + end + + update_user_password unless password_up_to_date + end + + action :drop do + # test + user_present = nil + begin + test_sql = 'SELECT User,Host' + test_sql += ' from mysql.user' + test_sql += " WHERE User='#{new_resource.username}'" + test_sql += " AND Host='#{new_resource.host}'" + test_sql_results = test_client.query test_sql + test_sql_results.each do |r| + user_present = true if r['User'] == new_resource.username + end + ensure + close_test_client + end + + # repair + if user_present + converge_by "Dropping user '#{new_resource.username}'@'#{new_resource.host}'" do + begin + repair_sql = 'DROP USER' + repair_sql += " '#{new_resource.username}'@'#{new_resource.host}'" + repair_client.query repair_sql + ensure + close_repair_client + end + end + end + end + + action :grant do + # gratuitous function + def ishash? + return true if /(\A\*[0-9A-F]{40}\z)/i =~ new_resource.password + end + + db_name = new_resource.database_name ? "`#{new_resource.database_name}`" : '*' + tbl_name = new_resource.table ? new_resource.table : '*' + test_table = new_resource.database_name ? 'mysql.db' : 'mysql.user' + + # Test + incorrect_privs = nil + begin + test_sql = "SELECT * from #{test_table}" + test_sql += " WHERE User='#{new_resource.username}'" + test_sql += " AND Host='#{new_resource.host}'" + test_sql += " AND Db='#{new_resource.database_name}'" if new_resource.database_name + test_sql_results = test_client.query test_sql + + incorrect_privs = true if test_sql_results.size.zero? + # These should all be 'Y' + test_sql_results.each do |r| + desired_privs.each do |p| + key = p.to_s.capitalize.tr(' ', '_').gsub('Replication_', 'Repl_').gsub('Create_temporary_tables', 'Create_tmp_table').gsub('Show_databases', 'Show_db') + key = "#{key}_priv" + incorrect_privs = true if r[key] != 'Y' + end + end + + password_up_to_date = incorrect_privs || test_user_password + ensure + close_test_client + end + + # Repair + if incorrect_privs + converge_by "Granting privs for '#{new_resource.username}'@'#{new_resource.host}'" do + begin + repair_sql = "GRANT #{new_resource.privileges.join(',')}" + repair_sql += " ON #{db_name}.#{tbl_name}" + repair_sql += " TO '#{new_resource.username}'@'#{new_resource.host}' IDENTIFIED BY" + repair_sql += if new_resource.password.is_a?(HashedPassword) + " PASSWORD '#{new_resource.password}'" + else + " '#{new_resource.password}'" + end + repair_sql += ' REQUIRE SSL' if new_resource.require_ssl + repair_sql += ' REQUIRE X509' if new_resource.require_x509 + repair_sql += ' WITH GRANT OPTION' if new_resource.grant_option + + redacted_sql = redact_password(repair_sql, new_resource.password) + Chef::Log.debug("#{@new_resource}: granting with sql [#{redacted_sql}]") + repair_client.query(repair_sql) + repair_client.query('FLUSH PRIVILEGES') + ensure + close_repair_client + end + end + else + # The grants are correct, but perhaps the password needs updating? + update_user_password unless password_up_to_date + end + end + + action :revoke do + db_name = new_resource.database_name ? "`#{new_resource.database_name}`" : '*' + tbl_name = new_resource.table ? new_resource.table : '*' + test_table = new_resource.database_name ? 'mysql.db' : 'mysql.user' + + privs_to_revoke = [] + begin + test_sql = "SELECT * from #{test_table}" + test_sql += " WHERE User='#{new_resource.username}'" + test_sql += " AND Host='#{new_resource.host}'" + test_sql += " AND Db='#{new_resource.database_name}'" if new_resource.database_name + test_sql_results = test_client.query test_sql + + # These should all be 'N' + test_sql_results.each do |r| + desired_privs.each do |p| + key = p.to_s.capitalize.tr(' ', '_').gsub('Replication_', 'Repl_').gsub('Create_temporary_tables', 'Create_tmp_table').gsub('Show_databases', 'Show_db') + key = "#{key}_priv" + privs_to_revoke << revokify_key(p) if r[key] != 'N' + end + end + ensure + close_test_client + end + + # Repair + unless privs_to_revoke.empty? + converge_by "Revoking privs for '#{new_resource.username}'@'#{new_resource.host}'" do + begin + revoke_statement = "REVOKE #{privs_to_revoke.join(',')}" + revoke_statement += " ON #{db_name}.#{tbl_name}" + revoke_statement += " FROM `#{@new_resource.username}`@`#{@new_resource.host}` " + + Chef::Log.debug("#{@new_resource}: revoking access with statement [#{revoke_statement}]") + repair_client.query(revoke_statement) + repair_client.query('FLUSH PRIVILEGES') + ensure + close_repair_client + end + end + end + end + + private + + def desired_privs + possible_global_privs = [ + :select, + :insert, + :update, + :delete, + :create, + :drop, + :references, + :index, + :alter, + :create_tmp_table, + :lock_tables, + :create_view, + :show_view, + :create_routine, + :alter_routine, + :execute, + :event, + :trigger, + :reload, + :shutdown, + :process, + :file, + :show_db, + :super, + :repl_slave, + :repl_client, + :create_user, + ] + possible_db_privs = [ + :select, + :insert, + :update, + :delete, + :create, + :drop, + :references, + :index, + :alter, + :create_tmp_table, + :lock_tables, + :create_view, + :show_view, + :create_routine, + :alter_routine, + :execute, + :event, + :trigger, + ] + + # convert :all to the individual db or global privs + desired_privs = if new_resource.privileges == [:all] && new_resource.database_name + possible_db_privs + elsif new_resource.privileges == [:all] + possible_global_privs + else + new_resource.privileges + end + desired_privs + end + + def test_client + require 'mysql2' + @test_client ||= + Mysql2::Client.new( + host: new_resource.connection[:host], + socket: new_resource.connection[:socket], + username: new_resource.connection[:username], + password: new_resource.connection[:password], + port: new_resource.connection[:port], + default_file: new_resource.connection[:default_file], + default_group: new_resource.connection[:default_group] + ) + end + + def close_test_client + @test_client.close if @test_client + rescue Mysql2::Error + @test_client = nil + end + + def repair_client + require 'mysql2' + @repair_client ||= + Mysql2::Client.new( + host: new_resource.connection[:host], + socket: new_resource.connection[:socket], + username: new_resource.connection[:username], + password: new_resource.connection[:password], + port: new_resource.connection[:port], + default_file: new_resource.connection[:default_file], + default_group: new_resource.connection[:default_group] + ) + end + + def close_repair_client + @repair_client.close if @repair_client + rescue Mysql2::Error + @repair_client = nil + end + + def revokify_key(key) + return '' if key.nil? + + # Some keys need to be translated as outlined by the table found here: + # https://dev.mysql.com/doc/refman/5.7/en/privileges-provided.html + result = key.to_s.downcase.tr('_', ' ').gsub('repl ', 'replication ').gsub('create tmp table', 'create temporary tables').gsub('show db', 'show databases') + result = result.gsub(/ priv$/, '') + result + end + + def test_user_password + if database_has_password_column(test_client) + test_sql = 'SELECT User,Host,Password FROM mysql.user ' \ + "WHERE User='#{new_resource.username}' AND Host='#{new_resource.host}' " + test_sql += if new_resource.password.is_a? HashedPassword + "AND Password='#{new_resource.password}'" + else + "AND Password=PASSWORD('#{new_resource.password}')" + end + else + test_sql = 'SELECT User,Host,authentication_string FROM mysql.user ' \ + "WHERE User='#{new_resource.username}' AND Host='#{new_resource.host}' " \ + "AND plugin='mysql_native_password' " + test_sql += if new_resource.password.is_a? HashedPassword + "AND authentication_string='#{new_resource.password}'" + else + "AND authentication_string=PASSWORD('#{new_resource.password}')" + end + end + test_client.query(test_sql).size > 0 + end + + def update_user_password + converge_by "Updating password of user '#{new_resource.username}'@'#{new_resource.host}'" do + begin + if database_has_password_column(repair_client) + repair_sql = "SET PASSWORD FOR '#{new_resource.username}'@'#{new_resource.host}' = " + repair_sql += if new_resource.password.is_a? HashedPassword + "'#{new_resource.password}'" + else + " PASSWORD('#{new_resource.password}')" + end + else + # "ALTER USER is now the preferred statement for assigning passwords." + # http://dev.mysql.com/doc/refman/5.7/en/set-password.html + repair_sql = "ALTER USER '#{new_resource.username}'@'#{new_resource.host}' " + repair_sql += if new_resource.password.is_a? HashedPassword + "IDENTIFIED WITH mysql_native_password AS '#{new_resource.password}'" + else + "IDENTIFIED BY '#{new_resource.password}'" + end + end + repair_client.query(repair_sql) + ensure + close_repair_client + end + end + end + + def database_has_password_column(client) + client.query('SHOW COLUMNS FROM mysql.user WHERE Field="Password"').size > 0 + end + + def redact_password(query, password) + if password.nil? || password == '' + query + else + query.gsub(password, 'REDACTED') + end + end + end + end + end +end diff --git a/libraries/resource_database.rb b/libraries/resource_database.rb new file mode 100644 index 00000000..d8ec8926 --- /dev/null +++ b/libraries/resource_database.rb @@ -0,0 +1,122 @@ +# +# Author:: Seth Chisamore () +# Copyright:: 2011-2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +# this file is originally from the database cookbook, preserved for legacy +# purposes until the functionality can be refactored into a custom resource. +# Original: https://github.com/chef-boneyard/database + +require 'chef/resource' + +class Chef + class Resource + class Database < Chef::Resource + def initialize(name, run_context = nil) + super + @resource_name = :database + @database_name = name + @allowed_actions.push(:create, :drop, :query) + @action = :create + end + + def database_name(arg = nil) + set_or_return( + :database_name, + arg, + kind_of: String + ) + end + + def connection(arg = nil) + set_or_return( + :connection, + arg, + required: true + ) + end + + def sql(arg = nil, &block) + arg ||= block + set_or_return( + :sql, + arg, + kind_of: [String, Proc] + ) + end + + def sql_query + if sql.is_a?(Proc) + sql.call + else + sql + end + end + + def template(arg = nil) + set_or_return( + :template, + arg, + kind_of: String, + default: 'DEFAULT' + ) + end + + def collation(arg = nil) + set_or_return( + :collation, + arg, + kind_of: String + ) + end + + def encoding(arg = nil) + set_or_return( + :encoding, + arg, + kind_of: String, + default: 'DEFAULT' + ) + end + + def tablespace(arg = nil) + set_or_return( + :tablespace, + arg, + kind_of: String, + default: 'DEFAULT' + ) + end + + def connection_limit(arg = nil) + set_or_return( + :connection_limit, + arg, + kind_of: String, + default: '-1' + ) + end + + def owner(arg = nil) + set_or_return( + :owner, + arg, + kind_of: String + ) + end + end + end +end diff --git a/libraries/resource_database_user.rb b/libraries/resource_database_user.rb new file mode 100644 index 00000000..f2614e98 --- /dev/null +++ b/libraries/resource_database_user.rb @@ -0,0 +1,118 @@ +# +# Author:: Seth Chisamore () +# Copyright:: 2011-2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +# this file is originally from the database cookbook, preserved for legacy +# purposes until the functionality can be refactored into a custom resource. +# Original: https://github.com/chef-boneyard/database + +require File.join(File.dirname(__FILE__), 'resource_database') + +class Chef + class Resource + class DatabaseUser < Chef::Resource::Database + def initialize(name, run_context = nil) + super + @resource_name = :database_user + @username = name + + @database_name = nil + @table = nil + @host = 'localhost' + @privileges = [:all] + @grant_option = false + @require_ssl = false + @require_x509 = false + + @allowed_actions.push(:create, :drop, :grant, :revoke) + @action = :create + end + + def database_name(arg = nil) + set_or_return( + :database_name, + arg, + kind_of: String + ) + end + + def username(arg = nil) + set_or_return( + :username, + arg, + kind_of: String + ) + end + + def require_ssl(arg = nil) + set_or_return( + :require_ssl, + arg, + kind_of: [TrueClass, FalseClass] + ) + end + + def require_x509(arg = nil) + set_or_return( + :require_x509, + arg, + kind_of: [TrueClass, FalseClass] + ) + end + + def password(arg = nil) + set_or_return( + :password, + arg, + kind_of: String + ) + end + + def table(arg = nil) + set_or_return( + :table, + arg, + kind_of: String + ) + end + + def host(arg = nil) + set_or_return( + :host, + arg, + kind_of: String + ) + end + + def privileges(arg = nil) + set_or_return( + :privileges, + arg, + kind_of: Array + ) + end + + def grant_option(arg = nil) + set_or_return( + :grant_option, + arg, + kind_of: [TrueClass, FalseClass], default: false + ) + end + end + end +end diff --git a/libraries/resource_mysql_database.rb b/libraries/resource_mysql_database.rb new file mode 100644 index 00000000..7b452fc9 --- /dev/null +++ b/libraries/resource_mysql_database.rb @@ -0,0 +1,36 @@ +# +# Author:: Seth Chisamore () +# Author:: Sean OMeara () +# Copyright:: 2011-2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +# this file is originally from the database cookbook, preserved for legacy +# purposes until the functionality can be refactored into a custom resource. +# Original: https://github.com/chef-boneyard/database + +require File.join(File.dirname(__FILE__), 'provider_database_mysql') + +class Chef + class Resource + class MysqlDatabase < Chef::Resource::Database + def initialize(name, run_context = nil) + super + @resource_name = :mysql_database + @provider = Chef::Provider::Database::Mysql + end + end + end +end diff --git a/libraries/resource_mysql_database_user.rb b/libraries/resource_mysql_database_user.rb new file mode 100644 index 00000000..700edbed --- /dev/null +++ b/libraries/resource_mysql_database_user.rb @@ -0,0 +1,44 @@ +# +# Author:: Seth Chisamore () +# Copyright:: 2011-2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +# this file is originally from the database cookbook, preserved for legacy +# purposes until the functionality can be refactored into a custom resource. +# Original: https://github.com/chef-boneyard/database + +require File.join(File.dirname(__FILE__), 'resource_database_user') +require File.join(File.dirname(__FILE__), 'provider_database_mysql_user') + +class Chef + class Resource + class MysqlDatabaseUser < Chef::Resource::DatabaseUser + def initialize(name, run_context = nil) + super + @resource_name = :mysql_database_user + @provider = Chef::Provider::Database::MysqlUser + end + + def password(arg = nil) + set_or_return( + :password, + arg, + kind_of: [String, HashedPassword] + ) + end + end + end +end diff --git a/metadata.rb b/metadata.rb index 4e5ccdc9..d2c62b3d 100644 --- a/metadata.rb +++ b/metadata.rb @@ -1,7 +1,7 @@ name 'openstack-common' maintainer 'openstack-chef' maintainer_email 'openstack-dev@lists.openstack.org' -license 'Apache 2.0' +license 'Apache-2.0' description 'Common OpenStack attributes, libraries and recipes.' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) version '16.0.0' @@ -14,14 +14,12 @@ recipe 'openstack-common::sysctl', 'Configures sysctl settings' supports os end -depends 'apt', '~> 5.0' -depends 'database', '~> 6.1' depends 'etcd', '~> 3.0' depends 'mariadb', '~> 1.5' +depends 'memcached', '~> 4.1' depends 'mysql', '~> 8.2' -depends 'yum', '~> 3.13' -depends 'yum-epel', '~> 2.0' depends 'poise-python', '~> 1.5' +depends 'selinux' issues_url 'https://launchpad.net/openstack-chef' if respond_to?(:issues_url) source_url 'https://github.com/openstack/cookbook-openstack-common' if respond_to?(:source_url) diff --git a/providers/database.rb b/providers/database.rb index 0bd36f2d..f27730de 100644 --- a/providers/database.rb +++ b/providers/database.rb @@ -38,10 +38,6 @@ end def db_types case @db_type - when 'postgresql', 'pgsql' - @db_prov = ::Chef::Provider::Database::Postgresql - @user_prov = ::Chef::Provider::Database::PostgresqlUser - @super_user = 'postgres' when 'mysql', 'mariadb', 'percona-cluster', 'galera' @db_prov = ::Chef::Provider::Database::Mysql @user_prov = ::Chef::Provider::Database::MysqlUser diff --git a/recipes/client.rb b/recipes/client.rb index b0f6acfd..72094215 100644 --- a/recipes/client.rb +++ b/recipes/client.rb @@ -19,4 +19,10 @@ # limitations under the License. # -package 'python-openstackclient' +platform_options = node['openstack']['common']['platform'] +platform_options['common_client_packages'].each do |pkg| + package pkg do + options platform_options['package_overrides'] + action :upgrade + end +end diff --git a/recipes/default.rb b/recipes/default.rb index 9bdb7bac..72e2a90c 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -22,9 +22,26 @@ platform_options = node['openstack']['common']['platform'] case node['platform_family'] when 'debian' if node['openstack']['apt']['update_apt_cache'] - # Ensure we've done an apt-update first or packages won't be found. - include_recipe 'apt' + # update the apt cache before installing anything + apt_update 'default' do + action :update + end end + + # populate the necessary apt options + # by default, do not overwrite existing configuration files + # this alleviates the need to populate package_overrides in every cookbook + file '/etc/apt/apt.conf.d/confdef' do + owner 'root' + group 'root' + mode 00644 + content 'Dpkg::Options { + "--force-confdef"; + "--force-confold"; + }' + action :create + end + package 'ubuntu-cloud-keyring' do options platform_options['package_overrides'] action :upgrade @@ -36,6 +53,7 @@ when 'debian' uri node['openstack']['apt']['uri'] distribution "#{node['lsb']['codename']}-updates/#{node['openstack']['release']}" components apt_components + cache_rebuild true # update the cache after a new repo is added end # add in the proposed repo, but only if we're in development @@ -50,19 +68,18 @@ when 'debian' distribution "#{node['lsb']['codename']}-proposed/#{node['openstack']['release']}" components apt_components action proposed_action + cache_rebuild true # update the cache after a new repo is added end end -when 'rhel' - include_recipe 'yum' if node['openstack']['yum']['update_yum_cache'] - if node['openstack']['yum']['rdo_enabled'] - repo_action = :add - include_recipe 'yum-epel' - elsif FileTest.exist? "/etc/yum.repos.d/RDO-#{node['openstack']['release']}.repo" - repo_action = :remove - else - repo_action = :nothing - end +when 'rhel' + repo_action = if node['openstack']['yum']['rdo_enabled'] + :add + elsif FileTest.exist? "/etc/yum.repos.d/RDO-#{node['openstack']['release']}.repo" + :remove + else + :nothing + end yum_repository "RDO-#{node['openstack']['release']}" do description "OpenStack RDO repo for #{node['openstack']['release']}" diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb index 3da3ec89..f745a92d 100644 --- a/spec/cli_spec.rb +++ b/spec/cli_spec.rb @@ -23,9 +23,8 @@ describe 'openstack-common::default' do } end it 'returns cli enviroment' do - allow(subject).to receive(:get_password) - .with('user', 'name') - .and_return('pass') + allow(subject).to receive(:get_password).with( + 'user', 'name').and_return('pass') expect( subject.openstack_command_env('name', 'project', 'default', 'default') @@ -112,9 +111,10 @@ describe 'openstack-common::default' do 'OS_AUTH_URL' => 'http://127.0.0.1:35357/v3', 'OS_IDENTITY_API_VERSION' => 3, } - allow(subject).to receive(:openstack_command).with('openstack', 'user list', env, {}) - allow(subject).to receive(:prettytable_to_array) - .and_return([{ 'name' => 'user1', 'id' => '1234567890ABCDEFGH' }]) + allow(subject).to receive(:openstack_command).with( + 'openstack', 'user list', env, {}) + allow(subject).to receive(:prettytable_to_array).and_return( + [{ 'name' => 'user1', 'id' => '1234567890ABCDEFGH' }]) result = subject.identity_uuid('user', 'name', 'user1', env) expect(result).to eq('1234567890ABCDEFGH') @@ -135,17 +135,19 @@ describe 'openstack-common::default' do end it 'runs glance command to query valid id' do - allow(subject).to receive(:openstack_command).with('openstack', 'image list', :env, {}) - allow(subject).to receive(:prettytable_to_array) - .and_return([{ 'ID' => '87f38e15-9737-46cc-a612-7c67ee29a24f', 'Name' => 'cirros' }]) + allow(subject).to receive(:openstack_command).with( + 'openstack', 'image list', :env, {}) + allow(subject).to receive(:prettytable_to_array).and_return( + [{ 'ID' => '87f38e15-9737-46cc-a612-7c67ee29a24f', 'Name' => 'cirros' }]) result = subject.image_id('cirros', :env) expect(result).to eq('87f38e15-9737-46cc-a612-7c67ee29a24f') end it 'runs glance command to query invalid id' do - allow(subject).to receive(:openstack_command).with('openstack', 'image list', :env, {}) - .and_raise("No image with a name or ID of 'test' exists. (1)") + allow(subject).to receive(:openstack_command).with( + 'openstack', 'image list', :env, {}).and_raise( + "No image with a name or ID of 'test' exists. (1)") expect { subject.image_id('test', :env) }.to raise_error(RuntimeError) end @@ -163,9 +165,10 @@ describe 'openstack-common::default' do 'OS_AUTH_URL' => 'http://127.0.0.1:35357/v3', 'OS_IDENTITY_API_VERSION' => 3, } - allow(subject).to receive(:openstack_command).with('openstack', 'network list', env, {}) - allow(subject).to receive(:prettytable_to_array) - .and_return([{ 'name' => 'net1', 'id' => '1234567890ABCDEFGH' }]) + allow(subject).to receive(:openstack_command).with( + 'openstack', 'network list', env, {}) + allow(subject).to receive(:prettytable_to_array).and_return( + [{ 'name' => 'net1', 'id' => '1234567890ABCDEFGH' }]) result = subject.network_uuid('network', 'name', 'net1', env) expect(result).to eq('1234567890ABCDEFGH') diff --git a/spec/client_spec.rb b/spec/client_spec.rb index 15c1ab9e..fff12119 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -10,7 +10,7 @@ describe 'openstack-common::client' do end it do - expect(chef_run).to install_package('python-openstackclient') + expect(chef_run).to upgrade_package('python-openstackclient') end end end diff --git a/spec/database_provider_spec.rb b/spec/database_provider_spec.rb index 4a575aaa..45677b95 100644 --- a/spec/database_provider_spec.rb +++ b/spec/database_provider_spec.rb @@ -30,7 +30,7 @@ describe 'test-openstack-common-database::default' do expect(chef_run).to create_database('create database service_db') .with( provider: ::Chef::Provider::Database::Mysql, - connection: { host: 'localhost123', port: 3306, username: 'root', password: 'root_pass', socket: '/run/mysql-default/mysqld.sock' }, + connection: { host: 'localhost123', port: 3306, username: 'root', password: 'root_pass', socket: '/var/run/mysqld/mysqld.sock' }, database_name: 'service_db', encoding: 'utf8' ) @@ -41,7 +41,7 @@ describe 'test-openstack-common-database::default' do expect(chef_run).to create_database('create database service_db') .with( provider: ::Chef::Provider::Database::Mysql, - connection: { host: 'localhost', port: 3306, username: 'root', password: 'root_pass', socket: '/run/mysql-default/mysqld.sock' }, + connection: { host: 'localhost', port: 3306, username: 'root', password: 'root_pass', socket: '/var/run/mysqld/mysqld.sock' }, database_name: 'service_db', encoding: 'utf8' ) @@ -51,7 +51,7 @@ describe 'test-openstack-common-database::default' do expect(chef_run).to create_database_user('create database user db_user') .with( provider: ::Chef::Provider::Database::MysqlUser, - connection: { host: 'localhost', port: 3306, username: 'root', password: 'root_pass', socket: '/run/mysql-default/mysqld.sock' }, + connection: { host: 'localhost', port: 3306, username: 'root', password: 'root_pass', socket: '/var/run/mysqld/mysqld.sock' }, username: 'db_user', password: 'db_pass' ) @@ -61,7 +61,7 @@ describe 'test-openstack-common-database::default' do expect(chef_run).to grant_database_user('grant database user db_user') .with( provider: ::Chef::Provider::Database::MysqlUser, - connection: { host: 'localhost', port: 3306, username: 'root', password: 'root_pass', socket: '/run/mysql-default/mysqld.sock' }, + connection: { host: 'localhost', port: 3306, username: 'root', password: 'root_pass', socket: '/var/run/mysqld/mysqld.sock' }, username: 'db_user', password: 'db_pass', database_name: 'service_db', diff --git a/spec/default-redhat_spec.rb b/spec/default-redhat_spec.rb index ad873344..974ba5f9 100644 --- a/spec/default-redhat_spec.rb +++ b/spec/default-redhat_spec.rb @@ -19,7 +19,6 @@ describe 'openstack-common::default' do before do node.set['openstack']['yum']['rdo_enabled'] = true node.set['openstack']['yum']['gpgcheck'] = true - node.set['openstack']['yum']['update_yum_cache'] = true end it 'adds RDO yum repository' do @@ -29,12 +28,12 @@ describe 'openstack-common::default' do .with(gpgcheck: true) end - it 'includes yum recipe' do - expect(chef_run).to include_recipe('yum') + it 'does not include yum recipe' do + expect(chef_run).to_not include_recipe('yum') end - it 'includes yum-epel recipe' do - expect(chef_run).to include_recipe('yum-epel') + it 'does not include yum-epel recipe' do + expect(chef_run).to_not include_recipe('yum-epel') end end @@ -49,8 +48,8 @@ describe 'openstack-common::default' do .with(gpgcheck: false) end - it 'includes yum-epel recipe' do - expect(chef_run).to include_recipe('yum-epel') + it 'does not include yum-epel recipe' do + expect(chef_run).to_not include_recipe('yum-epel') end end diff --git a/spec/default_spec.rb b/spec/default_spec.rb index bde978e5..2abf8280 100644 --- a/spec/default_spec.rb +++ b/spec/default_spec.rb @@ -10,13 +10,13 @@ describe 'openstack-common::default' do runner.converge(described_recipe) end - it 'includes apt for apt-get update' do - node.set['openstack']['apt']['update_apt_cache'] = 'true' - expect(chef_run).to include_recipe 'apt' + it 'does not include apt for apt-get update' do + expect(chef_run).to_not include_recipe 'apt' end - it 'doesnt include apt for apt-get update' do - expect(chef_run).to_not include_recipe 'apt' + it 'updates apt cache before installing packages' do + node.override['openstack']['apt']['update_apt_cache'] = true + expect(chef_run).to update_apt_update 'default' end it 'upgrades ubuntu-cloud-keyring package' do @@ -30,7 +30,8 @@ describe 'openstack-common::default' do expect(chef_run).to add_apt_repository('openstack-ppa').with( uri: 'http://ubuntu-cloud.archive.canonical.com/ubuntu', distribution: 'xenial-updates/pike', - components: ['main'] + components: ['main'], + cache_rebuild: true ) end @@ -47,7 +48,8 @@ describe 'openstack-common::default' do expect(chef_run).to add_apt_repository('openstack-ppa-proposed').with( uri: 'http://ubuntu-cloud.archive.canonical.com/ubuntu', distribution: 'xenial-proposed/pike', - components: ['main'] + components: ['main'], + cache_rebuild: true ) end diff --git a/spec/password_spec.rb b/spec/password_spec.rb index 2f6ba4a0..ee3eee67 100644 --- a/spec/password_spec.rb +++ b/spec/password_spec.rb @@ -16,8 +16,10 @@ describe 'openstack-common::default' do describe '#secret' do it 'returns databag' do value = { 'nova' => 'this' } - allow(Chef::EncryptedDataBagItem).to receive(:load_secret).with('/etc/chef/openstack_data_bag_secret').and_return('secret') - allow(Chef::EncryptedDataBagItem).to receive(:load).with('passwords', 'nova', 'secret').and_return(value) + allow(Chef::EncryptedDataBagItem).to receive(:load_secret).with( + '/etc/chef/openstack_data_bag_secret').and_return('secret') + allow(Chef::EncryptedDataBagItem).to receive(:load).with( + 'passwords', 'nova', 'secret').and_return(value) expect(subject.secret('passwords', 'nova')).to eq('this') end end @@ -27,7 +29,8 @@ describe 'openstack-common::default' do node.set['openstack']['databag_type'] = 'vault' end it 'returns the data from a chef vault item' do - allow(ChefVault::Item).to receive(:load).with('vault_passwords', 'nova') + allow(ChefVault::Item).to receive(:load) + .with('vault_passwords', 'nova') .and_return('nova' => 'novapassword') expect(subject.secret('passwords', 'nova')).to eq('novapassword') end @@ -37,8 +40,10 @@ describe 'openstack-common::default' do %w(service db user).each do |type| it "returns databag value for #{type}" do value = { 'nova' => 'this' } - allow(Chef::EncryptedDataBagItem).to receive(:load_secret).with('/etc/chef/openstack_data_bag_secret').and_return('secret') - allow(Chef::EncryptedDataBagItem).to receive(:load).with("#{type}_passwords", 'nova', 'secret').and_return(value) + allow(Chef::EncryptedDataBagItem).to receive(:load_secret).with( + '/etc/chef/openstack_data_bag_secret').and_return('secret') + allow(Chef::EncryptedDataBagItem).to receive(:load).with( + "#{type}_passwords", 'nova', 'secret').and_return(value) expect(subject.get_password(type, 'nova')).to eq('this') end end @@ -65,7 +70,8 @@ describe 'openstack-common::default' do describe '#secret' do it 'returns databag' do value = { 'nova' => 'this' } - allow(Chef::DataBagItem).to receive(:load).with('passwords', 'nova').and_return(value) + allow(Chef::DataBagItem).to receive(:load) + .with('passwords', 'nova').and_return(value) expect(subject.secret('passwords', 'nova')).to eq('this') end end @@ -74,7 +80,8 @@ describe 'openstack-common::default' do %w(service db user).each do |type| it "returns databag value for #{type}" do value = { 'nova' => 'this' } - allow(Chef::DataBagItem).to receive(:load).with("#{type}_passwords", 'nova').and_return(value) + allow(Chef::DataBagItem).to receive(:load).with( + "#{type}_passwords", 'nova').and_return(value) expect(subject.get_password(type, 'nova')).to eq('this') end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ec322162..bbbfdf96 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,7 +12,7 @@ UBUNTU_OPTS = { }.freeze REDHAT_OPTS = { platform: 'redhat', - version: '7.1', + version: '7.3', log_level: LOG_LEVEL, }.freeze # We set a default platform for non-platform specific test cases