diff --git a/plugins/dns/custom/.gitignore b/plugins/dns/custom/.gitignore new file mode 100644 index 00000000000..430567f259c --- /dev/null +++ b/plugins/dns/custom/.gitignore @@ -0,0 +1,2 @@ +doc +.yardoc diff --git a/plugins/dns/custom/COPYRIGHT b/plugins/dns/custom/COPYRIGHT new file mode 100644 index 00000000000..6bdf5239367 --- /dev/null +++ b/plugins/dns/custom/COPYRIGHT @@ -0,0 +1 @@ +Copyright 2015 Red Hat, Inc. and/or its affiliates. diff --git a/plugins/dns/custom/Gemfile b/plugins/dns/custom/Gemfile new file mode 100644 index 00000000000..b4e2a20bb60 --- /dev/null +++ b/plugins/dns/custom/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gemspec diff --git a/plugins/dns/custom/LICENSE b/plugins/dns/custom/LICENSE new file mode 100644 index 00000000000..90edcee40a5 --- /dev/null +++ b/plugins/dns/custom/LICENSE @@ -0,0 +1,11 @@ +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. diff --git a/plugins/dns/custom/README.md b/plugins/dns/custom/README.md new file mode 100644 index 00000000000..8d2242982b0 --- /dev/null +++ b/plugins/dns/custom/README.md @@ -0,0 +1,35 @@ +# Configuration + +This plugin provides a DNS integration for OpenShift Enterprise version 2.2. +The plugin essentially allows calling of a local script that can be used to integrate with a remote system as required. In the example the script calls local nsupdate commands. + +The configuration file for the plugin is ```/etc/openshift/plugins.d/openshift-origin-dns-custom.conf``` + +Three variables in the configuration file define the location of the update server: + # The DNS server + DNS_CUSTOM_SCRIPT_NAME="/usr/local/bin/ose-dns-custom" + +# Build - generates the gem file +gem build openshift-origin-dns-custom.gemspec + +# Manually Install: +gem install -V --local --install-dir /opt/rh/ruby193/root/usr/share/gems --force ./openshift-origin-dns-custom-1.0.0.gem + +restorecon -Rv /opt + +cp /opt/rh/ruby193/root/usr/share/gems/gems/openshift-origin-dns-custom-1.0.0/conf/openshift-origin-dns-custom.conf.example /etc/openshift/plugins.d/ +cp /opt/rh/ruby193/root/usr/share/gems/gems/openshift-origin-dns-custom-1.0.0/conf/ose-dns-custom /usr/local/bin/ +mv /etc/openshift/plugins.d/openshift-origin-dns-nsupdate.conf /etc/openshift/plugins.d/openshift-origin-dns-nsupdate.conf.save +cp /etc/openshift/plugins.d/openshift-origin-dns-custom.conf.example /etc/openshift/plugins.d/openshift-origin-dns-custom.conf + +cp /var/named/mydomain.key /etc/openshift/ +chown apache:root /etc/openshift/mydomain.key + +edit /usr/local/bin/ose-dns-custom as required, for local DNS server update the domainname and keyfile name, for custom DNS change add and delete code as required + Note: if using on second broker host, remote to the DNS server, need to remove the -l from nsupdate and insert 'server ' entry. + +Restart openshift-* services, broker first then console afterwards. + +# Note: oo-accept-broker NOTICE +The oo-accept-broker script has a descrete list of dynamic DNS plugins in a case statement so there is a warning NOTICE raised when the broker is checked, this is just a warning from the check script and not an issue with the OpenShift::CustomDNSPlugin class not being known. + diff --git a/plugins/dns/custom/Rakefile b/plugins/dns/custom/Rakefile new file mode 100644 index 00000000000..240ea530f53 --- /dev/null +++ b/plugins/dns/custom/Rakefile @@ -0,0 +1,21 @@ +#require "bundler/gem_tasks" +require 'rake' +require 'rake/testtask' +require 'rspec/core/rake_task' +require 'rdoc/task' + +task :default => [:rdoc] + +desc "Run RSpec unit tests" +RSpec::Core::RakeTask.new(:spec) do |t| + t.pattern = "./spec/*/*_spec.rb" # don't need this, it's default. + # make sure ruby can find the superclass and dependencies + t.ruby_opts = "-I spec/lib -I ../../../common/lib -I ../../../controller/lib -I lib" +end + +desc "Generate RDoc output" +Rake::RDocTask.new do |rd| + rd.main = "README.rdoc" + rd.rdoc_dir = "doc" + rd.rdoc_files.include("README.rdoc", "lib/**/*.rb") +end diff --git a/plugins/dns/custom/conf/openshift-origin-dns-custom.conf.example b/plugins/dns/custom/conf/openshift-origin-dns-custom.conf.example new file mode 100644 index 00000000000..8fb10d86275 --- /dev/null +++ b/plugins/dns/custom/conf/openshift-origin-dns-custom.conf.example @@ -0,0 +1,5 @@ +# Settings related OpenShift Enterprise custom DNS plugin + +# The custom script to call to perform the DNS updates +DNS_CUSTOM_SCRIPT_NAME="/usr/local/bin/ose-dns-custom" + diff --git a/plugins/dns/custom/conf/ose-dns-custom b/plugins/dns/custom/conf/ose-dns-custom new file mode 100755 index 00000000000..6199de82456 --- /dev/null +++ b/plugins/dns/custom/conf/ose-dns-custom @@ -0,0 +1,100 @@ +#!/bin/bash + +# Usage +function usage { + echo "Usage: $0 " + echo + echo " --action {add|delete}" + echo " --host hostname - FQ Hostname" + echo " --cname - CNAME to add to host" + echo + exit 1 +} + +# options followed by one colon indicate they have a required argument +if ! options=$(getopt -o ahc: -l action:,host:,cname: -- "$@") +then + usage +fi + +set -- $options + +while [ $# -gt 0 ] +do + case $1 in + --action) action=`eval echo $2` ; shift ;; + --host) osehost=`eval echo $2` ; shift ;; + --cname) cname=`eval echo $2` ; shift ;; + (--) shift; break;; + (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;; + (*) break;; + esac + shift +done + +echo +echo [ose-dns-custom] INFO: Input Param: action = $action +echo [ose-dns-custom] INFO: Input Param: host = $osehost +echo [ose-dns-custom] INFO: Input Param: cname = $cname + + +if [ -z $action ] ; then + echo + echo " action is a required option with arguments: {add|delete}, exiting." + echo + usage +fi + +if [ -z $osehost ] && [ "$action" = "add" ] ; then + echo + echo " host is a required option when action is add, exiting." + echo + usage +fi + +if [ -z $cname ] ; then + echo + echo " cname is a required option, exiting." + echo + usage +fi + + +# Main + +# Params for nsupdate +hostname=127.0.0.1 +priv_key=/etc/openshift/example.com.key +ttl=60 +zone=example.com + +ret_stat=0 + +case $action in + + add) echo [ose-dns-custom] INFO: adding CNAME $cname to HOST $osehost: update add $cname $ttl CNAME $osehost + nsupdate_out=$(echo "zone $zone +server $hostname +update add ${cname} $ttl CNAME $osehost +show +send" | nsupdate -k $priv_key -v 2>&1) + ret_stat=$? + logger "$nsupdate_out" + ;; + + delete) echo [ose-dns-custom] INFO: deleting CNAME $cname: update delete $cname + nsupdate_out=$(echo "zone $zone +server $hostname +update delete $cname +show +send" | nsupdate -k $priv_key -v 2>&1) + ret_stat=$? + logger "$nsupdate_out" + ;; + + (*) echo [ose-dns-custom] ERROR: Invalid option value for action, exiting. ; usage ;; + +esac + +echo [ose-dns-custom] INFO: return status=$ret_stat +exit $ret_stat diff --git a/plugins/dns/custom/config/initializers/openshift-origin-dns-custom.rb b/plugins/dns/custom/config/initializers/openshift-origin-dns-custom.rb new file mode 100644 index 00000000000..7e250b85536 --- /dev/null +++ b/plugins/dns/custom/config/initializers/openshift-origin-dns-custom.rb @@ -0,0 +1,18 @@ +require 'openshift-origin-common' + +Broker::Application.configure do + conf_file = File.join(OpenShift::Config::PLUGINS_DIR, File.basename(__FILE__, '.rb') + '.conf') + if Rails.env.development? + dev_conf_file = File.join(OpenShift::Config::PLUGINS_DIR, File.basename(__FILE__, '.rb') + '-dev.conf') + if File.exist? dev_conf_file + conf_file = dev_conf_file + else + Rails.logger.info "Development configuration for #{File.basename(__FILE__, '.rb')} not found. Using production configuration." + end + end + conf = OpenShift::Config.new(conf_file) + + config.dns = { + :dns_custom_script => conf.get("DNS_CUSTOM_SCRIPT_NAME", "/usr/local/bin/ose-dns-custom"), + } +end diff --git a/plugins/dns/custom/lib/custom_dns_engine.rb b/plugins/dns/custom/lib/custom_dns_engine.rb new file mode 100644 index 00000000000..ab79343a2b3 --- /dev/null +++ b/plugins/dns/custom/lib/custom_dns_engine.rb @@ -0,0 +1,7 @@ +require 'openshift-origin-controller' +require 'rails' + +module OpenShift + class CustomDnsEngine < Rails::Engine + end +end diff --git a/plugins/dns/custom/lib/openshift-origin-dns-custom.rb b/plugins/dns/custom/lib/openshift-origin-dns-custom.rb new file mode 100644 index 00000000000..330ddc30f02 --- /dev/null +++ b/plugins/dns/custom/lib/openshift-origin-dns-custom.rb @@ -0,0 +1,10 @@ +require "openshift-origin-common" + +module OpenShift + module CustomDnsModule + require 'custom_dns_engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3 + end +end + +require "openshift/custom_dns_plugin.rb" +OpenShift::DnsService.provider=OpenShift::CustomDNSPlugin diff --git a/plugins/dns/custom/lib/openshift/custom_dns_plugin.rb b/plugins/dns/custom/lib/openshift/custom_dns_plugin.rb new file mode 100644 index 00000000000..f7d360618e4 --- /dev/null +++ b/plugins/dns/custom/lib/openshift/custom_dns_plugin.rb @@ -0,0 +1,147 @@ +# +# Make Openshift +# +require 'rubygems' + +module OpenShift + + class CustomDNSPlugin < OpenShift::DnsService + + @provider = OpenShift::CustomDNSPlugin + + attr_reader :dns_custom_script + + + # Establish the parameters for a connection to the DNS update service + # + # @param access_info [Hash] communication configuration settings + # + def initialize(access_info = nil) + + if access_info != nil + @domain_suffix = access_info[:domain_suffix] + + elsif defined? Rails + access_info = Rails.application.config.dns + @domain_suffix = Rails.application.config.openshift[:domain_suffix] + + else + raise DNSException.new("Custom DNS plugin did not initialize") + end + + @dnsscript = access_info[:dns_custom_script] + + end + + +## public + + # Publish an application - create DNS record + # + # @param [String] app_name The name of the application to publish + # @param [String] namespace The namespace which contains the application + # @param [String] public_hostname The name of the location where the application resides + # @return [Object] The response from the service provider + # + def register_application(app_name, namespace, public_hostname) + + # create an A record for the application in the domain + fqdn = "#{app_name}-#{namespace}.#{@domain_suffix}" + cmd = add_cmd(fqdn, public_hostname) + + modify_dns(cmd, "adding", fqdn) + end + + + # Unpublish an application - remove DNS record + # + # @param [String] app_name The name of the application to publish + # @param [String] namespace The namespace which contains the application + # @return [Object] The response from the service provider + # + def deregister_application(app_name, namespace) + + # delete the CNAME record for the application in the domain + fqdn = "#{app_name}-#{namespace}.#{@domain_suffix}" + cmd = del_cmd(fqdn) + + modify_dns(cmd, "removing", fqdn) + end + + + # Change the published location of an application - Modify DNS record + # + # @param [String] app_name The name of the application to publish + # @param [String] namespace The namespace which contains the application + # @param [String] public_hostname The name of the location where the application resides + # @return [Object] The response from the service provider + # + def modify_application(app_name, namespace, public_hostname) + + deregister_application(app_name, namespace) + register_application(app_name, namespace, public_hostname) + end + + + # send any queued requests to the update server + # @return [nil] + def publish + end + + # close any persistent connection to the update server + # @return [nil] + def close + end + + + private + + # Generate a DNS add command string + # + # @param fqdn [String] DNS record name to add + # @param value [String] DNS record value + # @return [String] An nsupdate command sequence + # + def add_cmd(fqdn, value) + + # compose the DNS add command + cmd = "#{@dnsscript} --action add --cname #{fqdn} --host #{value} 2>&1" + + end + + + # Generate a DNS delete command string + # + # @param fqdn [String] DNS record name to delete + # @return [String] An nsupdate command sequence + # + def del_cmd(fqdn) + + # compose the DNS add command + cmd = "#{@dnsscript} --action delete --cname #{fqdn} 2>&1" + + end + + + # Run an nsupdate command, returning a detailed error on failure + # + # @param cmd [String] Command sequence to add the DNS CNAME entry + # @param action [String] Action to be reported in log message ("adding" or "removing") + # @param fqdn FQDN of the application + # + def modify_dns(cmd, action, fqdn) + + Rails.logger.info "[modify-dns]: #{action} DNS application record #{fqdn}: cmd=#{cmd}" + + output = `#{cmd}` + exit_code = $?.exitstatus + + if exit_code != 0 + Rails.logger.error "[modify-dns]: Error #{action} DNS application record #{fqdn}: #{output}" + raise DNSException.new("[modify-dns]: Error #{action} DNS application record #{fqdn} rc=#{exit_code}") + end + end + + + end +end diff --git a/plugins/dns/custom/openshift-origin-dns-custom-1.0.0.gem b/plugins/dns/custom/openshift-origin-dns-custom-1.0.0.gem new file mode 100644 index 00000000000..de694b9c23b Binary files /dev/null and b/plugins/dns/custom/openshift-origin-dns-custom-1.0.0.gem differ diff --git a/plugins/dns/custom/openshift-origin-dns-custom.gemspec b/plugins/dns/custom/openshift-origin-dns-custom.gemspec new file mode 100644 index 00000000000..4ef2183d4b1 --- /dev/null +++ b/plugins/dns/custom/openshift-origin-dns-custom.gemspec @@ -0,0 +1,33 @@ +# -*- encoding: utf-8 -*- +config_dir = File.join(File.join("config", "**"), "*") +$:.push File.expand_path("../lib", __FILE__) +lib_dir = File.join(File.join("lib", "**"), "*") +test_dir = File.join(File.join("test", "**"), "*") +bin_dir = File.join("bin", "*") +doc_dir = File.join(File.join("doc", "**"), "*") +conf_dir = File.join(File.join("conf", "**"), "*") +spec_file = "rubygem-openshift-origin-dns-custom.spec" + +Gem::Specification.new do |s| + spec_file = IO.read(File.expand_path("../rubygem-#{File.basename(__FILE__, '.gemspec')}.spec", __FILE__)) + + s.name = "openshift-origin-dns-custom" + s.version = spec_file.match(/^Version:\s*(.*?)$/mi)[1].chomp + s.authors = ["Graham Hares"] + s.email = ["ghares@redhat.com"] + s.homepage = 'https://github.com/openshift/origin-server' + s.summary = 'OpenShift Origin DNS Custom plugin' + + s.files = Dir[lib_dir] + Dir[doc_dir] + Dir[conf_dir] + Dir[config_dir] + s.test_files = Dir[test_dir] + s.executables = Dir[bin_dir] + s.files += %w(README.md Rakefile Gemfile rubygem-openshift-origin-dns-custom.spec openshift-origin-dns-custom.gemspec LICENSE COPYRIGHT) + s.require_paths = ["lib"] + + s.add_dependency('openshift-origin-controller') + s.add_dependency('json') + s.add_development_dependency('rake', '>= 0.8.7', '<= 0.9.6') + s.add_development_dependency('rspec') + s.add_development_dependency('bundler') + s.add_development_dependency('mocha') +end diff --git a/plugins/dns/custom/rubygem-openshift-origin-dns-custom.spec b/plugins/dns/custom/rubygem-openshift-origin-dns-custom.spec new file mode 100644 index 00000000000..f2357e027cd --- /dev/null +++ b/plugins/dns/custom/rubygem-openshift-origin-dns-custom.spec @@ -0,0 +1,100 @@ +%if 0%{?fedora}%{?rhel} <= 6 + %global scl ruby193 + %global scl_prefix ruby193- +%endif +%{!?scl:%global pkg_name %{name}} +%{?scl:%scl_package rubygem-%{gem_name}} +%global gem_name openshift-origin-dns-custom +%global rubyabi 1.9.1 + +Summary: OpenShift plugin for DNS update service using custom script +Name: rubygem-%{gem_name} +Version: 1.0.0 +Release: 1%{?dist} +Group: Development/Languages +License: ASL 2.0 +URL: http://www.openshift.com +Source0: http://mirror.openshift.com/pub/openshift-origin/source/%{name}/rubygem-%{gem_name}-%{version}.tar.gz +%if 0%{?fedora} >= 19 +Requires: ruby(release) +%else +Requires: %{?scl:%scl_prefix}ruby(abi) >= %{rubyabi} +%endif +Requires: %{?scl:%scl_prefix}rubygems +Requires: %{?scl:%scl_prefix}rubygem(json) +Requires: rubygem(openshift-origin-common) +Requires: bind-utils +# GSS-API requires kinit +Requires: krb5-workstation +Requires: openshift-origin-broker +Requires: selinux-policy-targeted +Requires: policycoreutils-python +%if 0%{?fedora}%{?rhel} <= 6 +BuildRequires: %{?scl:%scl_prefix}build +BuildRequires: scl-utils-build +%endif +%if 0%{?fedora} >= 19 +BuildRequires: ruby(release) +%else +BuildRequires: %{?scl:%scl_prefix}ruby(abi) >= %{rubyabi} +%endif +BuildRequires: %{?scl:%scl_prefix}rubygems +BuildRequires: %{?scl:%scl_prefix}rubygems-devel +BuildArch: noarch +Provides: rubygem(%{gem_name}) = %version + +%description +Provides a DNS service update plugin using custom script + +%prep +%setup -q + +%build +%{?scl:scl enable %scl - << \EOF} +mkdir -p ./%{gem_dir} +# Create the gem as gem install only works on a gem file +gem build %{gem_name}.gemspec +export CONFIGURE_ARGS="--with-cflags='%{optflags}'" +# gem install compiles any C extensions and installs into a directory +# We set that to be a local directory so that we can move it into the +# buildroot in %%install +gem install -V \ + --local \ + --install-dir ./%{gem_dir} \ + --bindir ./%{_bindir} \ + --force \ + --rdoc \ + %{gem_name}-%{version}.gem +%{?scl:EOF} + +%install +mkdir -p %{buildroot}%{gem_dir} +cp -a ./%{gem_dir}/* %{buildroot}%{gem_dir}/ + +# Add documents/examples +mkdir -p %{buildroot}%{_docdir}/%{name}-%{version}/ +#cp -r doc/* %{buildroot}%{_docdir}/%{name}-%{version}/ + +#Config file +mkdir -p %{buildroot}/etc/openshift/plugins.d +cp %{buildroot}/%{gem_dir}/gems/%{gem_name}-%{version}/conf/openshift-origin-dns-custom.conf.example %{buildroot}/etc/openshift/plugins.d/openshift-origin-dns-custom.conf.example + +#Sample custom Script to be edited as required +mkdir -p %{buildroot}/usr/local/bin +cp %{buildroot}/%{gem_dir}/gems/%{gem_name}-%{version}/conf/ose-dns-custom %{buildroot}/usr/local/bin/ose-dns-custom + +%files +%doc %{gem_docdir} +%doc %{_docdir}/%{name}-%{version} +%{gem_instdir} +%{gem_spec} +%{gem_cache} +/etc/openshift/plugins.d/openshift-origin-dns-custom.conf.example +/usr/local/bin/ose-dns-custom + + +%changelog +* Mon Mar 30 2015 Graham Hares 1.0.0-1 +- Initial version created + (ghares@redhat.com) + diff --git a/plugins/dns/custom/spec/unit/openshift-origin-dns-custom_spec.rb b/plugins/dns/custom/spec/unit/openshift-origin-dns-custom_spec.rb new file mode 100644 index 00000000000..ced0f4abbb8 --- /dev/null +++ b/plugins/dns/custom/spec/unit/openshift-origin-dns-custom_spec.rb @@ -0,0 +1,71 @@ +#Test each of the basic functions of the NsupdateDnsPlugin + +require 'rubygems' + +# the plugin extends classes in the OpenShift::Controller module +# load the superclass for all DnsService classes: Openshift::DnsService +require 'openshift/dns_service' + +# Now load the plugin code itself (not the wrapper!) +require 'openshift/custom_dns_plugin' + +# +# Define the Rails config structure for testing +# + +$hosted_zone = "apps.example.com" +$dns_custom_script = "/usr/local/bin/ose-dns-custom" + +module Rails + def self.application() + Application.new + end + + class Application + + class Configuration + attr_accessor :openshift, :dns + + def initialize() + @openshift = { :domain_suffix => $hosted_zone } + @dns = { + :dns_custom_script => "/usr/local/bin/ose-dns-custom", + } + end + + end + def config() + Configuration.new + end + end + +end + + +module OpenShift + + describe CustomDNSPlugin do + + before do + + # Set the assumed service file configuration + @dns = { + :dns_custom_script => "/usr/local/bin/ose-dns-custom", + } + + @plugin = CustomDNSPlugin.new(@dns) + + end + + it "can be configured using the Rails Application::Configuration object" do + + dns = OpenShift::CustomDNSPlugin.new + cfg = Rails.application.config.dns + + end + + + + end + +end