From d2c20990423e6cb09f9a08230643ee68b78cdd3f Mon Sep 17 00:00:00 2001 From: David Joos Date: Tue, 27 Jun 2017 17:24:05 +0100 Subject: [PATCH] New Relic Infrastructure implementation --- .kitchen.yml | 2 + Berksfile | 5 +- README.md | 25 ++++++ attributes/repository.rb | 21 +++++ libraries/helpers.rb | 44 ++++++++++ libraries/matchers.rb | 5 ++ metadata.rb | 2 + providers/agent_infrastructure.rb | 85 +++++++++++++++++++ recipes/infrastructure_agent.rb | 8 ++ resources/agent_infrastructure.rb | 22 +++++ spec/spec_helper.rb | 8 +- spec/unit/agent_infrastructure_spec.rb | 35 ++++++++ spec/unit/agent_java_spec.rb | 4 +- .../agent/infrastructure/newrelic.yml.erb | 19 +++++ .../cookbooks/newrelic_lwrp_test/Berksfile | 10 --- .../recipes/agent_infrastructure.rb | 9 ++ .../serverspec/default_spec.rb | 12 +++ 17 files changed, 299 insertions(+), 17 deletions(-) create mode 100644 providers/agent_infrastructure.rb create mode 100644 recipes/infrastructure_agent.rb create mode 100644 resources/agent_infrastructure.rb create mode 100644 spec/unit/agent_infrastructure_spec.rb create mode 100644 templates/default/agent/infrastructure/newrelic.yml.erb delete mode 100644 test/fixtures/cookbooks/newrelic_lwrp_test/Berksfile create mode 100644 test/fixtures/cookbooks/newrelic_lwrp_test/recipes/agent_infrastructure.rb create mode 100644 test/integration/infrastructure-agent/serverspec/default_spec.rb diff --git a/.kitchen.yml b/.kitchen.yml index e3c1a27c..bf3c545f 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -96,6 +96,8 @@ suites: execute_php5enmod: true - name: server-monitor run_list: "recipe[newrelic_lwrp_test::server_monitor]" + - name: infrastructure-agent + run_list: "recipe[newrelic_lwrp_test::agent_infrastructure]" - name: java-agent run_list: "recipe[newrelic_lwrp_test::agent_java]" attributes: diff --git a/Berksfile b/Berksfile index eca7362e..87f764db 100644 --- a/Berksfile +++ b/Berksfile @@ -1,8 +1,11 @@ source 'https://supermarket.chef.io' -cookbook 'newrelic_lwrp_test', :path => 'test/fixtures/cookbooks/newrelic_lwrp_test' # uninitialized constant Win32 caused by ark-cookbook change in v1.2.0 # (https://github.com/chef-cookbooks/ark/commit/0012c57188ff6e7df2ac69883c029bb88ce001e2) cookbook 'ark', '= 1.1.0' +group :integration do + cookbook 'newrelic_lwrp_test', :path => 'test/fixtures/cookbooks/newrelic_lwrp_test' +end + metadata diff --git a/README.md b/README.md index c7f6fb18..afcae98a 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ The agent installs are being converted into libraries, currently the following a * python_agent * nodejs_agent * dotnet_agent +* infrastructure_agent More information? @@ -565,6 +566,29 @@ newrelic_agent_dotnet 'Install' do end ``` +### `newrelic_agent_infrastructure` +This cookbook includes an LWRP for installing the infrastructure agent + +The `newrelic_agent_infrastructure` resource will handle the requirements to set up the infrastructure agent. + +#### Actions + +- :install - will setup the New Relic Infrastructure agent. + +#### Attribute parameters + +* `'license'` - New Relic license key +* `'version'` - New Relic Infrastructure Agent version to use. To find the current version, check New Relic repo +* `'display_name'` - Overrides the auto-generated hostname for reporting, defaults to nil +* `'logfile'` - To log to another location, provide a full path and file name, defaults to nil +* `'verbose'` - Enables verbose logging for the agent, defaults to 0 +* `'proxy'` - Defaults to nil +* `'template_cookbook'` - Sets cookbook for template, defaults to 'newrelic' +* `'template_source'` - Sets source for template, defaults to 'agent/infrastructure/newrelic.yml.erb' +* `'service_actions'` - The New Relic infrastructure agent service actions, defaults to "`%w(enable start)`" (#starts the service if it's not running and enables it to start at system boot time) +* `'windows_version'` - the Windows version to install, defaults to "1.0.703" +* `'windows_checksum'` - checksum of the (64-bit) Windows version, defaults to "3c9f98325dc484ee8735f01b913803eaef54f06641348b3dd9f3c0b3cd803ace" + ### `newrelic_deployment` This cookbook includes an LWRP for notifying New Relic of a deployment @@ -639,6 +663,7 @@ include the bits and pieces explicitly in a run list: `recipe[newrelic::php_agent]` `recipe[newrelic::python_agent]` `recipe[newrelic::ruby_agent]` +`recipe[newrelic::infrastructure_agent]` ``` 2. change the `node['newrelic']['license']` attribute to your New Relic license keys --- OR --- diff --git a/attributes/repository.rb b/attributes/repository.rb index 6707108d..f676ef87 100644 --- a/attributes/repository.rb +++ b/attributes/repository.rb @@ -15,3 +15,24 @@ when 'rhel', 'fedora' default['newrelic']['repository']['uri'] = 'http://download.newrelic.com/pub/newrelic/el5/$basearch/' end + +# New Relic infrastructure repository +default['newrelic']['repository']['infrastructure']['key'] = 'https://download.newrelic.com/infrastructure_agent/gpg/newrelic-infra.gpg' +default['newrelic']['repository']['infrastructure']['ssl_verify'] = true +case node['platform_family'] +when 'debian' + default['newrelic']['repository']['infrastructure']['uri'] = 'https://download.newrelic.com/infrastructure_agent/linux/apt' + default['newrelic']['repository']['infrastructure']['components'] = ['main'] +when 'rhel', 'fedora' + case node['platform'] + when 'amazon' + case node['platform_version'].to_i + when 2013, 2014, 2015, 2016, 2017 + rhel_version = 6 + end + else + rhel_version = node['platform_version'].to_i + end + + default['newrelic']['repository']['infrastructure']['uri'] = "https://download.newrelic.com/infrastructure_agent/linux/yum/el/#{rhel_version}/x86_64" +end diff --git a/libraries/helpers.rb b/libraries/helpers.rb index a71d0f66..ad93ac61 100644 --- a/libraries/helpers.rb +++ b/libraries/helpers.rb @@ -6,6 +6,10 @@ def newrelic_repository install_newrelic_repo end + def newrelic_repository_infrastructure + install_newrelic_repo_infrastructure + end + def check_license # check license key provided raise 'The NewRelic key is required.' if new_resource.license.nil? @@ -34,6 +38,46 @@ def install_newrelic_repo_rhel end end + def install_newrelic_repo_infrastructure + install_newrelic_repo_infrastructure_debian if node['platform_family'] == 'debian' + install_newrelic_repo_infrastructure_rhel if node['platform_family'] == ('rhel' || 'fedora') + end + + def install_newrelic_repo_infrastructure_debian + apt_repository 'newrelic-infra' do + uri node['newrelic']['repository']['infrastructure']['uri'] + distribution deb_version_to_codename(node['platform_version'].to_i) + components node['newrelic']['repository']['infrastructure']['components'] + key node['newrelic']['repository']['infrastructure']['key'] + arch 'amd64' + end + end + + def install_newrelic_repo_infrastructure_rhel + yum_repository 'newrelic-infra' do + description 'New Relic Infrastructure' + baseurl node['newrelic']['repository']['infrastructure']['uri'] + gpgkey node['newrelic']['repository']['infrastructure']['key'] + sslverify node['newrelic']['repository']['infrastructure']['ssl_verify'] + gpgcheck true + repo_gpgcheck true + end + end + + def deb_version_to_codename(version) + deb_version_to_codename = { + 7 => 'wheezy', + 8 => 'jessie', + 9 => 'stretch', + 10 => 'buster', + 12 => 'precise', + 14 => 'trusty', + 16 => 'xenial' + } + + deb_version_to_codename[version] + end + def directory_exists?(dir) return false unless ::File.exist?(dir) true diff --git a/libraries/matchers.rb b/libraries/matchers.rb index 3bb6d976..4d46ec54 100644 --- a/libraries/matchers.rb +++ b/libraries/matchers.rb @@ -1,6 +1,7 @@ if defined?(ChefSpec) ChefSpec.define_matcher :newrelic_server_monitor ChefSpec.define_matcher :newrelic_agent_php + ChefSpec.define_matcher :newrelic_agent_infrastructure ChefSpec.define_matcher :newrelic_agent_java ChefSpec.define_matcher :newrelic_agent_ruby ChefSpec.define_matcher :newrelic_agent_dotnet @@ -15,6 +16,10 @@ def install_newrelic_agent_php(resource_name) ChefSpec::Matchers::ResourceMatcher.new(:newrelic_agent_php, :install, resource_name) end + def install_newrelic_agent_infrastructure(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:newrelic_agent_infrastructure, :install, resource_name) + end + def install_newrelic_agent_java(resource_name) ChefSpec::Matchers::ResourceMatcher.new(:newrelic_agent_java, :install, resource_name) end diff --git a/metadata.rb b/metadata.rb index 982a2def..e99311d5 100644 --- a/metadata.rb +++ b/metadata.rb @@ -5,6 +5,7 @@ description 'Installs/Configures New Relic' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) version '2.28.1' +chef_version '>= 0.10.0' if respond_to?(:chef_version) %w(debian ubuntu redhat centos fedora scientific amazon windows smartos oracle).each do |os| supports os @@ -22,6 +23,7 @@ recipe 'newrelic::repository', 'Adds the New Relic repository.' recipe 'newrelic::server_monitor_agent', 'Installs & configures the New Relic server monitor agent.' recipe 'newrelic::dotnet_agent', 'Installs New Relic .NET agent.' +recipe 'newrelic::infrastructure_agent', 'Installs New Relic Infrastructure agent.' recipe 'newrelic::java_agent', 'Installs the New Relic Java agent.' recipe 'newrelic::nodejs_agent', 'Installs New Relic Node.js agent.' recipe 'newrelic::php_agent', 'Installs the New Relic PHP agent.' diff --git a/providers/agent_infrastructure.rb b/providers/agent_infrastructure.rb new file mode 100644 index 00000000..9b94aa55 --- /dev/null +++ b/providers/agent_infrastructure.rb @@ -0,0 +1,85 @@ +# +# Cookbook Name:: newrelic +# Provider:: agent_infrastructure +# +# Copyright (c) 2017, David Joos +# + +# include helper methods +include NewRelic::Helpers + +use_inline_resources if defined?(use_inline_resources) + +def whyrun_supported? + true +end + +action :install do + check_license + newrelic_repository_infrastructure + case node['platform_family'] + when 'debian', 'rhel' + install_newrelic_infrastructure_service_linux + when 'windows' + install_newrelic_infrastructure_service_windows + end +end + +def install_newrelic_infrastructure_service_linux + # install the newrelic infrastructure agent + package 'newrelic-infra' do + action new_resource.action + action new_resource.version unless new_resource.version.nil? + end + + # workaround for issue on RHEL family version six + # service is not known to chkconfig + # dribble the issue by not making use of the RHEL service provider + service_provider = if node['platform_family'] == 'rhel' && node['platform_version'] =~ /^6/ + Chef::Provider::Service::Upstart + end + + # setup newrelic infrastructure service + service 'newrelic-infra' do + provider service_provider unless service_provider.nil? + action new_resource.service_actions + end + + # lay down newrelic-infra agent config + template '/etc/newrelic-infra.yml' do + cookbook new_resource.template_cookbook + source new_resource.template_source + owner 'root' + group 'root' + mode '0644' + variables( + :resource => new_resource + ) + notifies :restart, 'service[newrelic-infra]', :delayed + end +end + +def install_newrelic_infrastructure_service_windows + windows_package 'newrelic-infra' do + source "https://download.newrelic.com/infrastructure_agent/windows/newrelic-infra.#{new_resource.windows_version}.msi" + installer_type :msi + version new_resource.windows_version + action new_resource.action + checksum new_resource.windows_checksum + end + + # lay down newrelic-infra agent config + template 'C:\Program Files\New Relic\newrelic-infra\newrelic-infra.yml' do + cookbook new_resource.template_cookbook + source new_resource.template_source + variables( + :resource => new_resource + ) + notifies :restart, 'service[newrelic-infra]', :delayed + end + + # setup newrelic-infra service + service 'newrelic-infra' do + action new_resource.service_actions + end +end diff --git a/recipes/infrastructure_agent.rb b/recipes/infrastructure_agent.rb new file mode 100644 index 00000000..ac6677ca --- /dev/null +++ b/recipes/infrastructure_agent.rb @@ -0,0 +1,8 @@ +# +# Cookbook Name:: newrelic +# Recipe:: infrastructure_agent +# +# Copyright (c) 2017, David Joos +# + +newrelic_agent_infrastructure 'Install' diff --git a/resources/agent_infrastructure.rb b/resources/agent_infrastructure.rb new file mode 100644 index 00000000..3fb0980d --- /dev/null +++ b/resources/agent_infrastructure.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: newrelic +# Resource:: agent_infrastructure +# +# Copyright (c) 2017, David Joos +# + +actions :install +default_action :install + +attribute :license, :kind_of => String, :default => NewRelic.application_monitoring_license(node) +attribute :version, :kind_of => String, :default => nil + +attribute :display_name, :kind_of => String, :default => nil +attribute :logfile, :kind_of => String, :default => nil +attribute :verbose, :kind_of => Integer, :default => 0 +attribute :proxy, :kind_of => String, :default => nil +attribute :template_cookbook, :kind_of => String, :default => 'newrelic' +attribute :template_source, :kind_of => String, :default => 'agent/infrastructure/newrelic.yml.erb' +attribute :service_actions, :kind_of => Array, :default => %w(enable start) +attribute :windows_version, :kind_of => String, :default => '1.0.703' +attribute :windows_checksum, :kind_of => String, :default => '3c9f98325dc484ee8735f01b913803eaef54f06641348b3dd9f3c0b3cd803ace' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ea10fdc2..650ea012 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -18,10 +18,10 @@ def stub_resources end def stub_node_resources(node) - node.set['newrelic']['license'] = '0000ffff0000ffff0000ffff0000ffff0000ffff' - node.set['newrelic']['php_agent']['web_server']['service_name'] = 'httpd' - node.set['newrelic']['php_agent']['php_config'] = '/etc/php.d/newrelic.ini' - node.set['rubygems'] = 'rubygems' + node.override['newrelic']['license'] = '0000ffff0000ffff0000ffff0000ffff0000ffff' + node.override['newrelic']['php_agent']['web_server']['service_name'] = 'httpd' + node.override['newrelic']['php_agent']['php_config'] = '/etc/php.d/newrelic.ini' + node.override['rubygems'] = 'rubygems' end RSpec.configure do |config| diff --git a/spec/unit/agent_infrastructure_spec.rb b/spec/unit/agent_infrastructure_spec.rb new file mode 100644 index 00000000..1c001bf5 --- /dev/null +++ b/spec/unit/agent_infrastructure_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe 'newrelic_lwrp_test::agent_infrastructure' do + before do + stub_resources + end + + context 'Centos' do + let(:chef_run) do + ChefSpec::SoloRunner.new(:log_level => LOG_LEVEL, :platform => 'centos', :version => '6.6', :step_into => ['newrelic_agent_infrastructure']) do |node| + stub_node_resources(node) + end.converge(described_recipe) + end + + it 'installs New Relic Infrastructure agent' do + expect(chef_run).to install_newrelic_agent_infrastructure('Install') + end + + it 'creates a yum_repository for newrelic' do + expect(chef_run).to create_yum_repository('newrelic-infra') + end + + it 'creates newrelic infrastructure yml config template from agent/infrastructure/newrelic.yml.erb' do + expect(chef_run).to render_file('/etc/newrelic-infra.yml').with_content('0000ffff0000ffff0000ffff0000ffff0000ffff') + end + + it 'installs newrelic-infra' do + expect(chef_run).to install_package('newrelic-infra') + end + + it 'enables newrelic-infra service' do + expect(chef_run).to enable_service('newrelic-infra') + end + end +end diff --git a/spec/unit/agent_java_spec.rb b/spec/unit/agent_java_spec.rb index aee220c7..f98b87aa 100644 --- a/spec/unit/agent_java_spec.rb +++ b/spec/unit/agent_java_spec.rb @@ -45,7 +45,7 @@ let(:chef_run) do ChefSpec::Runner.new(:log_level => LOG_LEVEL, :platform => 'centos', :version => '6.6', :step_into => ['newrelic_agent_java']) do |node| stub_node_resources(node) - node.set['newrelic']['java_agent']['class_transformer_config'] = { + node.override['newrelic']['java_agent']['class_transformer_config'] = { 'classloader_blacklist' => %w(class1 class2), 'instrumentation_classes' => { 'wildfly-8' => { 'enabled' => false }, @@ -53,7 +53,7 @@ 'wildfly-8-PORT' => { 'enabled' => false } } } - node.set['newrelic']['java_agent']['agent_action'] = :install + node.override['newrelic']['java_agent']['agent_action'] = :install end.converge(described_recipe) end diff --git a/templates/default/agent/infrastructure/newrelic.yml.erb b/templates/default/agent/infrastructure/newrelic.yml.erb new file mode 100644 index 00000000..f5d41982 --- /dev/null +++ b/templates/default/agent/infrastructure/newrelic.yml.erb @@ -0,0 +1,19 @@ +################### +# Generated by Chef +################### +# +# This file configures the New Relic Infrastructure Agent. + +license_key: <%= @resource.license %> +<% unless @resource.display_name.nil? -%> +display_name: <%= @resource.display_name %> +<% end -%> +<% unless @resource.logfile.nil? -%> +log_file: <%= @resource.logfile %> +<% end -%> +<% unless @resource.verbose.nil? -%> +verbose: <%= @resource.verbose %> +<% end -%> +<% unless @resource.proxy.nil? -%> +proxy: <%= @resource.proxy %> +<% end -%> diff --git a/test/fixtures/cookbooks/newrelic_lwrp_test/Berksfile b/test/fixtures/cookbooks/newrelic_lwrp_test/Berksfile deleted file mode 100644 index 7af24e0d..00000000 --- a/test/fixtures/cookbooks/newrelic_lwrp_test/Berksfile +++ /dev/null @@ -1,10 +0,0 @@ -source 'https://supermarket.chef.io' - -group :integration do - cookbook 'apt' - cookbook 'yum' -end - -cookbook 'newrelic_lwrp_test', :path => 'test/fixtures/cookbooks/newrelic_lwrp_test' - -metadata diff --git a/test/fixtures/cookbooks/newrelic_lwrp_test/recipes/agent_infrastructure.rb b/test/fixtures/cookbooks/newrelic_lwrp_test/recipes/agent_infrastructure.rb new file mode 100644 index 00000000..1dc2fd46 --- /dev/null +++ b/test/fixtures/cookbooks/newrelic_lwrp_test/recipes/agent_infrastructure.rb @@ -0,0 +1,9 @@ +# Encoding: utf-8 +# +# Cookbook Name:: newrelic_lwrp_test +# Recipe:: agent_infrastructure +# +# Copyright (c) 2017, David Joos +# + +newrelic_agent_infrastructure 'Install' diff --git a/test/integration/infrastructure-agent/serverspec/default_spec.rb b/test/integration/infrastructure-agent/serverspec/default_spec.rb new file mode 100644 index 00000000..222b55d0 --- /dev/null +++ b/test/integration/infrastructure-agent/serverspec/default_spec.rb @@ -0,0 +1,12 @@ +require 'spec_helper' + +describe yumrepo('newrelic-infra'), :if => os[:family] == 'redhat' do + it { is_expected.to exist } + it { is_expected.to be_enabled } +end +describe file('/etc/apt/sources.list.d/newrelic-infra.list'), :if => %w(debian ubuntu).include?(os[:family]) do + it { is_expected.to be_file } +end +describe package 'newrelic-infra' do + it { is_expected.to be_installed } +end