diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a1bead0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.kitchen/ +Gemfile.lock diff --git a/.kitchen.docker.yml b/.kitchen.docker.yml new file mode 100644 index 0000000..bf2fecc --- /dev/null +++ b/.kitchen.docker.yml @@ -0,0 +1,74 @@ +<% +require 'socket' + +# @return [String] public IP address of workstation used for egress traffic +def local_ip + @local_ip ||= begin + # turn off reverse DNS resolution temporarily + orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true + + UDPSocket.open do |s| + s.connect '64.233.187.99', 1 # a google IP, does not hit network + s.addr.last + end + ensure + Socket.do_not_reverse_lookup = orig + end +end + +# @return [Integer] default polipo listening port +def local_port ; 8123 ; end + +# @return [String] the polipo proxy URL +def http_proxy_url ; "http://#{local_ip}:#{local_port}" ; end + +# @return [TrueClass,FalseClass] whether or not the polipo port is listening +def proxy_running? + socket = TCPSocket.new(local_ip, local_port) + true +rescue SocketError, Errno::ECONNREFUSED, + Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError + false +rescue Errno::EPERM, Errno::ETIMEDOUT + false +ensure + socket && socket.close +end +%> +--- +driver: + name: docker + use_sudo: true + require_chef_omnibus: false + <% if proxy_running? %> + http_proxy: <%= http_proxy_url %> + https_proxy: <%= http_proxy_url %> + <% end %> + +driver_config: + provision_command: + - sed -i 's/http\:\/\/archive/http\:\/\/us.archive/g' /etc/apt/sources.list + - apt-get clean && rm -rf /var/lib/apt/lists/* && apt-get update + <% if proxy_running? %> + - echo 'Acquire::http::Proxy "<%= http_proxy_url %>";' > /etc/apt/apt.conf.d/proxy + - "env http_proxy=<%= http_proxy_url %> bash -c 'curl -sL http://www.chef.io/chef/install.sh | bash'" + - curl -o bootstrap-salt.sh -sL https://bootstrap.saltstack.com + - env http_proxy=<%= http_proxy_url %> bash bootstrap-salt.sh -X -d -H <%= http_proxy_url %> + <% else %> + - "curl -sL http://www.chef.io/chef/install.sh | bash" + - curl -o bootstrap-salt.sh -sL https://bootstrap.saltstack.com + - bash bootstrap-salt.sh -X -d + <% end %> + +provisioner: + # installs from an http:// source to enable better caching through + # http_proxy, and yes, this is a bit evil +<% if proxy_running? %> + http_proxy: <%= http_proxy_url %> + https_proxy: <%= http_proxy_url %> + chef_omnibus_url: http://www.chef.io/chef/install.sh + chef_bootstrap_url: http://www.chef.io/chef/install.sh + additional_minion_config: + proxy_host: <%= (http_proxy_url.split(":")[1]).split("/")[2] %> + proxy_port: <%= http_proxy_url.split(":")[2] %> +<% end %> diff --git a/.kitchen.yml b/.kitchen.yml new file mode 100644 index 0000000..b26fb1a --- /dev/null +++ b/.kitchen.yml @@ -0,0 +1,31 @@ +<% +require 'yaml' +formula = YAML.load_file('FORMULA') +formula_name = formula['name'] +%> +--- +platforms: + - name: ubuntu-16.04 + - name: ubuntu-18.04 + +provisioner: + name: salt_solo + salt_install: bootstrap + salt_bootstrap_url: https://bootstrap.saltstack.com + salt_version: latest + pillars-from-files: + <%= formula_name %>.sls: pillar.example + pillars: + top.sls: + base: + '*': + - <%= formula_name %> + log_level: <%= ENV['SALT_DEBUG_LEVEL'] || 'debug' %> + formula: <%= formula_name %> + state_top: + base: + '*': + - <%= formula_name %> + +suites: + - name: default diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..858de22 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,24 @@ +language: ruby + +rvm: + - 2.4.1 + +sudo: required +services: docker + +env: + matrix: + - INSTANCE=default-ubuntu-1604 + - INSTANCE=default-ubuntu-1804 + +# https://github.com/zuazo/kitchen-in-travis-native/issues/1#issuecomment-142455888 +before_script: sudo iptables -L DOCKER || sudo iptables -N DOCKER + +install: + # setup ci for test formula + - export BUNDLE_GEMFILE=$PWD/Gemfile + - bundle install + +script: + # Run unit tests + - KITCHEN_LOCAL_YAML=.kitchen.docker.yml bundle exec kitchen test ${INSTANCE} diff --git a/FORMULA b/FORMULA new file mode 100644 index 0000000..7e014ce --- /dev/null +++ b/FORMULA @@ -0,0 +1,8 @@ +name: xinetd +os: Ubuntu +os_family: Debian +version: 201705 +release: 1 +minimum_version: 2016.11.4 +summary: Formula for installing xinetd +description: Formula for installing xinetd diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..589f271 --- /dev/null +++ b/Gemfile @@ -0,0 +1,9 @@ +source 'https://rubygems.org' + +ruby '2.4.1' + +gem "test-kitchen", '>=2.2.4' +gem "kitchen-docker" +gem "kitchen-salt" +gem 'kitchen-inspec' +gem "kitchen-vagrant" diff --git a/README.rst b/README.rst index 8ab866a..7167596 100644 --- a/README.rst +++ b/README.rst @@ -15,9 +15,13 @@ Available states .. contents:: :local: -``xinetd`` +``xinetd.install`` ---------- Installs the xinetd package and starts the daemon. +``xinetd.config`` +---------- + +Configure xinetd services based on pillar data. diff --git a/pillar.example b/pillar.example new file mode 100644 index 0000000..ba39fed --- /dev/null +++ b/pillar.example @@ -0,0 +1,14 @@ +xinetd: + services: + # Configure custom xinetd services (Options are not checked) + echo: + description: An xinetd internal service which echo's characters back to + # yes or no values needs to be escaped otherwise are treated as booleans + disable: 'yes' + type: INTERNAL + id: echo-stream + socket_type: stream + protocol: tcp + user: root + # yes or no values needs to be escaped otherwise are treated as booleans + wait: 'no' diff --git a/test/integration/default/serverspec/xinetd_spec.rb b/test/integration/default/serverspec/xinetd_spec.rb new file mode 100644 index 0000000..50e3bd2 --- /dev/null +++ b/test/integration/default/serverspec/xinetd_spec.rb @@ -0,0 +1,19 @@ +require 'serverspec' + +# Required by serverspec +set :backend, :exec + +describe "xinetd" do + it "package is installed" do + expect(package("xinetd")).to be_installed + end + + it "service is enabled" do + expect(service("xinetd")).to be_enabled + end + + it "service is running" do + expect(service("xinetd")).to be_running + end + +end diff --git a/xinetd/config.sls b/xinetd/config.sls new file mode 100644 index 0000000..b5f8853 --- /dev/null +++ b/xinetd/config.sls @@ -0,0 +1,16 @@ +{%- from "xinetd/map.jinja" import xinetd with context -%} + +{%- if xinetd.services is iterable %} +{%- for service, config in xinetd.services.items() %} +xinetd_{{ service }}_config: + file.managed: + - name: /etc/xinetd.d/{{ service }} + - source: salt://xinetd/files/config_template + - template: jinja + - context: + service: {{ service }} + config: {{ config|tojson }} + - watch_in: + service: xinetd +{% endfor %} +{% endif %} diff --git a/xinetd/files/config_template b/xinetd/files/config_template new file mode 100644 index 0000000..742c917 --- /dev/null +++ b/xinetd/files/config_template @@ -0,0 +1,15 @@ +# ----------------------------------- +# THIS FILE IS MANAGED BY SALTSTACK +# MANUAL CHANGES WILL BE OVERRIDEN +# ----------------------------------- +{% if config.description is defined %} +# description: {{ config.description }} +{% endif -%} +service {{ service }} +{ +{% for k, v in config.items() -%} +{%- if k != 'description' -%} +{{ '%-15s' | format(k) | indent(2, true) ~ ' = ' ~ v }} +{% endif -%} +{% endfor -%} +} diff --git a/xinetd/init.sls b/xinetd/init.sls index f1f5e05..38a5351 100644 --- a/xinetd/init.sls +++ b/xinetd/init.sls @@ -1,20 +1,3 @@ -{%- from "xinetd/map.jinja" import xinetd with context -%} - -xinetd: - pkg.installed: - - name: {{ xinetd.pkg }} - service.running: - - name: {{ xinetd.service }} - - enable: True - -# The following states are inert by default and can be used by other states to -# trigger a restart or reload as needed. -xinetd-reload: - module.wait: - - name: service.reload - - m_name: {{ xinetd.service }} - -xinetd-restart: - module.wait: - - name: service.restart - - m_name: {{ xinetd.service }} +include: + - xinetd.install + - xinetd.config diff --git a/xinetd/install.sls b/xinetd/install.sls new file mode 100644 index 0000000..f1f5e05 --- /dev/null +++ b/xinetd/install.sls @@ -0,0 +1,20 @@ +{%- from "xinetd/map.jinja" import xinetd with context -%} + +xinetd: + pkg.installed: + - name: {{ xinetd.pkg }} + service.running: + - name: {{ xinetd.service }} + - enable: True + +# The following states are inert by default and can be used by other states to +# trigger a restart or reload as needed. +xinetd-reload: + module.wait: + - name: service.reload + - m_name: {{ xinetd.service }} + +xinetd-restart: + module.wait: + - name: service.restart + - m_name: {{ xinetd.service }} diff --git a/xinetd/map.jinja b/xinetd/map.jinja index 1b88523..f65d599 100644 --- a/xinetd/map.jinja +++ b/xinetd/map.jinja @@ -1,4 +1,13 @@ -{% set xinetd = { - 'pkg': 'xinetd', - 'service': 'xinetd', - } %} +{% set default_settings = salt['grains.filter_by']({ + 'default': { + 'pkg': 'xinetd', + 'service': 'xinetd', + }, +}, merge=salt['pillar.get']('xinetd:lookup')) %} + +{% set xinetd = salt['pillar.get']( + 'xinetd', + default=default_settings, + merge=True + ) +%}