Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add foreman_location and foreman_organization resources #1179

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
160 changes: 160 additions & 0 deletions lib/puppet/provider/foreman_location/rest_v3.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# frozen_string_literal: true

Puppet::Type.type(:foreman_location).provide( # rubocop:disable Metrics/BlockLength
:rest_v3,
parent: Puppet::Type.type(:foreman_resource).provider(:rest_v3)
) do
desc 'foreman_location configures a location in foreman.'
confine feature: %i[json oauth]

def initialize(value = {})
super(value)
@property_flush = {}
end

def location # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
@location ||= begin
loc_search = search('locations', 'name', resource[:name]).first

return nil if loc_search.nil?

path = "api/v2/locations/#{loc_search['id']}"
req = request(:get, path)

unless success?(req)
raise Puppet::Error, "Error making GET request to Foreman at #{request_uri(path)}: #{error_message(req)}"
end

result = JSON.parse(req.body)
debug("Using Foreman Location '#{resource[:name]}' with: #{result}")
result
end
end

def id
location['id'] if location
end

def exists?
!id.nil?
end

def create # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
debug("Creating Foreman Location #{resource[:name]}")

path = 'api/v2/locations'
payload = {
location: {
name: resource[:name],
parent_id: resource[:parent] ? location_id(resource[:parent]) : nil,
description: resource[:description],
ignore_types: resource[:select_all_types],
domain_ids: domain_ids(resource[:domains]),
organization_ids: organization_ids(resource[:organizations])
}
}
req = request(:post, path, {}, payload.to_json)

return if success?(req)

raise Puppet::Error, "Error making POST request to Foreman at #{request_uri(path)}: #{error_message(req)}"
end

def destroy
debug("Destroying Foreman Location #{resource[:name]}")

path = "api/v2/locations/#{id}"
req = request(:delete, path)

unless success?(req)
raise Puppet::Error, "Error making DELETE request to Foreman at #{request_uri(path)}: #{error_message(req)}"
end

@location = nil
end

def flush
return if @property_flush.empty?

debug("Calling API to update properties for Foreman Location #{resource[:name]} with: #{@property_flush}")

path = "api/v2/locations/#{id}"
req = request(:put, path, {}, { location: @property_flush }.to_json)

return if success?(req)

raise Puppet::Error, "Error making PUT request to Foreman at #{request_uri(path)}: #{error_message(req)}"
end

def parent
location && location['parent_name'] ? locations['parent_name'].split('/')[-1] : nil
end

def parent=(value)
if value.nil?
@property_flush[:parent_id] = nil
else
parent_id = location_id(value)

raise Puppet::Error, "Could not find Foreman Location with name #{value} as parent." if parent_id.nil?

@property_flush[:parent_id] = parent_id
end
end

def description
location ? location['description'] : nil
end

def description=(value)
@property_flush[:description] = value
end

def select_all_types
location ? location['select_all_types'] : []
end

def select_all_types=(value)
@property_flush[:ignore_types] = value
end

def domains
location ? location['domains'].reject { |d| d['inherited'] }.map { |d| d['name'] } : nil
end

def domain_ids(domains)
return nil if domains.nil?

domains.map do |domain|
res = search('domains', 'name', domain).first

raise Puppet::Error, "Could not find Foreman Domain with name '#{domain}'" if res.nil?

res['id']
end
end

def domains=(value)
@property_flush[:domain_ids] = domain_ids(value)
end

def organizations
location ? location['organizations'].reject { |o| o['inherited'] }.map { |o| o['name'] } : nil
end

def organization_ids(orgs)
return nil if orgs.nil?

orgs.map do |organization|
org_id = organization_id(organization)

raise Puppet::Error, "Could not find Foreman Organization with name '#{organization}'" if org_id.nil?

org_id
end
end

def organizations=(value)
@property_flush[:organization_ids] = organization_ids(value)
end
end
160 changes: 160 additions & 0 deletions lib/puppet/provider/foreman_organization/rest_v3.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# frozen_string_literal: true

Puppet::Type.type(:foreman_organization).provide( # rubocop:disable Metrics/BlockLength
:rest_v3,
parent: Puppet::Type.type(:foreman_resource).provider(:rest_v3)
) do
desc 'foreman_organization configures a organization in foreman.'
confine feature: %i[json oauth]

def initialize(value = {})
super(value)
@property_flush = {}
end

def organization # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
@organization ||= begin
org_search = search('organizations', 'name', resource[:name]).first

return nil if org_search.nil?

path = "api/v2/organizations/#{org_search['id']}"
req = request(:get, path)

unless success?(req)
raise Puppet::Error, "Error making GET request to Foreman at #{request_uri(path)}: #{error_message(req)}"
end

result = JSON.parse(req.body)
debug("Using Foreman Organization '#{resource[:name]}' with: #{result}")
result
end
end

def id
organization['id'] if organization
end

def exists?
!id.nil?
end

def create # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
debug("Creating Foreman Organization #{resource[:name]}")

path = 'api/v2/organizations'
payload = {
organization: {
name: resource[:name],
parent_id: resource[:parent] ? organization_id(resource[:parent]) : nil,
description: resource[:description],
ignore_types: resource[:select_all_types],
domain_ids: domain_ids(resource[:domains]),
location_ids: location_ids(resource[:locations])
}
}
req = request(:post, path, {}, payload.to_json)

return if success?(req)

raise Puppet::Error, "Error making POST request to Foreman at #{request_uri(path)}: #{error_message(req)}"
end

def destroy
debug("Destroying Foreman Organization #{resource[:name]}")

path = "api/v2/organizations/#{id}"
req = request(:delete, path)

unless success?(req)
raise Puppet::Error, "Error making DELETE request to Foreman at #{request_uri(path)}: #{error_message(req)}"
end

@organization = nil
end

def flush
return if @property_flush.empty?

debug("Calling API to update properties for Foreman Organization #{resource[:name]} with: #{@property_flush}")

path = "api/v2/organizations/#{id}"
req = request(:put, path, {}, { organization: @property_flush }.to_json)

return if success?(req)

raise Puppet::Error, "Error making PUT request to Foreman at #{request_uri(path)}: #{error_message(req)}"
end

def parent
organization && organization['parent_name'] ? organization['parent_name'].split('/')[-1] : nil
end

def parent=(value)
if value.nil?
@property_flush[:parent_id] = nil
else
parent_id = organization_id(value)

raise Puppet::Error, "Could not find Foreman Organzation with name #{value} as parent." if parent_id.nil?

@property_flush[:parent_id] = parent_id
end
end

def description
organization ? organization['description'] : nil
end

def description=(value)
@property_flush[:description] = value
end

def select_all_types
organization ? organization['select_all_types'] : []
end

def select_all_types=(value)
@property_flush[:ignore_types] = value
end

def domains
organization ? organization['domains'].reject { |d| d['inherited'] }.map { |d| d['name'] } : nil
end

def domain_ids(domains)
return nil if domains.nil?

domains.map do |domain|
res = search('domains', 'name', domain).first

raise Puppet::Error, "Could not find Foreman Domain with name '#{domain}'" if res.nil?

res['id']
end
end

def domains=(value)
@property_flush[:domain_ids] = domain_ids(value)
end

def locations
organization ? organization['locations'].reject { |l| l['inherited'] }.map { |l| l['name'] } : nil
end

def location_ids(locations)
return nil if locations.nil?

locations.map do |location|
location_id = location_id(location)

raise Puppet::Error, "Could not find Foreman Location with name '#{location}'" if location_id.nil?

location_id
end
end

def locations=(value)
@property_flush[:location_ids] = location_ids(value)
end
end
21 changes: 21 additions & 0 deletions lib/puppet/provider/foreman_resource/rest_v3.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,25 @@ def error_message(response)
JSON.parse(response.body)['error']['full_messages'].join(' ') rescue "Response: #{response.code} #{response.message}"
end
end

def search(resource, key, value)
path = "api/v2/#{resource}"
req = request(:get, path, { search: %(#{key}="#{value}"), per_page: 'all' })

unless success?(req)
raise Puppet::Error, "Error making GET request to Foreman at #{request_uri(path)}: #{error_message(req)}"
end

JSON.parse(req.body)['results']
end

def location_id(name)
res = search('locations', 'name', name).first
res.nil? ? nil : res['id']
end

def organization_id(name)
res = search('organizations', 'name', name).first
res.nil? ? nil : res['id']
end
end
37 changes: 37 additions & 0 deletions lib/puppet/type/foreman_location.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

require 'puppet_x/foreman/common'

Puppet::Type.newtype(:foreman_location) do
desc 'foreman_location configures a location in foreman.'

instance_eval(&PuppetX::Foreman::Common::REST_API_COMMON_PARAMS)

newparam(:name) do
desc 'The name of the location'
end

newproperty(:parent) do
desc 'The name of the parent location'
end

newproperty(:description) do
desc 'The description of this location'
end

newproperty(:select_all_types, array_matching: :all) do
desc 'List of resource types for which to "Select All"'
end

newproperty(:domains, array_matching: :all) do
desc 'A list of domain names to allow for this location'
end

newproperty(:organizations, array_matching: :all) do
desc 'A list of organization names to allow for this location'
end

autorequire(:foreman_location) do
self[:parent] if self[:ensure] == :present
end
end
Loading