
# Class which restarts networking if needed.
#
# This class is automatically included when needed.
#
class network::helper::restart {
    case $operatingsystem {
	centos,fedora: {
	    exec { "restart-network":
		command     => "/sbin/service network restart",
		path	    => "/bin:/usr/bin:/sbin:/usr/sbin",
		refreshonly => true,
	    }
	}
	openbsd: {
	    exec { "restart-network":
		command     => "/sbin/route delete default ; /bin/sh /etc/netstart",
		path        => "/bin:/usr/bin:/sbin:/usr/sbin",
		refreshonly => true,
	    }
	}
        debian,ubuntu: {
            exec { "restart-network":
                cwd         => "/etc/network",
                command     => "cat interfaces.in interfaces.d/*.conf > interfaces && /etc/init.d/networking restart",
                path        => "/bin:/usr/bin:/sbin:/usr/sbin",
                refreshonly => true,
            }
        }
    }
}


# Install Debian/Ubuntu specific support files.
#
class network::helper::debian {

    file { "/etc/network/interfaces.in":
        ensure => present,
        mode   => 0644,
        owner  => root,
        group  => root,
        source => "puppet:///modules/network/interfaces.in",
    }

    file { "/etc/network/interfaces.d":
        ensure  => directory,
        mode    => 0644,
        owner   => root,
        group   => root,
        purge   => true,
        force   => true,
        recurse => true,
        source  => "puppet:///modules/custom/empty",
    }

}


# Set system hostname according to $homename variable.
#
class network::hostname {

    case $operatingsystem {
        "debian","ubuntu": {
            file { "/etc/hostname":
                ensure  => present,
                content => "${homename}\n",
                mode    => 0644,
                owner   => "root",
                group   => "root",
            }
        }
        "centos","fedora": {
            augeas { "set-hostname":
                context => "/files/etc/sysconfig/network",
                changes => "set HOSTNAME ${homename}",
            }
        }
        "openbsd": {
            file { "/etc/myname":
                ensure  => present,
                content => "${homename}\n",
                mode    => 0644,
                owner   => "root",
                group   => "wheel",
            }
        }
        default: {
            fail("network::hostname not supported on ${operatingsystem}")
        }
    }

}


# Configure interface.
#
# === Parameters
#
#   $name:
#       Network device name.
#   $ipaddr:
#	IP address for interface. Use dhcp for DHCP configuration and none
#	if interface just needs to be brought up. Defaults to none.
#   $eaddr:
#       Ethernet address. Overrides udev configuration.
#   $netmask:
#	Netmask for interface. Required only when $ipaddr is used.
#   $ip6addr:
#       IPv6 address for interface. Use auto for autoconfigured address.
#       Defaults to none.
#   $ip6netmask:
#       IPv6 netmask length. Defaults to 64.
#   $bridge:
#       Array of interfaces to add to bridge.
#   $options:
#	Custom options for interface (used only on OpenBSD).
#   $postcmd:
#       Custom commands to be executed after interface is up (used only on
#       OpenBSD).
#
# === Sample usage
#
# network::interface { "eth0":
#     ipaddr  => "10.10.120.6",
#     netmask => "255.255.0.0",
# }
#
define network::interface($ipaddr = "none", $eaddr = "none", $netmask = "none",
                          $ip6addr = "none", $ip6netmask = "64",
                          $bridge = [], $options = [], $postcmd = []) {

    include network::helper::restart

    # try to determine boot protocol from ip address
    case $ipaddr {
	dhcp: { $proto = "dhcp" }
	none: { $proto = "none" }
	default: {
	    $proto = "static"
	    case $netmask {
		none: { fail("Netmask must be defined with ip address") }
	    }
	}
    }
    case $eaddr {
        none: {
            $myvar = "macaddress_${name}"
            $eaddr_real = inline_template("<%= scope.lookupvar(myvar) %>")
        }
        default: {
            $eaddr_real = $eaddr
        }
    }

    case $operatingsystem {
	openbsd: {
	    file { "/etc/hostname.${name}":
		ensure  => present,
		content => template("network/hostname.if.erb"),
		mode    => 0600,
		owner   => root,
		group   => wheel,
		notify  => Exec["restart-network"],
	    }
	}
	centos,fedora: {
            if $bridge {
                network::interface { $bridge:
                    options => [ "BRIDGE=${name}", "LINKDELAY=10" ],
                    before  => Exec["restart-interface-${name}"],
                }
            }
	    file { "/etc/sysconfig/network-scripts/ifcfg-${name}":
		ensure  => present,
		content => template("network/ifcfg-if.erb"),
		mode    => 0644,
		owner   => root,
		group   => root,
		notify  => Exec["restart-interface-${name}"],
	    }
	    exec { "restart-interface-${name}":
		command     => "ifdown ${name} ; ifup ${name}",
		path        => "/bin:/usr/bin:/sbin:/usr/sbin",
		user        => root,
		refreshonly => true,
		require     => File["/etc/sysconfig/network-scripts/ifcfg-${name}"],
	    }
	}
        debian,ubuntu: {
            include network::helper::debian
            file { "/etc/network/interfaces.d/${name}-addr.conf":
                ensure  => present,
                content => template("network/interfaces-if.erb"),
                mode    => 0644,
                owner   => root,
                group   => root,
                notify  => Exec["restart-network"],
                require => File["/etc/network/interfaces.d", "/etc/network/interfaces.in"],
            }
            if $eaddr_real {
                file { "/etc/udev/rules.d/99-persistent-net-${name}.rules":
                    ensure  => present,
                    mode    => 0644,
                    owner   => root,
                    group   => root,
                    content => "SUBSYSTEM==\"net\", ACTION==\"add\", ATTR{address}==\"${eaddr_real}\", KERNEL==\"eth*\", NAME=\"${name}\"\n",
                }
            }
        }
	default: {
	    fail("Network module not supported in ${operatingsystem}")
	}
    }

}


# Configure static or default route.
#
# === Parameters
#
#   $name:
#       Destination network or default for default route.
#   $gateway:
#       Gateway address.
#   $ipv6gateway:
#       IPv6 gateway address.
#   $device:
#       Interface to use for this route.
#
define network::route($gateway, $device, $ipv6gateway = "") {

    case $name {
	"default": {
	    case $operatingsystem {
		centos,fedora: {
		    include network::helper::restart
		    augeas { "set-default-route":
			context => "/files/etc/sysconfig/network",
			changes => [ "set GATEWAY ${gateway}",
				     "set GATEWAYDEV ${device}", ],
			notify  => Exec["restart-network"],
		    }
                    if "${ipv6gateway}" != "" {
                        augeas { "set-default-ipv6-route":
                            context => "/files/etc/sysconfig/network",
                            changes => "set IPV6_DEFAULTGW ${ipv6gateway}",
                            notify  => Exec["restart-network"],
                        }
                    }
		}
		openbsd: {
		    include network::helper::restart
		    file { "/etc/mygate":
			ensure  => present,
			content => template("network/mygate.erb"),
			mode    => 644,
			owner   => root,
			group   => wheel,
			notify  => Exec["restart-network"],
		    }
		}
                debian,ubuntu: {
                    include network::helper::restart
                    include network::helper::debian
                    file { "/etc/network/interfaces.d/${device}-gate.conf":
                        ensure  => present,
                        content => template("network/interfaces-gateway.erb"),
                        mode    => 0644,
                        owner   => root,
                        group   => root,
                        notify  => Exec["restart-network"],
                        require => File["/etc/network/interfaces.d/${device}-addr.conf"],
                    }
                }
		default: {
		    fail("Network module not supported in ${operatingsystem}")
		}
	    }
	}
	default: { fail("Only default routes are currently supported") }
    }

}


# Configure CARP interface
#
# === Parameters
#
#   $name:
#       CARP VHID
#   $password:
#       Password for authenticating CARP advertisements.
#   $ipaddr:
#       -
#   $netmask:
#       -
#   $options:
#       Extra options for interface.
#
# === Sample usage
#
# network::carp { "1":
#     ipaddr   => "192.168.1.1",
#     netmask  => "255.255.255.0",
#     password => "secret",
# }
#
define network::carp($password, $ipaddr, $netmask, $options = []) {
    case $operatingsystem {
	openbsd: {
	    network::interface { "carp${name}":
		ipaddr  => "${ipaddr}",
		netmask => "${netmask}",
		options => [ "vhid ${name}", "pass ${password}", $options ],
                postcmd => [ "/usr/sbin/ndp -i carp${name} -- -accept_rtadv" ],
	    }
	}
	centos,fedora: {
	    include network::ucarp
	    file { "/etc/ucarp/vip-${name}.conf":
		ensure  => present,
		content => template("network/vip.conf.erb"),
		mode    => 0600,
		owner   => root,
		group   => root,
		require => Package["ucarp"],
		notify  => Service["ucarp"],
	    }
	}
	default: {
	    fail("Network module not supported in ${operatingsystem}")
	}
    }
}


# Install uCARP[http://www.ucarp.org] daemon on host.
#
# This class is automatically included by network::carp when needed.
#
class network::ucarp {
    package { "ucarp":
	ensure => installed,
    }
    service { "ucarp":
	ensure    => running,
	enable    => true,
	hasstatus => true,
	require   => Package["ucarp"],
    }
}


# Configure PPPoE interface.
#
# === Parameters
#
#   $name:
#       PPPoE device name.
#   $device:
#       Physical interface name.
#   $username:
#       Username to use for connection.
#   $password:
#       Password to use for connection.
#   $authtype:
#       Authentication method to use. Defaults to PAP.
#
define network::pppoe($username, $password, $device, $authtype = "pap") {

    include network::helper::restart

    case $operatingsystem {
	openbsd: {
	    file { "/etc/hostname.${name}":
		ensure  => present,
		content => template("network/hostname.pppoe.erb"),
		mode    => 0600,
		owner   => root,
		group   => wheel,
		notify  => Exec["restart-network"],
	    }
	}
	default: {
	    fail("Network module not supported in ${operatingsystem}")
	}
    }

}


# Configure trunk (bonded) interface.
#
# === Parameters
#
#   $name:
#       Trunk device name.
#   $devices:
#       Physical network devices to use.
#   $ipaddr:
#       -
#   $netmask:
#       -
#
# === Sample usage
#
# network::trunk { "bond0":
#     devices => [ "eth0", "eth1", ]
#     ipaddr  => "10.10.120.6",
#     netmask => "255.255.0.0",
# }
#
define network::trunk($devices, $mode = 0, $ipaddr = "none", $netmask = "none") {
    case $operatingsystem {
	centos,fedora: {
	    file { "/etc/modprobe.d/${name}.conf":
		ensure  => present,
		content => "alias ${name} bonding\noptions ${name} miimon=100 mode=${mode}\n",
		mode    => 0644,
		owner   => root,
		group   => root,
	    }
	    network::interface { $devices:
		options => [ "MASTER=${name}", "SLAVE=yes", ],
		require => File["/etc/modprobe.d/${name}.conf"],
		before  => Network::Interface["${name}"],
	    }
	    network::interface { $name:
		ipaddr  => "${ipaddr}",
		netmask => "${netmask}",
	    }
	}
	default: {
	    fail("Network module not supported in ${operatingsystem}")
	}
    }
}


# Enable VLAN support for host.
#
# This class is automatically included when needed.
#
class network::helper::vlan {
    case $operatingsystem {
	centos,fedora: {
	    augeas { "enable-vlan-support":
		context => "/files/etc/sysconfig/network",
		changes => "set VLAN yes",
	    }
	}
    }
}


# Configure VLAN interface.
#
# === Parameters
#
#   $name:
#       VLAN tag.
#   $device:
#       Physical network device to use.
#   $ipaddr:
#       -
#   $netmask:
#       -
#
# === Sample usage
#
# network::vlan { "1":
#     device  => "eth0",
#     ipaddr  => "10.10.120.6",
#     netmask => "255.255.0.0",
# }
#
define network::vlan($device, $ipaddr = "none", $netmask = "none") {
    case $operatingsystem {
	openbsd: {
	    network::interface { "vlan${name}":
		options => [ "vlandev ${device}" ],
		ipaddr  => $ipaddr,
		netmask => $netmask,
	    }
	}
	centos,fedora: {
	    include network::helper::vlan
	    network::interface { "${device}.${name}":
		ipaddr  => $ipaddr,
		netmask => $netmask,
		require => Augeas["enable-vlan-support"],
	    }
	}
	default: {
	    fail("Network module not supported in ${operatingsystem}")
	}
    }
}


# Disable NetworkManager.
#
class network::manager::disable {

    case $operatingsystem {
        ubuntu: {
            file { "/etc/init/network-manager.conf":
                ensure => present,
                mode   => 0644,
                owner  => root,
                group  => root,
                source => "puppet:///modules/network/network-manager.disabled.conf",
            }
            xdg::autostart { "nm-applet":
                enable => false,
            }
        }
    }

    service { "network-manager":
        name      => $operatingsystem ? {
            ubuntu  => "network-manager",
            default => "NetworkManager",
        },
        ensure    => stopped,
        enable    => false,
        hasstatus => true,
    }

}
