diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..b33108e --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +source 'https://rubygems.org' + +puppetversion = ENV.key?('PUPPET_VERSION') ? "#{ENV['PUPPET_VERSION']}" : ['>= 3.3'] +gem 'puppet', puppetversion +gem 'puppetlabs_spec_helper', '>= 0.8.2' +gem 'puppet-lint', '>= 1.0.0' +gem 'facter', '>= 1.7.0' diff --git a/README.md b/README.md new file mode 100644 index 0000000..aeb3758 --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +# qdr + +#### Table of Contents + +1. [Overview](#overview) +2. [Module Description - What the module does and why it is useful](#module-description) +3. [Setup - The basics of getting started with qdr](#setup) + * [What qdr affects](#what-qdr-affects) + * [Setup requirements](#setup-requirements) + * [Beginning with qdr](#beginning-with-qdr) +4. [Usage - Configuration options and additional functionality](#usage) +5. [Reference - An under-the-hood peek at what the module is doing and how](#reference) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) + +## Overview + +A one-maybe-two sentence summary of what the module does/what problem it solves. +This is your 30 second elevator pitch for your module. Consider including +OS/Puppet version it works with. + +## Module Description + +If applicable, this section should have a brief description of the technology +the module integrates with and what that integration enables. This section +should answer the questions: "What does this module *do*?" and "Why would I use +it?" + +If your module has a range of functionality (installation, configuration, +management, etc.) this is the time to mention it. + +## Setup + +### What qdr affects + +* A list of files, packages, services, or operations that the module will alter, + impact, or execute on the system it's installed on. +* This is a great place to stick any warnings. +* Can be in list or paragraph form. + +### Setup Requirements **OPTIONAL** + +If your module requires anything extra before setting up (pluginsync enabled, +etc.), mention it here. + +### Beginning with qdr + +The very basic steps needed for a user to get the module up and running. + +If your most recent release breaks compatibility or requires particular steps +for upgrading, you may wish to include an additional section here: Upgrading +(For an example, see http://forge.puppetlabs.com/puppetlabs/firewall). + +## Usage + +Put the classes, types, and resources for customizing, configuring, and doing +the fancy stuff with your module here. + +## Reference + +Here, list the classes, types, providers, facts, etc contained in your module. +This section should include all of the under-the-hood workings of your module so +people know what the module is touching on their system but don't need to mess +with things. (We are working on automating this section!) + +## Limitations + +This is where you list OS compatibility, version compatibility, etc. + +## Development + +Since your module is awesome, other users will want to play with it. Let them +know what the ground rules for contributing are. + +## Release Notes/Contributors/Etc **Optional** + +If you aren't using changelog, put your release notes here (though you should +consider using changelog). You may also add any additional sections you feel are +necessary or important to include here. Please use the `## ` header. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..a16ed29 --- /dev/null +++ b/Rakefile @@ -0,0 +1,17 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] + +desc "Validate manifests, templates, and ruby files" +task :validate do + Dir['manifests/**/*.pp'].each do |manifest| + sh "puppet parser validate --noop #{manifest}" + end + Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file| + sh "ruby -c #{ruby_file}" unless ruby_file =~ /spec\/fixtures/ + end + Dir['templates/**/*.erb'].each do |template| + sh "erb -P -x -T '-' #{template} | ruby -c" + end +end diff --git a/examples/init.pp b/examples/init.pp new file mode 100644 index 0000000..cbdef53 --- /dev/null +++ b/examples/init.pp @@ -0,0 +1,12 @@ +# The baseline for module testing used by Puppet Labs is that each manifest +# should have a corresponding test manifest that declares that class or defined +# type. +# +# Tests are then run by using puppet apply --noop (to check for compilation +# errors and view a log of events) or by fully applying the test in a virtual +# environment (to compare the resulting system state to the desired state). +# +# Learn more about module testing here: +# http://docs.puppetlabs.com/guides/tests_smoke.html +# +include qdr diff --git a/lib/puppet/provider/qdr_listener/qdmanage.rb b/lib/puppet/provider/qdr_listener/qdmanage.rb new file mode 100644 index 0000000..dedc2dc --- /dev/null +++ b/lib/puppet/provider/qdr_listener/qdmanage.rb @@ -0,0 +1,117 @@ +require "json" + +Puppet::Type.type(:qdr_listener).provide(:qdmanage) do + + # should rely on environment rather fq path + commands :qdmanage => '/usr/bin/qdmanage' + + def self.instances + begin + listeners = json.load(execute("/usr/bin/qdmanage QUERY --type=listener")) + + + +# parsed["name"].each do |name| +# notice("Found a name") + end + end + + def create + begin + qdmanage('CREATE', + '--type=listener', + '--name', + resource[:name], + 'addr='+resource[:addr], + 'port='+resource[:port], + 'role='+resource[:role].to_s) + rescue Puppet::ExecutionFailure => e + false + end + end + + def destroy + notice("Listener destroy not supported") + true + end + + def exists? + begin + qdmanage('READ', + '--type=listener', + '--name', + resource[:name]) + true + rescue Puppet::ExecutionFailure => e + false + end + end + + def addr + begin + listener=JSON.load(qdmanage('READ', + '--type=listener', + '--name', + resource[:name])) + addr=listener["addr"] + rescue Puppet::ExecutionFailure => e + addr=empty + end + end + + def addr=(value) + notice("Listener update address not supported") + true + end + + def port + begin + listener=JSON.load(qdmanage('READ', + '--type=listener', + '--name', + resource[:name])) + port=listener["port"] + rescue Puppet::ExecutionFailure => e + port=empty + end + end + + def port=(value) + notice("Listener port value update not supported") + true + end + + def role + begin + listener=JSON.load(qdmanage('READ', + '--type=listener', + '--name', + resource[:name])) + role=listener["role"] + rescue Puppet::ExecutionFailure => e + role=empty + end + end + + def role=(value) + notice("Listener role value update not supported") + end + + def auth_peer + begin + listener=JSON.load(qdmanage('READ', + '--type=listener', + '--name', + resource[:name])) + auth_peer=listener["auth_peer"] + rescue Puppet::ExecutionFailure => e + auth_peer=empty + end + end + + def auth_peer=(value) + notice("Listener auth_peer value update not supported") + true + end + +end diff --git a/lib/puppet/provider/qdr_listener/qdr_listener.pp b/lib/puppet/provider/qdr_listener/qdr_listener.pp new file mode 100644 index 0000000..a1367ff --- /dev/null +++ b/lib/puppet/provider/qdr_listener/qdr_listener.pp @@ -0,0 +1,3 @@ +Debug: Runtime environment: puppet_version=4.2.1, ruby_version=2.2.4, run_mode=user, default_encoding=UTF-8 +Notice: Puppet::Type::Qdr_listener::ProviderQdmanage: inside self instances +Debug: Executing: '/usr/bin/qdmanage QUERY --type=listener' diff --git a/lib/puppet/type/qdr_listener.rb b/lib/puppet/type/qdr_listener.rb new file mode 100644 index 0000000..feb0900 --- /dev/null +++ b/lib/puppet/type/qdr_listener.rb @@ -0,0 +1,40 @@ +Puppet::Type.newtype(:qdr_listener) do + desc "Type for managing qdrouterd listener instances" + + ensurable + + # this autorequire should not be hard coded +# autorequire(:service) { 'qdrouterd' } + newparam(:name, :namevar => true) do + desc "The unique name for the listener" + end + + newproperty(:addr) do + desc "The listening host's IP address, IPv4 or IPv6" + end + + newproperty(:port) do + desc "The listeing port number on the host" + end + + newproperty(:role) do + desc "The role for connections established by the listener" + defaultto :normal + newvalues(:normal, :inter_router, :on_demand) + end + + newproperty(:auth_peer) do + defaultto :no + newvalues(:yes, :no) + + def should_to_s(value) + value.inspect + end + + def is_to_s(value) + value.inspect + end + + end + +end diff --git a/lib/puppet/type/qdr_listener.rb~ b/lib/puppet/type/qdr_listener.rb~ new file mode 100644 index 0000000..22227e1 --- /dev/null +++ b/lib/puppet/type/qdr_listener.rb~ @@ -0,0 +1,31 @@ +Puppet::Type.newtype(:qdr_listener) do + desc "Type for managing qdrouterd listener instances" + + ensurable + + # this autorequire should not be hard coded +# autorequire(:service) { 'qdrouterd' } + newparam(:name, :namevar => true) do + desc "The unique name for the listener" + end + + newproperty(:addr) do + desc "The listening host's IP address, IPv4 or IPv6" + end + + newproperty(:port) do + desc "The listeing port number on the host" + end + + newproperty(:role) do + desc "The role for connections established by the listener" + defaultto :normal + newvalues(:normal, :inter_router, :on_demand) + end + + newproperty(:auth_peer) do + defaultto :no + newvalues(:yes, :no) + end + +end diff --git a/manifests/config.pp b/manifests/config.pp new file mode 100644 index 0000000..100dec2 --- /dev/null +++ b/manifests/config.pp @@ -0,0 +1,16 @@ +# == Class qdr::config +# +# This class is called from qdr for qdrouterd service configuration +# +class qdr::config inherits qdr { + + notice("Inside of qdr config") + + file { "/etc/qpid-dispatch/qdrouterd.conf" : + ensure => file, + owner => 0, + group => 0, + mode => '0644', + content => template('qdr/qdrouterd.conf.erb'), + } +} diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 0000000..22233e8 --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,102 @@ +# Class: qdr +# =========================== +# +# Full description of class qdr here. +# +# Parameters +# ---------- +# +# Document parameters here. +# +# * `sample parameter` +# Explanation of what this parameter affects and what it defaults to. +# e.g. "Specify one or more upstream ntp servers as an array." +# +# Variables +# ---------- +# +# Here you should define a list of variables that this module would require. +# +# * `sample variable` +# Explanation of how this variable affects the function of this class and if +# it has a default. e.g. "The parameter enc_ntp_servers must be set by the +# External Node Classifier as a comma separated list of hostnames." (Note, +# global variables should be avoided in favor of class parameters as +# of Puppet 2.6.) +# +# Examples +# -------- +# +# @example +# class { 'qdr': +# servers => [ 'pool.ntp.org', 'ntp.local.company.com' ], +# } +# +# Authors +# ------- +# +# Author Name +# +# Copyright +# --------- +# +# Copyright 2016 Your name here, unless otherwise noted. +# +class qdr( + $container_debug_dump = $qdr::params::container_debug_dump, + $container_name = $qdr::params::container_name, + $container_worker_threads = $qdr::params::container_worker_threads, + $container_sasl_name = $qdr::params::container_sasl_name, + $container_sasl_path = $qdr::params::container_sasl_path, + $listener_addr = $qdr::params::listener_addr, + $listener_auth_peer = $qdr::params::listener_auth_peer, + $listener_idle_timeout = $qdr::params::listener_idle_timeout, + $listener_max_frame_size = $qdr::params::listener_max_frame_size, + $listener_port = $qdr::params::listener_port, + $listener_require_encrypt = $qdr::params::listener_require_encrypt, + $listener_require_ssl = $qdr::params::listener_require_ssl, + $listener_sasl_mech = $qdr::params::listener_sasl_mech, + $listener_ssl_cert_db = $qdr::params::listener_ssl_cert_db, + $listener_ssl_cert_file = $qdr::params::listener_ssl_cert_file, + $listener_ssl_key_file = $qdr::params::listener_ssl_key_file, + $listener_ssl_password = $qdr::params::listener_ssl_password, + $listener_ssl_pw_file = $qdr::params::listener_ssl_pw_file, + $listener_trusted_certs = $qdr::params::listener_trusted_certs, + $log_enable = $qdr::params::log_enable, + $log_module = $qdr::params::log_module, + $log_output = $qdr::params::log_output, + $manage_service = $qdr::params::manage_service, + $package_ensure = $qdr::params::package_ensure, + $package_name = $qdr::params::package_name, + $router_hello_interval = $qdr::params::router_hello_interval, + $router_hello_max_age = $qdr::params::router_hello_max_age, + $router_id = $qdr::params::router_id, + $router_mobile_addr_max_age = $qdr::params::router_mobile_addr_max_age, + $router_mode = $qdr::params::router_mode, + $router_ra_interval = $qdr::params::router_ra_interval, + $router_ra_interval_flux = $qdr::params::router_ra_interval_flux, + $router_mobile_addr_max_age = $qdr::params::router_mobile_addr_max_age, + $service_config_file = $qdr::params::service_config_file, + $service_group = $qdr::params::service_group, + $service_enable = $qdr::params::service_enable, + $service_ensure = $qdr::params::service_ensure, + $service_manage = $qdr::params::service_manage, + $service_name = $qdr::params::service_name, + $service_password = $qdr::params::service_password, + $service_user = $qdr::params::service_user, + $tools_ensure = $qdr::params::tools_ensure, + $tools_package_name = $qdr::params::tools_package_name, + + +) inherits qdr::params { + + #validate parameters + + # + notice("inside qdr init.pp") + + class { '::qdr::install': } -> + class { '::qdr::config': } ~> + class { '::qdr::service': } + +} diff --git a/manifests/install.pp b/manifests/install.pp new file mode 100644 index 0000000..41dd953 --- /dev/null +++ b/manifests/install.pp @@ -0,0 +1,22 @@ +# == Class qdr::install +# +# This class is called from qdr for qdrouterd service installation +class qdr::install inherits qdr { + + $package_ensure = $qdr::package_ensure + $package_name = $qdr::package_name + $tools_ensure = $qdr::tools_ensure + $tools_package_name = $qdr::tools_package_name + + notice("Inside of qdr install for $package_name") + package { $package_name: + ensure => $ackage_ensure, + name => $package_name, + } + + # (TODO:ansmith) should this be in its own class? + package { $tools_package_name: + ensure => $tools_ensure, + } + +} diff --git a/manifests/params.pp b/manifests/params.pp new file mode 100644 index 0000000..09d8fef --- /dev/null +++ b/manifests/params.pp @@ -0,0 +1,69 @@ +# Class: qdr::params +# +# The Qpid Dispatch Router Module configuration settings +# +class qdr::params { + + case $::osfamily { + 'RedHat': { + $package_ensure = latest + $package_name = 'qpid-dispatch-router' + $service_name = 'qdrouterd' + $service_user = 'qdrouterd' + $service_group = 'qdrouterd' + $version = '0.5.0' + } + default: { + fail("The ${module_name} module is not supported on an ${::osfamily} based system.") + } + } + + #service and config attributes + $service_config_file = '/etc/qpid-dispatch/qdrouterd.conf' + $service_password = 'qdrpassword' + $service_ensure = running + $service_enable = true + $service_manage = true + + # container attributes + $container_name = "Qpid.Dispatch.Router.$::hostname" + $container_worker_threads = $::processorcount + $container_debug_dump = '/var/log/' + $container_sasl_path = '/etc/sasl2' + $container_sasl_name = 'qdrouterd' + + # router attributes + $router_id = "Router.$::fqdn" + $router_mode = 'standalone' + $router_hello_interval = '1' + $router_hello_max_age = '3' + $router_ra_interval = '30' + $router_ra_interval_flux = '4' + $router_remote_ls_max_age = '60' + $router_mobile_addr_max_age = '60' + + # listener attributes + $listener_addr = '127.0.0.1' + $listener_port = '5672' + $listener_ssl_cert_db = 'UNSET' + $listener_ssl_cert_file = 'UNSET' + $listener_ssl_key_file = 'UNSET' + $listener_ssl_pw_file = 'UNSET' + $listener_ssl_password = undef + $listener_sasl_mech = 'ANONYMOUS,DIGEST-MD5,EXTERNAL,PLAIN' + $listener_auth_peer = 'no' + $listener_require_encrypt = 'no' + $listener_require_ssl = 'no' + $listener_trusted_certs = 'UNSET' + $listener_max_frame_size = '65536' + $listener_idle_timout = '16' + + # log parameters + $log_module = 'DEFAULT' + $log_enable = 'debug+' + $log_output = '/var/log/qdrouterd.log' + + # tools package + $tools_ensure = 'installed' + $tools_package_name = 'qpid-dispatch-tools' +} diff --git a/manifests/service.pp b/manifests/service.pp new file mode 100644 index 0000000..37c201a --- /dev/null +++ b/manifests/service.pp @@ -0,0 +1,19 @@ +# == Class qdr::service +# +# This class is called from qdr for qdrouterd service management +class qdr::service inherits qdr { + + $service_enable = $qdr::service_enable + $service_ensure = $qdr::service_ensure + $service_name = $qdr::service_name + + notice("Inside of qdr service for $service_name") + + service { $service_name: + ensure => $service_ensure, + enable => $service_enable, + hasstatus => true, + hasrestart => true, + } + +} diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..c02051d --- /dev/null +++ b/metadata.json @@ -0,0 +1,14 @@ +{ + "name": "ajssmith-qdr", + "version": "0.1.0", + "author": "Andy Smith", + "summary": "This module manages qpid-dispatch-router service", + "license": "Apache-2.0", + "source": "https://github.com/ajssmith/puppet-qdr", + "project_page": "https://github.com/ajssmith/puppet-qdr", + "issues_url": "https://github.com/ajssmith/puppet-qdr/issues", + "dependencies": [ + {"name":"puppetlabs-stdlib","version_requirement":">= 1.0.0"} + ] +} + diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb new file mode 100644 index 0000000..736d8c0 --- /dev/null +++ b/spec/classes/init_spec.rb @@ -0,0 +1,7 @@ +require 'spec_helper' +describe 'qdr' do + + context 'with defaults for all parameters' do + it { should contain_class('qdr') } + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..2c6f566 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1 @@ +require 'puppetlabs_spec_helper/module_spec_helper' diff --git a/templates/qdrouterd.conf.erb b/templates/qdrouterd.conf.erb new file mode 100644 index 0000000..23444e5 --- /dev/null +++ b/templates/qdrouterd.conf.erb @@ -0,0 +1,95 @@ +## +## Licensed to the Apache Software Foundation (ASF) under one +## or more contributor license agreements. See the NOTICE file +## distributed with this work for additional information +## regarding copyright ownership. The ASF licenses this file +## to you 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 +## + +# See the qdrouterd.conf (5) manual page for information about this +# file's format and options. + +container { + containerName: <%= @container_name %> + workerThreads: <%= @container_worker_threads %> + debugDump: <%= @container_debug_dump %> + saslConfigPath: <%= @container_sasl_path %> + saslConfigName: <%= @container_sasl_name %> +} + +router { + mode: <%= @router_mode %> + routerId: <%= @router_id %> +} + +listener { + addr: <%= @listener_addr %> + port: <%= @listener_port %> + authenticatePeer: <%= @listener_auth_peer %> +} + +fixedAddress { + prefix: /closest/ + fanout: single + bias: closest +} + +fixedAddress { + prefix: /multicast/ + fanout: multiple +} + +fixedAddress { + prefix: /queue/ + phase: 0 + fanout: single + bias: closest +} + +fixedAddress { + prefix: /queue/ + phase: 1 + fanout: single + bias: closest +} + +fixedAddress { + prefix: /unicast + fanout: single + bias: closest +} + +fixedAddress { + prefix: /exclusive + fanout: single + bias: closest +} + +fixedAddress { + prefix: /broadcast + fanout: multiple +} + +fixedAddress { + prefix: / + fanout: multiple +} + +log { + module: <%= @log_module %> + enable: <%= @log_enable %> + timestamp: true + output: <%= @log_output %> +} +