puppet matching multiple agent hostnames to params.pp data structure - wso2

I have a module called appserver in my puppet modules.
In that module manifests I have a params.pp file which is inherited by init.pp file.
In params.pp file I have the following data structure.
$servers = {
appserver-mgr => { axis2 => {subDomain => 'mgt',},
carbon => {subDomain => 'mgt',},
serverOptions => '-Dsetup',
server_home => $carbon_home, },
appserver-wkr => { axis2 => {subDomain => 'worker', members => ['appserver-mgr2-ip']},
carbon => {subDomain => 'worker',},
serverOptions => '-DworkerNode=true',
server_home => $carbon_home, },
}
In my init.pp file I'm filling my templates as follows using the said data structure.
define fill_templates($axis2, $carbon, $clustering, $serverOptions, $server_home) {
$ipAdd = $::ipaddress
$hostName = $::hostname
if $hostName == "${name}" {
notify {"host name match found for $hostName for $ipAdd":}
file { "${server_home}/repository/conf/axis2/axis2.xml":
ensure => file,
content => template('appserver/axis2.xml.erb'),
}
->
file { "${server_home}/repository/conf/carbon.xml":
ensure => file,
content => template('appserver/carbon.xml.erb'),
}
->
file { "${server_home}/repository/conf/tomcat/catalina-server.xml":
ensure => file,
content => template('appserver/catalina-server.xml.erb'),
}
}
}
As per the current method, if a matching node is found (say appserver-mgr) the respective data structure values are retrieved and applied to the templates.
Currently these scripts are working as expected.
Now I want to change it as follows.
I have a cluster containing following nodes.
appserver-mgr-1
appserver-mgr-2
appserver-mgr-3
appserver-wkr-1
appserver-wkr-2
appserver-wkr-3
appserver-wkr-4
appserver-wkr-5
By using the same data structure in params.pp file, how can I apply the appserver-mgr configuration to *.mgr nodes 1-3 and appserver-wkr configuration to *.wkr nodes 1-5?
Can I use regular expressions for this task?

I'm quite sure that it would be possible to bend the Puppet DSL to do what you need here. However, the far better approach to this issue is Hiera.
node /appserver-mgr/ {
$node_class = 'appserver'
$node_subclass = 'manager'
}
node /appserver-wrk/ {
$node_class = 'appserver'
$node_subclass = 'worker'
}
Use the node_class and node_subclass variables in your Hierarchy.
# /etc/puppet/hiera.yaml
---
:backends:
- yaml
:yaml:
:datadir: /etc/puppet/hieradata
:hierarchy:
- "%{::clientcert}"
- "class-%{node_class}-%{node_subclass}"
- "class-%{node_class}"
- common
Now you can define your data right in the YAML for Hiera, instead of params.pp.
# /etc/puppet/hieradata/class-appserver-manager.yaml
servers:
axis2:
subDomain: mgt
carbon:
subDomain: mgt
serverOptions: -Dsetup
server_home: %{carbon_home}
and for the worker:
# /etc/puppet/hieradata/class-appserver-worker.yaml
servers:
axis2:
subDomain: worker
members:
- appserver-mgr2-ip
carbon:
subDomain: worker
serverOptions: -DworkerNode=true
server_home: %{carbon_home}
In your params class, the following then suffices:
$servers = hiera('servers')
Or you don't even bother with the params class, and just replace the uses of the $servers variable with hiera calls. But doing just one call in a params style class is a good practice.
Note: Using the variable value %{carbon_home} from Hiera is somewhat dangerous, you might want to hardcode the actual value in the YAML there.

Related

How to update values dynamically for the individual match sections within sshd config file using puppet

i am able to update the value to the sections "User foo" and "Host *.example.net" by passing the index. If i pass index 1 or 2 the respective value is getting updated.
my code:
$sections = ['Host *.example.net', 'User foo']
$sections.each |String $section| {
sshd_config_match { "${section}":
ensure => present,
}
}
$settings = [['User foo', 'X11Forwarding yes', 'banner none'],['Host *.example.net', 'X11Forwarding no', 'banner none']]
$settings.each |Array $setting| {
$setting_array = split($setting[1],/ /)
sshd_config { "${setting_array[0]} ${setting[0]}":
ensure => present,
key => "${setting_array[0]}",
condition => "${setting[0]}",
value => "${setting_array[1]}",
}
}
current result:
Match Host *.example.net
# Created by Puppet
X11Forwarding no
Match User foo
# Created by Puppet
X11Forwarding yes
Expected results:
Match Host *.example.net
# Created by Puppet
X11Forwarding no
Banner none
Match User foo
# Created by Puppet
X11Forwarding yes
Banner none
i am able to update only one value mentioned in the index but am looking a way to update more or all the values mentioned in the list.
It's not clear what module is providing your sshd_config_match and sshd_config resource types, nor, therefore, exactly what they do. Nevertheless, if we consider this code ...
$settings = [['User foo', 'X11Forwarding yes', 'banner none'],['Host *.example.net', 'X11Forwarding no', 'banner none']]
$settings.each |Array $setting| {
$setting_array = split($setting[1],/ /)
sshd_config { "${setting_array[0]} ${setting[0]}":
ensure => present,
key => "${setting_array[0]}",
condition => "${setting[0]}",
value => "${setting_array[1]}",
}
}
... we can see that each element of $settings is a three-element array, of which the each call accesses only those at indexes 0 and 1. That seems to match up with the result you see, which does not contain anything corresponding to the data from the elements at index 2.
You could iterate over the inner $setting elements, starting at index 1, instead of considering that element only, but I would suggest instead restructuring the data more naturally, and writing code suited to the restructured data. You have data of mixed significance in your arrays, and you are needlessly jamming keys and values together such that you need to spend effort to break them back apart. Structuring the data as a hash of hashes instead of an array of arrays could be a good start:
$settings = {
'User foo' => { 'X11Forwarding' => 'yes', 'banner' => 'none'},
'Host *.example.net' => { 'X11Forwarding' => 'no', 'banner' => 'none'},
}
Not only does that give you much enhanced readability (mostly from formatting), but it also affords much greater usability. To wit, although I'm guessing a bit here, you should be able to do something similar to the following:
$settings.each |String $condition, Hash $properties| {
$properties.each |String $key, String $value| {
sshd_config { "${condition} ${key}":
ensure => 'present',
condition => $condition,
key => $key,
value => $value,
}
}
}
Again, greater readability, this time largely from a helpful choice of names, and along with it greater clarity that something like this is in fact the right structure for the code (supposing that I have correctly inferred enough about the types you are using).

Logstash can not handle multiple heterogeneous inputs

Let's say you have 2 very different types of logs such as FORTINET and NetASQ logs and you want:
grok FORTINET using a regex, ang grok NETASQ using an other regex.
I know that with "type"in the input file and "condition" in the filter we can resolve this problem.
So I used this confing file to do it :
input {
file {
type => "FORTINET"
path => "/fortinet/*.log"
sincedb_path=>"/logstash-autre_version/var/.sincedb"
start_position => 'beginning'
}
file {
type => "NETASQ"
path => "/home/netasq/*.log"
}
}
filter {
if [type] == "FORTINET" {
grok {
patterns_dir => "/logstash-autre_version/patterns"
match => [
"message" , "%{FORTINET}"
]
tag_on_failure => [ "failure_grok_exemple" ]
break_on_match => false
}
}
if [type] == "NETASQ" {
# .......
}
}
output {
elasticsearch {
cluster => "logstash"
}
}
And i'm getting this error :
Got error to send bulk of actions: no method 'type' for arguments(org.jruby.RubyArray) on Java::OrgElasticsearchActionIndex::IndexRequest {:level=>:error}
But if don't use "type" and i grok only FORTINET logs it wroks.
What should i do ?
I'm not sure about this but maybe it helps:
I have the same error and I think that it is caused by the use of these if statements:
if [type] == "FORTINET"
your type field is compared to "FORTINET" but this is maybe not possible because "FORTINET" is a string and type isn't. Some times by setting a type to an input, if there is already a type, the type isn't replaced, but the new type is added to a list with the old type. You should have a look to your data in kibana (or wherever) and try to find something like this:
\"type\":[\"FORTINET\",\"some-other-type\"]
maybe also without all those \" .
If you find something like this try not to set the type of your input explicitly and compare the type in your if-statement to the some-other-type you have found.
Hope this works (I'm working with more complex inputs/forwarders and for me it doesn't, but it is worth a try)

rails4 Devise omniauth How to modify dynamically one of the strategy options?

I am using Devise+Omniauth , and I defined my own doorkeeper strategy to add a language option
In config/initializers/devise.rb , I set up :
require 'omniauth/strategies/doorkeeper'
config.omniauth :doorkeeper, Rails.application.secrets.doorkeeper_app_id, Rails.application.secrets.doorkeeper_app_secret,
:client_options => {
:site => Rails.application.secrets.doorkeeper_url
},
:authorize_params =>{:lang => I18n.locale}
which initially set lang to :en ( default locale )
this works fine and send the lang options to the remote server for Doorkeeperprocessing
now, how can I change this parameter in my client calling controller ?
I tried to use :
def index
I18n.locale = :fr
Rails.application.config.middleware.use OmniAuth::Builder do
provider :doorkeeper, :setup => lambda{|env| env['omniauth.strategy'].options[:authorize_params][:lang] = env['rack.session'][I18n.locale] }
end
but I got an error :
RuntimeError (can't modify frozen Array):
app/controllers/home_controller.rb:7:in `index'
Is there any better way to do it ? thanks for help
I modified the config/initializers/devise.rb, adding :setup => true
require 'omniauth/strategies/doorkeeper'
config.omniauth :doorkeeper, Rails.application.secrets.doorkeeper_app_id, Rails.application.secrets.doorkeeper_app_secret,
:client_options => {
:site => Rails.application.secrets.doorkeeper_url
},
:authorize_params =>{:lang => I18n.locale},
:setup => true
and I modified my doorkeeper strategy, to include the setup_phase, in which I set the lang option to the current locale.
def setup_phase
request.env['omniauth.strategy'].options[:authorize_params][:lang] = request.params["locale"]
end

doctrine 2 returns errror 'proxy directory must be writable'

i am using doctrine 2 with Zendframework 2
i am trying to return an object but keep getting this error:
Your proxy directory must be writable
this is my query:
$this->getEntityManager()
->getRepository('Messages\Entity\Messages')
->findOneBy(array('id' => 6,
'receiverId' => 16
));
However, the same query return an array without any problems re:
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select(array('u'))
->from('Messages\Entity\Messages','u')
->where('u.id = :id')
->andWhere('u.receiverUserId = :receiverId')
->setParameter('receiverId',16)
->setParameter('id',(int)6);
$query = $qb->getQuery();
return $data = $query->getArrayResult();
If you are using Setup::createAnnotationMetadataConfiguration you can simply fix it by
Create the following directory in your project root. data/DoctrineORMModule/Proxy
chmod -R 755 data/DoctrineORMModule/Proxy
In your bootstrap include the path to the data directory as in:
Setup::createAnnotationMetadataConfiguration(array(__DIR__ . "/src/models"), $this->isDevMode, "data/DoctrineORMModule/Proxy")
That fixed it for me.
Proxies are simple classes which extends your actual entities and used internally by doctrine to hydrate associations of your entities by lazy-loading them. Doctrine decides to use or not to use a proxy instances on runtime for different situations and it really depends on your queries and associations in your entities. You may want to read about this subject in-depth at official documentation.
In your case, doctrine trying to generate a proxy class for your Messages entity but your proxy directory is simply not writable as error output's said.
This seems like misconfiguration of DoctineModule. (Assuming that you are using DoctrineORMModule to integrate doctrine with ZF2) Doctrine needs a writeable directory to put that generated proxy classes. For ZF2's view, data directory on application root perfectly fits for this requirement.
Make sure existence of the line below in your public/index.php:
chdir(dirname(__DIR__));
and try to use a configuration like this:
<?php
/**
* module/Application/config/module.config.php
*/
return array(
'router' => array(
// ...
),
// ...
'doctrine' => array(
'driver' => array(
//...
),
/**
* Generating proxies on runtime and using array cache instead of apc(u)
* greatly reduces the performance. So, you may want to override
* this settings on production environment.
*/
'configuration' => array(
'orm_default' => array(
'metadata_cache' => 'array',
'query_cache' => 'array',
'result_cache' => 'array',
'hydration_cache' => 'array',
'generate_proxies' => true,
'proxy_dir' => 'data/DoctrineORMModule/Proxy',
'proxy_namespace' => 'DoctrineORMModule\Proxy',
),
),
)
);
If you are using Fedora 24, enter the following commands:
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/YOUR_SITE/data';
restorecon -v '/var/www/html/YOUR_SITE/data'
With this, you are changing the label of the /var/www/html and giving write permission to httpd.

How do I access sinatra settings in custom extension specs?

I have an email helper extension I have written for my application. I use settings I have defined on the application like so:
set :mailgun_options, JSON.parse(File.open('config/mailer.json').read)[ENV['RACK_ENV']]
which reads configuration settings from a json file into the global Sinatra settings.
I then have my email helper which references these settings to create connections and what not.
require 'sinatra/base'
require 'faraday'
module Sinatra
module EmailHelper
def connect opts={}
connection = Faraday.new(:url => settings.mailgun_options['mailgun_url']) do |faraday|
if settings.mailgun_options['test']
faraday.adapter :test do |stubs|
stubs.post(settings.mailgun_options['domain'] + '/messages') {[ 200, {}, 'success' ]}
end
else
faraday.request :url_encoded
faraday.adapter Faraday.default_adapter
end
end
connection.basic_auth('api', settings.mailgun_options['key'])
return connection
end
def send_email params={}
connect.post((settings.mailgun_options['domain'] + '/messages'), params)
end
def send_password_reset_email email
template = File.open( File.expand_path( '../../helpers/email_helper/templates/password_reset.erb', __FILE__ ), 'r' ).read
send_email({
:from => 'REscour <noreply#' + settings.mailgun_options['domain'] + '>',
:to => email,
:subject => 'REscour.com Password Reset',
:text => ERB.new(template).result(binding)
})
end
end
end
So, when I am trying to write my specs to test the "connect" method, I get the following error:
undefined local variable or method `settings' for #<Class:0x007faaf9c9bd18>
My spec code is as follows:
module Sinatra
describe EmailHelper
let(:dummy_class) { Class.new { extend EmailHelper } }
it 'should connect to mailgun\'s api' do
app.set :mailgun_options, ::JSON.parse(File.open('config/mailer.json').read)['test']
puts dummy_class.connect
end
end
end
I'm not sure how to interact with the global Sinatra settings from my specs to have the local "settings" variable be defined during execution of the helper code.
I could have the architecture of my application wrong here for all I know. Does anyone have any experience in writing Sinatra extensions using the global settings and write specs for them?
The spec you've written seems to want to be a unit test, because you've not run the extension the way it would be used in an app. In the specs, try something like:
describe "connect" do
let(:app) { Sinatra.new do
helpers Sinatra::EmailHelper
configure do
:mailgun_options, ::JSON.parse(File.open('config/mailer.json')
end
get "/" do
connect
end
end
}
# now write specs for the `connect` helper
end
Using an anonymous class (Sinatra.new do…) lets you quickly set up an app that's convenient for a small test, but there are other ways too.
In the extension, you need to add:
helpers EmailHelper
as per the example in the docs.