Initial Chef repository

This commit is contained in:
Greg Karékinian
2015-07-21 19:45:23 +02:00
parent 7e5401fc71
commit ee4079fa85
1151 changed files with 185163 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
hostsfile Cookbook CHANGELOG
=======================
This file is used to list changes made in each version of the hostsfile cookbook.
v2.4.5 (2014-06-24)
-------------------
- Fix notifications and why-run mode
v2.4.4 (2014-02-25)
-------------------
- Bump Berkshelf version
- Remove scope pieces from IPv6 addresses
v2.4.3 (2014-02-01)
-------------------
- Package custom ChefSpec matchers
- Update testing harness
- Avoid using `Chef::Application.fatal!`
- Use Chef::Resource::File for atomic updates
v2.4.2
------
- Fix Travis CI integration
- Remove newline characters
- Allow specifying a custom hostsfile path
v2.4.1
------
- Force a new upload to the community site
v2.4.0
------
- Convert everything to Ruby 1.9 syntax because I'm tired of people removing trailing commas despite the **massive** warning in the README: ([#29](https://github.com/customink-webops/hostsfile/issues/29), [#30](https://github.com/customink-webops/hostsfile/issues/30), [#32](https://github.com/customink-webops/hostsfile/issues/32), [#33](https://github.com/customink-webops/hostsfile/issues/33), [#34](https://github.com/customink-webops/hostsfile/issues/34), [#35](https://github.com/customink-webops/hostsfile/issues/35), [#36](https://github.com/customink-webops/hostsfile/issues/36), [#38](https://github.com/customink-webops/hostsfile/issues/38), [#39](https://github.com/customink-webops/hostsfile/issues/39))
- Update to the latest and greatest testing gems and practices
- Remove strainer in favor of a purer solution
- Update `.gitignore` to ignore additional files
- Add more platforms to the `.kitchen.yml`
- Use `converge_by` and support whyruny mode
v2.0.0
------
- Completely manage the hostsfile, ensuring no duplicate entries
v1.0.2
------
- Support Windows (thanks @igantt-daptiv)
- Specs + Travis support
- Throw fatal error if hostsfile does not exist (@jkerzner)
- Write priorities in hostsfile so they are read on subsequent Chef runs
v0.2.0
------
- Updated README to require Ruby 1.9
- Allow hypens in hostnames
- Ensure newline at end of file
- Allow priority ordering in hostsfile
v0.1.1
------
- Fixed issue #1
- Better unique object filtering
- Better handing of aliases
v0.1.0
------
- Initial release

View File

@@ -0,0 +1,234 @@
hostsfile LWRP
==============
[![Build Status](https://travis-ci.org/customink-webops/hostsfile.png?branch=master)](https://travis-ci.org/customink-webops/hostsfile)
`hostsfile` provides an LWRP for managing your `/etc/hosts` (or Windows equivalent) file using Chef.
Requirements
------------
- Chef 11 or higher
- **Ruby 1.9.3 or higher**
**Please stop opening Pull Requests to restore Ruby 1.8 support!** Any of the `1.x.y` series of this cookbook will work with Chef 10 and Ruby 1.8. You can use Opscode's [Omnibus installer](http://www.opscode.com/blog/2012/06/29/omnibus-chef-packaging/) to install Ruby 1.9+ and Seth Chisamore's [Vagrant Omnibus plugin](https://github.com/schisamo/vagrant-omnibus) to get Ruby 1.9+ on your Vagrant box.
Attributes
----------
<table>
<tr>
<th>Attribute</th>
<th>Description</th>
<th>Example</th>
<th>Default</th>
</tr>
<tr>
<td>ip_address</td>
<td>(name attribute) the IP address for the entry</td>
<td><tt>1.2.3.4</tt></td>
<td></td>
</tr>
<tr>
<td>hostname</td>
<td>(required) the hostname associated with the entry</td>
<td><tt>example.com</tt></td>
<td></td>
</tr>
<tr>
<td>unique</td>
<td>remove any existing entries that have the same <tt>hostname</tt></td>
<td><tt>true</tt></td>
<td><tt>false</tt></td>
</tr>
<tr>
<td>aliases</td>
<td>array of aliases for the entry</td>
<td><tt>['www.example.com']</tt></td>
<td><tt>[]</tt></td>
</tr>
<tr>
<td>comment</td>
<td>a comment to append to the end of the entry</td>
<td><tt>'interal DNS server'</tt></td>
<td><tt>nil</tt></td>
</tr>
<tr>
<td>priority</td>
<td>the relative position of this entry</td>
<td><tt>20</tt></td>
<td>(varies, see **Priorities** section)</td>
</tr>
</table>
Actions
-------
**Please note**: In `v0.1.2`, specifying a hostname or alias that existed in another automatically removed that hostname from the other entry before. In `v2.1.0`, the `unique` option was added to give the user case-by-case control of this behavior. For example, given an `/etc/hosts` file that contains:
1.2.3.4 example.com www.example.com
when the Chef recipe below is converged:
```ruby
hostsfile_entry '2.3.4.5' do
hostname 'www.example.com'
unique true
end
```
then the `/etc/hosts` file will look like this:
1.2.3.4 example.com
2.3.4.5 www.example.com
Not specifying the `unique` parameter will result in duplicate hostsfile entries.
#### `create`
Creates a new hosts file entry. If an entry already exists, it will be overwritten by this one.
```ruby
hostsfile_entry '1.2.3.4' do
hostname 'example.com'
action :create
end
```
This will create an entry like this:
1.2.3.4 example.com
#### `create_if_missing`
Create a new hosts file entry, only if one does not already exist for the given IP address. If one exists, this does nothing.
```ruby
hostsfile_entry '1.2.3.4' do
hostname 'example.com'
action :create_if_missing
end
```
#### `append`
Append a hostname or alias to an existing record. If the given IP address doesn't already exist in the hostsfile, this method behaves the same as create. Otherwise, it will append the additional hostname and aliases to the existing entry.
1.2.3.4 example.com www.example.com # Created by Chef
```ruby
hostsfile_entry '1.2.3.4' do
hostname 'www2.example.com'
aliases ['foo.com', 'foobar.com']
comment 'Append by Recipe X'
action :append
end
```
would yield:
1.2.3.4 example.com www.example.com www2.example.com foo.com foobar.com # Created by Chef, Appended by Recipe X
#### `update`
Updates the given hosts file entry. Does nothing if the entry does not exist.
```ruby
hostsfile_entry '1.2.3.4' do
hostname 'example.com'
comment 'Update by Chef'
action :update
end
```
This will create an entry like this:
1.2.3.4 example # Updated by Chef
#### `remove`
Removes an entry from the hosts file. Does nothing if the entry does not
exist.
```ruby
hostsfile_entry '1.2.3.4' do
action :remove
end
```
This will remove the entry for `1.2.3.4`.
Usage
-----
If you're using [Berkshelf](http://berkshelf.com/), just add `hostsfile` to your `Berksfile`:
```ruby
cookbook 'hostsfile'
```
Otherwise, install the cookbook from the community site:
knife cookbook site install hostsfile
Have any other cookbooks *depend* on hostsfile by editing editing the `metadata.rb` for your cookbook.
```ruby
# metadata.rb
depends 'hostsfile'
```
Note that you can specify a custom path to your hosts file in the `['hostsfile']['path']` node attribute. Otherwise, it defaults to sensible paths depending on your OS.
### Testing
If you are using [ChefSpec](https://github.com/sethvargo/chefspec) to unit test a cookbook that implements the `hostsfile_entry` LWRP, this cookbook packages customer matchers that you can use in your unit tests:
- `append_hostsfile_entry`
- `create_hostsfile_entry`
- `create_hostsfile_entry_if_missing`
- `remove_hostsfile_entry`
- `update_hostsfile_entry`
For example:
```ruby
it 'creates a hostsfile entry for the DNS server' do
expect(chef_run).to create_hostsfile_entry('1.2.3.4')
.with_hostname('dns.example.com')
end
```
Priority
--------
Priority is a relatively new addition to the cookbook. It gives you the ability to (somewhat) specify the relative order of entries. By default, the priority is calculated for you as follows:
1. Local, loopback
2. IPV4
3. IPV6
However, you can override it using the `priority` option.
Contributing
------------
1. Fork the project
2. Create a feature branch corresponding to you change
3. Commit and test thoroughly
4. Create a Pull Request on github
License & Authors
-----------------
- Author:: Seth Vargo (sethvargo@gmail.com)
```text
Copyright 2012-2013, Seth Vargo
Copyright 2012, CustomInk, LLC
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.
```

View File

@@ -0,0 +1,22 @@
#
# Author:: Seth Vargo <sethvargo@gmail.com>
# Cookbook:: hostsfile
# Attribute:: default
#
# Copyright 2012-2013, Seth Vargo
# Copyright 2012, CustomInk, LCC
#
# 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.
#
default['hostsfile']['path'] = nil

View File

@@ -0,0 +1,183 @@
#
# Author:: Seth Vargo <sethvargo@gmail.com>
# Cookbook:: hostsfile
# Library:: entry
#
# Copyright 2012-2013, Seth Vargo
# Copyright 2012, CustomInk, LCC
#
# 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.
#
require 'ipaddr'
# An object representation of a single line in a hostsfile.
#
# @author Seth Vargo <sethvargo@gmail.com>
class Entry
class << self
# Creates a new Hostsfile::Entry object by parsing a text line. The
# `line` attribute will be in the following format:
#
# 1.2.3.4 hostname [alias[, alias[, alias]]] [# comment [@priority]]
#
# @param [String] line
# the line to parse
# @return [Entry]
# a new entry object
def parse(line)
entry, comment = extract_comment(line)
comment, priority = extract_priority(comment)
entries = extract_entries(entry)
# Return nil if the line is empty
return nil if entries.nil? || entries.empty?
# If /etc/hosts has a broken content we throw a descriptive exception
if entries[0].nil?
raise ArgumentError, "/etc/hosts has a line without IP address: #{line}"
end
if entries[1].nil?
raise ArgumentError, "/etc/hosts has a line without hostname: #{line}"
end
return self.new(
ip_address: entries[0],
hostname: entries[1],
aliases: entries[2..-1],
comment: comment,
priority: priority,
)
end
private
def extract_comment(line)
return nil if presence(line).nil?
line.split('#', 2).collect { |part| presence(part) }
end
def extract_priority(comment)
return nil if comment.nil?
if comment.include?('@')
comment.split('@', 2).collect { |part| presence(part) }
else
[comment, nil]
end
end
def extract_entries(entry)
return nil if entry.nil?
entry.split(/\s+/).collect { |entry| presence(entry) }.compact
end
def presence(string)
return nil if string.nil?
return nil if string.strip.empty?
string.strip
end
end
# @return [String]
attr_accessor :ip_address, :hostname, :aliases, :comment, :priority
# Creates a new entry from the given options.
#
# @param [Hash] options
# a list of options to create the entry with
# @option options [String] :ip_address
# the IP Address for this entry
# @option options [String] :hostname
# the hostname for this entry
# @option options [String, Array<String>] :aliases
# a alias or array of aliases for this entry
# @option options[String] :comment
# an optional comment for this entry
# @option options [Fixnum] :priority
# the relative priority of this entry (compared to others)
#
# @raise [ArgumentError]
# if neither :ip_address nor :hostname are supplied
def initialize(options = {})
if options[:ip_address].nil? || options[:hostname].nil?
raise ArgumentError, ':ip_address and :hostname are both required options'
end
@ip_address = IPAddr.new(remove_ip_scope(options[:ip_address]))
@hostname = options[:hostname]
@aliases = [options[:aliases]].flatten.compact
@comment = options[:comment]
@priority = options[:priority] || calculated_priority
end
# Set a the new priority for an entry.
#
# @param [Fixnum] new_priority
# the new priority to set
def priority=(new_priority)
@calculated_priority = false
@priority = new_priority
end
# The line representation of this entry.
#
# @return [String]
# the string representation of this entry
def to_line
hosts = [hostname, aliases].flatten.join(' ')
comments = "# #{comment.to_s}".strip
comments << " @#{priority}" unless priority.nil? || @calculated_priority
comments = comments.strip
comments = nil if comments == '#'
[ip_address, hosts, comments].compact.join("\t").strip
end
# Returns true if priority is calculated
#
# @return [Boolean]
# true if priority is calculated and false otherwise
def calculated_priority?
@calculated_priority
end
private
# Calculates the relative priority of this entry.
#
# @return [Fixnum]
# the relative priority of this item
def calculated_priority
@calculated_priority = true
return 81 if ip_address == IPAddr.new('127.0.0.1')
return 80 if IPAddr.new('127.0.0.0/8').include?(ip_address) # local
return 60 if ip_address.ipv4? # ipv4
return 20 if ip_address.ipv6? # ipv6
return 00
end
# Removes the scopes pieces of the address, because reasons.
#
# @see https://bugs.ruby-lang.org/issues/8464
# @see https://github.com/customink-webops/hostsfile/issues/51
#
# @return [String, nil]
#
def remove_ip_scope(address)
return nil if address.nil?
address.to_s.sub(/%.*/, '')
end
end

View File

@@ -0,0 +1,293 @@
#
# Author:: Seth Vargo <sethvargo@gmail.com>
# Cookbook:: hostsfile
# Library:: manipulator
#
# Copyright 2012-2013, Seth Vargo
# Copyright 2012, CustomInk, LCC
#
# 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.
#
require 'chef/application'
require 'digest/sha2'
class Manipulator
attr_reader :node
attr_reader :entries
# Create a new Manipulator object (aka an /etc/hosts manipulator). If a
# hostsfile is not found, an exception is raised.
#
# @param [Chef::node] node
# the current Chef node
# @return [Manipulator]
# a class designed to manipulate the node's /etc/hosts file
def initialize(node)
@node = node
# Fail if no hostsfile is found
unless ::File.exists?(hostsfile_path)
raise RuntimeError, "No hostsfile exists at `#{hostsfile_path}'!"
end
@entries = []
collect_and_flatten(::File.readlines(hostsfile_path))
end
# Return a list of all IP Addresses for this hostsfile.
#
# @return [Array<IPAddr>]
# the list of IP Addresses
def ip_addresses
@entries.collect do |entry|
entry.ip_address
end.compact || []
end
# Add a new record to the hostsfile.
#
# @param [Hash] options
# a list of options to create the entry with
# @option options [String] :ip_address
# the IP Address for this entry
# @option options [String] :hostname
# the hostname for this entry
# @option options [String, Array<String>] :aliases
# a alias or array of aliases for this entry
# @option options[String] :comment
# an optional comment for this entry
# @option options [Fixnum] :priority
# the relative priority of this entry (compared to others)
def add(options = {})
entry = Entry.new(
ip_address: options[:ip_address],
hostname: options[:hostname],
aliases: options[:aliases],
comment: options[:comment],
priority: options[:priority],
)
@entries << entry
remove_existing_hostnames(entry) if options[:unique]
end
# Update an existing entry. This method will do nothing if the entry
# does not exist.
#
# @param (see #add)
def update(options = {})
if entry = find_entry_by_ip_address(options[:ip_address])
entry.hostname = options[:hostname]
entry.aliases = options[:aliases]
entry.comment = options[:comment]
entry.priority = options[:priority]
remove_existing_hostnames(entry) if options[:unique]
end
end
# Append content to an existing entry. This method will add a new entry
# if one does not already exist.
#
# @param (see #add)
def append(options = {})
if entry = find_entry_by_ip_address(options[:ip_address])
hosts = normalize(entry.hostname, entry.aliases, options[:hostname], options[:aliases])
entry.hostname = hosts.shift
entry.aliases = hosts
unless entry.comment && options[:comment] && entry.comment.include?(options[:comment])
entry.comment = normalize(entry.comment, options[:comment]).join(', ')
end
remove_existing_hostnames(entry) if options[:unique]
else
add(options)
end
end
# Remove an entry by it's IP Address
#
# @param [String] ip_address
# the IP Address of the entry to remove
def remove(ip_address)
if entry = find_entry_by_ip_address(ip_address)
@entries.delete(entry)
end
end
# Save the new hostsfile to the target machine. This method will only write the
# hostsfile if the current version has changed. In other words, it is convergent.
def save
file = Chef::Resource::File.new(hostsfile_path, node.run_context)
file.content(new_content)
file.run_action(:create)
end
# Determine if the content of the hostfile has changed by comparing sha
# values of existing file and new content
#
# @return [Boolean]
def content_changed?
new_sha = Digest::SHA512.hexdigest(new_content)
new_sha != current_sha
end
# Find an entry by the given IP Address.
#
# @param [String] ip_address
# the IP Address of the entry to find
# @return [Entry, nil]
# the corresponding entry object, or nil if it does not exist
def find_entry_by_ip_address(ip_address)
@entries.find do |entry|
!entry.ip_address.nil? && entry.ip_address == ip_address
end
end
# Determine if the current hostsfile contains the given resource. This
# is really just a proxy to {find_resource_by_ip_address} /
#
# @param [Chef::Resource] resource
#
# @return [Boolean]
def contains?(resource)
!!find_entry_by_ip_address(resource.ip_address)
end
private
# The path to the current hostsfile.
#
# @return [String]
# the full path to the hostsfile, depending on the operating system
# can also be overriden in the node attributes
def hostsfile_path
return @hostsfile_path if @hostsfile_path
@hostsfile_path = node['hostsfile']['path'] || case node['platform_family']
when 'windows'
"#{node['kernel']['os_info']['system_directory']}\\drivers\\etc\\hosts"
else
'/etc/hosts'
end
end
# The header of the new hostsfile
#
# @return [Array]
# an array of header comments
def hostsfile_header
lines = []
lines << '#'
lines << '# This file is managed by Chef, using the hostsfile cookbook.'
lines << '# Editing this file by hand is highly discouraged!'
lines << '#'
lines << '# Comments containing an @ sign should not be modified or else'
lines << '# hostsfile will be unable to guarantee relative priority in'
lines << '# future Chef runs!'
lines << '#'
lines << ''
end
# The content that will be written to the hostfile
#
# @return [String]
# the full contents of the hostfile to be written
def new_content
entries = hostsfile_header
entries += unique_entries.map(&:to_line)
entries << ''
entries.join("\n")
end
# The current sha of the system hostsfile.
#
# @return [String]
# the sha of the current hostsfile
def current_sha
@current_sha ||= Digest::SHA512.hexdigest(File.read(hostsfile_path))
end
# Normalize the given list of elements into a single array with no nil
# values and no duplicate values.
#
# @param [Object] things
#
# @return [Array]
# a normalized array of things
def normalize(*things)
things.flatten.compact.uniq
end
# This is a crazy way of ensuring unique objects in an array using a Hash.
#
# @return [Array]
# the sorted list of entires that are unique
def unique_entries
entries = Hash[*@entries.map { |entry| [entry.ip_address, entry] }.flatten].values
entries.sort_by { |e| [-e.priority.to_i, e.hostname.to_s] }
end
# Takes /etc/hosts file contents and builds a flattened entries
# array so that each IP address has only one line and multiple hostnames
# are flattened into a list of aliases.
#
# @param [Array] contents
# Array of lines from /etc/hosts file
def collect_and_flatten(contents)
contents.each do |line|
entry = Entry.parse(line)
next if entry.nil?
append(
ip_address: entry.ip_address,
hostname: entry.hostname,
aliases: entry.aliases,
comment: entry.comment,
priority: !entry.calculated_priority? && entry.priority,
)
end
end
# Removes duplicate hostnames in other files ensuring they are unique
#
# @param [Entry] entry
# the entry to keep the hostname and aliases from
#
# @return [nil]
def remove_existing_hostnames(entry)
@entries.delete(entry)
changed_hostnames = [entry.hostname, entry.aliases].flatten.uniq
@entries = @entries.collect do |entry|
entry.hostname = nil if changed_hostnames.include?(entry.hostname)
entry.aliases = entry.aliases - changed_hostnames
if entry.hostname.nil?
if entry.aliases.empty?
nil
else
entry.hostname = entry.aliases.shift
entry
end
else
entry
end
end.compact
@entries << entry
nil
end
end

View File

@@ -0,0 +1,21 @@
if defined?(ChefSpec)
def append_hostsfile_entry(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:hostsfile_entry, :append, resource_name)
end
def create_hostsfile_entry(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:hostsfile_entry, :create, resource_name)
end
def create_hostsfile_entry_if_missing(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:hostsfile_entry, :create_if_missing, resource_name)
end
def remove_hostsfile_entry(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:hostsfile_entry, :remove, resource_name)
end
def update_hostsfile_entry(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:hostsfile_entry, :update, resource_name)
end
end

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,7 @@
name 'hostsfile'
maintainer 'Seth Vargo'
maintainer_email 'sethvargo@gmail.com'
license 'Apache 2.0'
description 'Provides an LWRP for managing the /etc/hosts file'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version '2.4.5'

View File

@@ -0,0 +1,138 @@
#
# Author:: Seth Vargo <sethvargo@gmail.com>
# Cookbook:: hostsfile
# Provider:: entry
#
# Copyright 2012-2013, Seth Vargo
# Copyright 2012, CustomInk, LCC
#
# 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.
#
# Support whyrun
def whyrun_supported?
true
end
# Creates a new hosts file entry. If an entry already exists, it will be
# overwritten by this one.
action :create do
if hostsfile.contains?(new_resource)
Chef::Log.debug "#{new_resource} already exists - overwriting."
end
hostsfile.add(
ip_address: new_resource.ip_address,
hostname: new_resource.hostname,
aliases: new_resource.aliases,
comment: new_resource.comment,
priority: new_resource.priority,
unique: new_resource.unique,
)
if hostsfile.content_changed?
converge_by("Create #{new_resource}") { hostsfile.save }
else
Chef::Log.info "#{new_resource} content already matches - nothing to do."
end
end
# Create a new hosts file entry, only if one does not already exist for
# the given IP address. If one exists, this does nothing.
action :create_if_missing do
if hostsfile.contains?(new_resource)
Chef::Log.info "#{new_resource} already exists - skipping create_if_missing."
else
converge_by("Create #{new_resource} if missing") do
hostsfile.add(
ip_address: new_resource.ip_address,
hostname: new_resource.hostname,
aliases: new_resource.aliases,
comment: new_resource.comment,
priority: new_resource.priority,
unique: new_resource.unique,
)
hostsfile.save
end
end
end
# Appends the given data to an existing entry. If an entry does not exist,
# one will be created
action :append do
unless hostsfile.contains?(new_resource)
Chef::Log.info "#{new_resource} does not exist - creating instead."
end
hostsfile.append(
ip_address: new_resource.ip_address,
hostname: new_resource.hostname,
aliases: new_resource.aliases,
comment: new_resource.comment,
priority: new_resource.priority,
unique: new_resource.unique,
)
if hostsfile.content_changed?
converge_by("Append #{new_resource}") { hostsfile.save }
else
Chef::Log.info "#{new_resource} content already matches - nothing to do."
end
end
# Updates the given hosts file entry. Does nothing if the entry does not
# exist.
action :update do
if hostsfile.contains?(new_resource)
hostsfile.update(
ip_address: new_resource.ip_address,
hostname: new_resource.hostname,
aliases: new_resource.aliases,
comment: new_resource.comment,
priority: new_resource.priority,
unique: new_resource.unique,
)
if hostsfile.content_changed?
converge_by("Update #{new_resource}") { hostsfile.save }
else
Chef::Log.info "#{new_resource} content already matches - nothing to do."
end
else
Chef::Log.info "#{new_resource} does not exist - skipping update."
end
end
# Removes an entry from the hosts file. Does nothing if the entry does
# not exist.
action :remove do
if hostsfile.contains?(new_resource)
converge_by("Remove #{new_resource}") do
hostsfile.remove(new_resource.ip_address)
hostsfile.save
end
else
Chef::Log.info "#{new_resource} does not exist - skipping remove."
end
end
private
# The hostsfile object
#
# @return [Manipulator]
# the manipulator for this hostsfile
def hostsfile
@hostsfile ||= Manipulator.new(node)
end

View File

@@ -0,0 +1,36 @@
#
# Author:: Seth Vargo <sethvargo@gmail.com>
# Cookbook:: hostsfile
# Resource:: entry
#
# Copyright 2012-2013, Seth Vargo
# Copyright 2012, CustomInk, LCC
#
# 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.
#
# List of all actions supported by the provider
actions :create, :create_if_missing, :append, :update, :remove
# Make create the default action
default_action :create
# Required attributes
attribute :ip_address, kind_of: String, name_attribute: true
attribute :hostname, kind_of: String
# Optional attributes
attribute :aliases, kind_of: Array
attribute :comment, kind_of: String
attribute :priority, kind_of: Fixnum
attribute :unique, kind_of: [TrueClass, FalseClass]