Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions lib/puppet/provider/network/libvirt.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
require 'libvirt'
require 'erb'
require 'nokogiri'

Puppet::Type.type(:network).provide(:libvirt) do
desc "Create domains with libvirt"

mk_resource_methods

$conn = Libvirt::open('qemu:///system')

def self.parse_network(network)
doc = Nokogiri::XML(network.xml_desc)
definition = {}
definition[:name] = doc.at_xpath('//name').content
definition[:uuid] = doc.at_xpath('//uuid').content
if doc.at_xpath('//bridge') and doc.at_xpath('//bridge').attribute('name')
definition[:bridge] = doc.at_xpath('//bridge').attribute('name').content
end
if doc.at_xpath('//forward')
forward = doc.at_xpath('//forward')
if forward.attribute('mode')
definition[:forward_mode] = forward.attribute('mode').content
end
if forward.attribute('dev')
definition[:forward_dev] = forward.attribute('dev').content
end
if forward.xpath('//interface')
definition[:forward_interfaces] = []
for int in forward.xpath('//interface')
definition[:forward_interfaces].push(int.attribute('dev').content)
end
end
end
if doc.xpath('//ip')
definition[:ip] = []
definition[:ipv6] = []
for ip in doc.xpath('//ip')
data = {}
for setting in ['address', 'netmask', 'prefix']
if ip.attribute(setting)
data[setting] = ip.attribute(setting).content
end
end
if ip.at_xpath('//dhcp')
data[:dhcp] = {}
for setting in ['start', 'end']
data[:dhcp][setting] = ip.at_xpath('//dhcp/range').attribute(setting).content
end
if ip.at_xpath('//dhcp/bootp')
data[:dhcp][:bootp_file] = ip.at_xpath('//dhcp/bootp').attribute('file').content
end
end
if ip.attribute('family') and ip.attribute('family').content == 'ipv6'
definition[:ipv6].push(data)
else
definition[:ip].push(data)
end
end
end
if doc.at_xpath('//mac')
definition[:mac] = doc.at_xpath('//mac').attribute('address').content
end
return definition
end

def self.instances
networks = []
for net in $conn.list_all_networks() do
hash = parse_network(net)
hash[:autostart] = net.autostart?
networks << new(hash)
end
return networks
end

def self.prefetch(resources)
instances.each do |prov|
if resource = resources[prov.name]
resource.provider = prov
end
end
end

def create
# @property_hash = @resource
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason why this code is commented out?
can we do better here? Or should we just remove #create altogether, seeing as this is done in #flush?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commented out line is leftover from some experimentation, I'll remove it. The create function must exist, even if it's empty, otherwise puppet will throw an error.

end


def flush
debug("flushing '" + @resource[:name] + "' with: " + @property_hash.to_s )
net_xml = <<EOF
<network>
<name><%= @resource[:name] %></name>
<% if @property_hash[:uuid] %><uuid><%= @property_hash[:uuid] %></uuid><% end %>
<% if @property_hash[:mac] %>
<mac address='<%= @property_hash[:mac] %>'/>
<% end %>
<% if @resource[:forward_mode] %>
<forward<% if @resource[:forward_dev] %> dev='<%= @resource[:forward_dev] %>'<%end%> mode='<%= @resource[:forward_mode] %>'<% if !@resource[:forward_interfaces] %>/<%end%>>
<% if @resource[:forward_interfaces] %>
<% @resource[:forward_interfaces].each do |dev| %>
<interface dev='<%= dev %>'/>
<% end %>
</forward>
<% end %>
<% end %>
<% if @resource[:bridge] %>
<bridge name='<%= @resource[:bridge] %>'<% if @resource[:forward_mode] and @resource[:forward_mode] != 'bridge' %> stp='on' delay='0'<%end%>/>
<% end %>
<%if @resource[:ip] %>
<% @resource[:ip].each do |ip| %>
<ip<%if ip['address']%> address='<%=ip['address']%>'<%end%><% if ip['netmask']%> netmask='<%=ip['netmask']%>'<%end%><% if ip['prefix']%> prefix='<%=ip['prefix']%>'<%end%><% unless ip['dhcp'] %>/<% end %>>
<% if ip['dhcp'] %>
<% dhcp = ip['dhcp'] %>
<dhcp>
<% if dhcp['start'] and dhcp['end']%>
<range start='<%=dhcp['start']%>' end='<%=dhcp['end']%>'/>
<%end%>
<% if dhcp['bootp_file']%>
<bootp file='<%= dhcp['bootp_file'] %>'<% if dhcp['bootp_server']%> server='<%=dhcp['bootp_server']%>'<%end%>/>
<%end%>
</dhcp>
</ip>
<% end%>
<% end%>
<%end%>
<% if @resource[:ipv6] %>
<% @resource[:ipv6].each do |ip| %>
<ip family='ipv6'<% if ip['address']%> address='<%=ip['address']%>'<%end%><% if ip['netmask']%> netmask='<%=ip['netmask']%>'<%end%><% if ip['prefix']%> prefix='<%=ip['prefix']%>'<%end%><% unless ip['dhcp'] %>/<% end %>>
<% if ip['dhcp'] %>
<% dhcp = ip['dhcp'] %>
<dhcp>
<% if dhcp['start'] and dhcp['end']%>
<range start='<%=dhcp['start']%>' end='<%=dhcp['end']%>'/>
<%end%>
</dhcp>
</ip>
<% end%>
<% end%>
<%end%>
</network>
EOF
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh. this is not pretty. actually, from what i gather, it's the same as my old template, but the whole bits around it ensure that it'll be a lot more stable.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bit started as a simple copy of the existing template, then got tweaked as needed.

new_net_xml = ERB.new(net_xml).result(binding)
debug("generated: " + new_net_xml )
begin
net = $conn.define_network_xml(new_net_xml)
rescue Libvirt::Error => e
puts "error", e
end
end

def exists?
begin
net = $conn.lookup_network_by_name(name)
true
rescue Libvirt::RetrieveError => e
false
end
end

def destroy
net = $conn.lookup_network_by_name(name)
net.destroy
net.undefine
end

def autostart
@property_hash[:autostart] == true
end

def autostart=(value)
net = $conn.lookup_network_by_name(name)
net.autostart = value
end

end
59 changes: 59 additions & 0 deletions lib/puppet/type/network.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
Puppet::Type.newtype(:network) do
@doc = "manages domains with libvirt"

ensurable

newparam(:name) do
desc "The name of the domain."
end

newproperty(:autostart) do
desc "Whether to start this network at boot time"
end

newproperty(:bridge) do
desc "Name of the bridge this network will be attached to"
end

newproperty(:forward_mode) do
desc "One of nat, route, bridge, vepa, passthrough, private, hostdev"
#TODO nat must have an ip address
#TODO A network with forward mode='bridge' can specify a bridge name or a forward dev, but not both
end

newproperty(:forward_dev) do
desc "The interface to forward, useful in bridge and route mode"
end

newproperty(:forward_interfaces, :array_matching => :all) do
desc "An array of interfaces to forwad"
end

newproperty(:ip, :array_matching => :all ) do
desc "a hash with
address
netmask (or alterntively prefix)
dhcp This is another hash that consists of
start - start of the range
end - end of the range
host - an array of hosts"
end

newproperty(:ipv6, :array_matching => :all) do
desc "a hash with
address
netmask (or alterntively prefix)
dhcp This is another hash that consists of
start - start of the range
end - end of the range
host - an array of hosts
Note: The following options are not supported on IPv6 networks
bootp_file - A file to serve for servers booting from PXE
bootp_server - Which server that file is served from"
end

newproperty(:mac) do
desc "mac address for the bridge"
end

end
151 changes: 0 additions & 151 deletions manifests/network.pp

This file was deleted.

Loading