Skip to content

Commit bc173c6

Browse files
Rob Emanuelerjemanuele
authored andcommitted
Add domains and subnets to the puppet API
1 parent 71d6c22 commit bc173c6

File tree

7 files changed

+333
-0
lines changed

7 files changed

+333
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
Puppet::Type.type(:foreman_domain).provide(:rest_v3, :parent => Puppet::Type.type(:foreman_resource).provider(:rest_v3)) do
2+
confine :feature => [:json, :oauth]
3+
4+
def exists?
5+
!id.nil?
6+
end
7+
8+
def create
9+
path = "api/v2/domains"
10+
payload = {
11+
:domain => {
12+
:name => resource[:name],
13+
:fullname => resource[:fullname],
14+
:dns_id => search('smart_proxies', resource[:dns_id]),
15+
}
16+
}
17+
18+
req = request(:post, path, {}, payload.to_json)
19+
20+
unless success?(req)
21+
error_string = "Error making POST request to Foreman at #{request_uri(path)}: #{error_message(req)}"
22+
raise Puppet::Error.new(error_string)
23+
end
24+
end
25+
26+
def destroy
27+
req = request(:delete, destroy_path, {})
28+
29+
unless success?(req)
30+
error_string = "Error making DELETE request to Foreman at #{request_uri(path)}: #{error_message(req)}"
31+
raise Puppet::Error.new(error_string)
32+
end
33+
end
34+
35+
def id
36+
domain['id'] if domain
37+
end
38+
39+
def domain
40+
@domain ||= begin
41+
path = 'api/v2/domains'
42+
req = request(:get, path, :search => %{name="#{resource[:name]}"})
43+
44+
unless success?(req)
45+
error_string = "Error making GET request to Foreman at #{request_uri(path)}: #{error_message(req)}"
46+
raise Puppet::Error.new(error_string)
47+
end
48+
49+
JSON.load(req.body)['results'].first
50+
end
51+
end
52+
53+
private
54+
55+
def destroy_path
56+
"api/v2/domains/#{id}"
57+
end
58+
end

lib/puppet/provider/foreman_resource/rest_v3.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,19 @@ def error_message(response)
131131
JSON.parse(response.body)['error']['full_messages'].join(' ') rescue "Response: #{response.code} #{response.message}"
132132
end
133133
end
134+
135+
def search(id_name, value)
136+
if !value.nil? and value.start_with?("search=") then
137+
lookup_uri = "api/v2/" + id_name + "?" + value
138+
lookup = request(:get, lookup_uri)
139+
unless success?(lookup)
140+
error_string = "Error making GET request to Foreman at #{lookup_uri}: #{error_message(lookup)}"
141+
raise Puppet::Error.new(error_string)
142+
end
143+
144+
JSON.load(lookup.body)['results'][0]['id']
145+
else
146+
value
147+
end
148+
end
134149
end
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
Puppet::Type.type(:foreman_subnet).provide(:rest_v3, :parent => Puppet::Type.type(:foreman_resource).provider(:rest_v3)) do
2+
confine :feature => [:json, :oauth]
3+
4+
def exists?
5+
!id.nil?
6+
end
7+
8+
def create
9+
path = "api/v2/subnets"
10+
payload = {
11+
:subnet => {
12+
:name => resource[:name],
13+
:description => resource[:description],
14+
:network_type => resource[:network_type],
15+
:network => resource[:network],
16+
:cidr => resource[:cidr],
17+
:mask => resource[:mask],
18+
:gateway => resource[:gateway],
19+
:dns_primary => resource[:dns_primary],
20+
:dns_secondary => resource[:dns_secondary],
21+
:ipam => !resource[:ipam].nil? ? resource[:ipam] : 'None',
22+
:from => resource[:from],
23+
:to => resource[:to],
24+
:vlanid => resource[:vlanid],
25+
:domain_ids => resource[:domain_ids].map {|s| search('domains', s)},
26+
:dhcp_id => search('smart_proxies', resource[:dhcp_id]),
27+
:tftp_id => search('smart_proxies', resource[:tftp_id]),
28+
:httpboot_id => search('smart_proxies', resource[:httpboot_id]),
29+
:dns_id => search('smart_proxies', resource[:dns_id]),
30+
:template_id => search('smart_proxies', resource[:template_id]),
31+
:bmc_id => search('smart_proxies', resource[:bmc_id]),
32+
}
33+
}
34+
35+
req = request(:post, path, {}, payload.to_json)
36+
37+
unless success?(req)
38+
error_string = "Error making POST request to Foreman at #{request_uri(path)}: #{error_message(req)}"
39+
raise Puppet::Error.new(error_string)
40+
end
41+
end
42+
43+
def destroy
44+
req = request(:delete, destroy_path, {})
45+
46+
unless success?(req)
47+
error_string = "Error making DELETE request to Foreman at #{request_uri(path)}: #{error_message(req)}"
48+
raise Puppet::Error.new(error_string)
49+
end
50+
end
51+
52+
def id
53+
subnet['id'] if subnet
54+
end
55+
56+
def subnet
57+
@subnet ||= begin
58+
path = 'api/v2/subnets'
59+
req = request(:get, path, :search => %{name="#{resource[:name]}"})
60+
61+
unless success?(req)
62+
error_string = "Error making GET request to Foreman at #{request_uri(path)}: #{error_message(req)}"
63+
raise Puppet::Error.new(error_string)
64+
end
65+
66+
JSON.load(req.body)['results'].first
67+
end
68+
end
69+
70+
private
71+
72+
def destroy_path
73+
"api/v2/subnets/#{id}"
74+
end
75+
end

lib/puppet/type/foreman_domain.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
require_relative '../../puppet_x/foreman/common'
2+
3+
Puppet::Type.newtype(:foreman_domain) do
4+
desc 'foreman_domain creates a domain in foreman.'
5+
6+
instance_eval(&PuppetX::Foreman::Common::REST_API_COMMON_PARAMS)
7+
instance_eval(&PuppetX::Foreman::Common::FOREMAN_DOMAIN_PARAMS)
8+
9+
end

lib/puppet/type/foreman_subnet.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
require_relative '../../puppet_x/foreman/common'
2+
3+
Puppet::Type.newtype(:foreman_subnet) do
4+
desc 'foreman_subnet creates a subnet in foreman.'
5+
6+
instance_eval(&PuppetX::Foreman::Common::REST_API_COMMON_PARAMS)
7+
instance_eval(&PuppetX::Foreman::Common::FOREMAN_SUBNET_PARAMS)
8+
9+
end

lib/puppet_x/foreman/common.rb

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,102 @@ module Common
5656
desc 'The name of the host.'
5757
end
5858
end
59+
60+
FOREMAN_DOMAIN_PARAMS = Proc.new do
61+
newparam(:name, :namevar => true) do
62+
desc 'The name of the domain resource.'
63+
end
64+
65+
newparam(:fullname) do
66+
desc 'The name/description of the domain.'
67+
end
68+
69+
newparam(:dns_id) do
70+
desc 'DNS Smart Proxy ID.'
71+
end
72+
end
73+
74+
FOREMAN_SUBNET_PARAMS = Proc.new do
75+
newparam(:name, :namevar => true) do
76+
desc 'The name of the subnet resource.'
77+
end
78+
79+
newparam(:description) do
80+
desc 'The subnet description.'
81+
end
82+
83+
newparam(:network_type) do
84+
desc 'The subnet network type, either "IPv4" or "IPv6".'
85+
end
86+
87+
newparam(:network) do
88+
desc 'The subnet network address.'
89+
end
90+
91+
newparam(:cidr) do
92+
desc 'The subnet network CIDR.'
93+
end
94+
95+
newparam(:mask) do
96+
desc 'The subnet network mask.'
97+
end
98+
99+
newparam(:gateway) do
100+
desc 'The subnet gateway.'
101+
end
102+
103+
newparam(:dns_primary) do
104+
desc 'Primary DNS address.'
105+
end
106+
107+
newparam(:dns_secondary) do
108+
desc 'Secondary DNS address.'
109+
end
110+
111+
newparam(:ipam) do
112+
desc 'IPAM Source type.'
113+
end
114+
115+
newparam(:to) do
116+
desc 'Static IPAM end address.'
117+
end
118+
119+
newparam(:from) do
120+
desc 'Static IPAM start address.'
121+
end
122+
123+
newparam(:vlanid) do
124+
desc 'VLAN ID for this subnet.'
125+
end
126+
127+
newparam(:domain_ids) do
128+
desc 'Domain IDs or searches to attribute to subnet.'
129+
end
130+
131+
newparam(:dhcp_id) do
132+
desc 'DHCP Smart Proxy ID.'
133+
end
134+
135+
newparam(:tftp_id) do
136+
desc 'TFTP Smart Proxy ID.'
137+
end
138+
139+
newparam(:httpboot_id) do
140+
desc 'HTTP Boot Smart Proxy ID.'
141+
end
142+
143+
newparam(:dns_id) do
144+
desc 'DNS Smart Proxy ID.'
145+
end
146+
147+
newparam(:template_id) do
148+
desc 'Template Smart Proxy ID.'
149+
end
150+
151+
newparam(:bmc_id) do
152+
desc 'BMC Smart Proxy ID.'
153+
end
154+
end
59155
end
60156
end
61157
end
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
require 'spec_helper'
2+
3+
describe Puppet::Type.type(:foreman_domain).provider(:rest_v3) do
4+
let(:resource) do
5+
Puppet::Type.type(:foreman_domain).new(
6+
:name => 'example.com',
7+
:fullname => 'domain entry for example.com',
8+
:base_url => 'https://foreman.example.com',
9+
:consumer_key => 'oauth_key',
10+
:consumer_secret => 'oauth_secret',
11+
:effective_user => 'admin'
12+
)
13+
end
14+
15+
let(:provider) do
16+
provider = described_class.new
17+
provider.resource = resource
18+
provider
19+
end
20+
21+
describe '#create' do
22+
it 'sends POST request' do
23+
expect(provider).to receive(:request).with(:post, 'api/v2/domains', {}, kind_of(String)).and_return(
24+
double(:code => '201', :body => {'id' => 1, 'name' => 'example.com', 'fullname' => 'domain entry for example.com'})
25+
)
26+
provider.create
27+
end
28+
end
29+
30+
describe '#destroy' do
31+
it 'sends DELETE request' do
32+
expect(provider).to receive(:id).and_return(1)
33+
expect(provider).to receive(:request).with(:delete, 'api/v2/domains/1', {}).and_return(double(:code => '204'))
34+
provider.destroy
35+
end
36+
end
37+
38+
describe '#exists?' do
39+
it 'returns true when domain is marked as a foreman domain' do
40+
expect(provider).to receive(:domain).twice.and_return({"id" => 1})
41+
expect(provider.exists?).to be true
42+
end
43+
44+
it 'returns nil when domain does not exist' do
45+
expect(provider).to receive(:domain).and_return(nil)
46+
expect(provider.exists?).to be false
47+
end
48+
end
49+
50+
describe '#id' do
51+
it 'returns ID from domain hash' do
52+
expect(provider).to receive(:domain).twice.and_return({'id' => 1})
53+
expect(provider.id).to eq(1)
54+
end
55+
56+
it 'returns nil when domain is absent' do
57+
expect(provider).to receive(:domain).and_return(nil)
58+
expect(provider.id).to be_nil
59+
end
60+
end
61+
62+
describe '#domain' do
63+
it 'returns domain hash from API results' do
64+
expect(provider).to receive(:request).with(:get, 'api/v2/domains', :search => 'name="example.com"').and_return(
65+
double('response', :body => {:results => [{:id => 1, :name => 'example.com'}]}.to_json, :code => '200')
66+
)
67+
expect(provider.domain['id']).to eq(1)
68+
expect(provider.domain['name']).to eq('example.com')
69+
end
70+
end
71+
end

0 commit comments

Comments
 (0)