diff --git a/lib/puppet/provider/mikrotik.rb b/lib/puppet/provider/mikrotik.rb new file mode 100644 index 0000000..f948eb0 --- /dev/null +++ b/lib/puppet/provider/mikrotik.rb @@ -0,0 +1,9 @@ +require 'puppet/util/network_device/mikrotik/device' +require 'puppet/provider/network_device' + +class Puppet::Provider::Mikrotik < Puppet::Provider::NetworkDevice + def self.device(url) + Puppet::Util::NetworkDevice::Mikrotik::Device.new(url) + @parse_cache = {} + end +end diff --git a/lib/puppet/provider/mikrotik_interface_6to4/mikrotik.rb b/lib/puppet/provider/mikrotik_interface_6to4/mikrotik.rb new file mode 100644 index 0000000..867df6b --- /dev/null +++ b/lib/puppet/provider/mikrotik_interface_6to4/mikrotik.rb @@ -0,0 +1,27 @@ +require 'puppet/provider/mikrotik' + +Puppet::Type.type(:mikrotik_interface_6to4).provide :mikrotik, :parent => Puppet::Provider::Mikrotik do + + desc "Mikrotik provider for mikrotik_interface_6to4." + + mk_resource_methods + + def self.lookup(device, name) + @parse_cache = {} unless @parse_cache + device.command do |dev| + @parse_cache[:interface_6to4s] = dev.parse_interface_6to4s() || {} + end unless @parse_cache[:interface_6to4s] + @parse_cache[:interface_6to4s][name] + end + + def initialize(device, *args) + super + end + + def flush + device.command do |dev| + dev.update_interface_6to4(resource[:name], former_properties, properties) + end + super + end +end diff --git a/lib/puppet/provider/mikrotik_interface_ovpnclient/mikrotik.rb b/lib/puppet/provider/mikrotik_interface_ovpnclient/mikrotik.rb new file mode 100644 index 0000000..8d8f9b7 --- /dev/null +++ b/lib/puppet/provider/mikrotik_interface_ovpnclient/mikrotik.rb @@ -0,0 +1,27 @@ +require 'puppet/provider/mikrotik' + +Puppet::Type.type(:mikrotik_interface_ovpnclient).provide :mikrotik, :parent => Puppet::Provider::Mikrotik do + + desc "Mikrotik provider for mikrotik_interface_ovpnclient." + + mk_resource_methods + + def self.lookup(device, name) + @parse_cache = {} unless @parse_cache + device.command do |dev| + @parse_cache[:interface_ovpnclients] = dev.parse_interface_ovpnclients() || {} + end unless @parse_cache[:interface_ovpnclients] + @parse_cache[:interface_ovpnclients][name] + end + + def initialize(device, *args) + super + end + + def flush + device.command do |dev| + dev.update_interface_ovpnclient(resource[:name], former_properties, properties) + end + super + end +end diff --git a/lib/puppet/provider/mikrotik_interface_vlan/mikrotik.rb b/lib/puppet/provider/mikrotik_interface_vlan/mikrotik.rb new file mode 100644 index 0000000..c1b4113 --- /dev/null +++ b/lib/puppet/provider/mikrotik_interface_vlan/mikrotik.rb @@ -0,0 +1,27 @@ +require 'puppet/provider/mikrotik' + +Puppet::Type.type(:mikrotik_interface_vlan).provide :mikrotik, :parent => Puppet::Provider::Mikrotik do + + desc "Mikrotik provider for mikrotik_interface_vlan." + + mk_resource_methods + + def self.lookup(device, name) + @parse_cache = {} unless @parse_cache + device.command do |dev| + @parse_cache[:interface_vlans] = dev.parse_interface_vlans() || {} + end unless @parse_cache[:interface_vlans] + @parse_cache[:interface_vlans][name] + end + + def initialize(device, *args) + super + end + + def flush + device.command do |dev| + dev.update_interface_vlan(resource[:name], former_properties, properties) + end + super + end +end diff --git a/lib/puppet/provider/mikrotik_ip_address/mikrotik.rb b/lib/puppet/provider/mikrotik_ip_address/mikrotik.rb new file mode 100644 index 0000000..cccacaf --- /dev/null +++ b/lib/puppet/provider/mikrotik_ip_address/mikrotik.rb @@ -0,0 +1,27 @@ +require 'puppet/provider/mikrotik' + +Puppet::Type.type(:mikrotik_ip_address).provide :mikrotik, :parent => Puppet::Provider::Mikrotik do + + desc "Mikrotik provider for mikrotik_ip_address." + + mk_resource_methods + + def self.lookup(device, address) + @parse_cache = {} unless @parse_cache + device.command do |dev| + @parse_cache[:ip_addresses] = dev.parse_addresses('ip') || {} + end unless @parse_cache[:ip_addresses] + @parse_cache[:ip_addresses][address] + end + + def initialize(device, *args) + super + end + + def flush + device.command do |dev| + dev.update_address('ip', resource[:address], former_properties, properties) + end + super + end +end diff --git a/lib/puppet/provider/mikrotik_ip_dhcpserver_lease/mikrotik.rb b/lib/puppet/provider/mikrotik_ip_dhcpserver_lease/mikrotik.rb new file mode 100644 index 0000000..f38fb7e --- /dev/null +++ b/lib/puppet/provider/mikrotik_ip_dhcpserver_lease/mikrotik.rb @@ -0,0 +1,27 @@ +require 'puppet/provider/mikrotik' + +Puppet::Type.type(:mikrotik_ip_dhcpserver_lease).provide :mikrotik, :parent => Puppet::Provider::Mikrotik do + + desc "Mikrotik provider for mikrotik_ip_dhcpserver_lease." + + mk_resource_methods + + def self.lookup(device, name) + @parse_cache = {} unless @parse_cache + device.command do |dev| + @parse_cache[:ip_dhcpserver_leases] = dev.parse_ip_dhcpserver_leases() || {} + end unless @parse_cache[:ip_dhcpserver_leases] + @parse_cache[:ip_dhcpserver_leases][name] + end + + def initialize(device, *args) + super + end + + def flush + device.command do |dev| + dev.update_ip_dhcpserver_lease(resource[:name], former_properties, properties) + end + super + end +end diff --git a/lib/puppet/provider/mikrotik_ip_firewall_addresslist/mikrotik.rb b/lib/puppet/provider/mikrotik_ip_firewall_addresslist/mikrotik.rb new file mode 100644 index 0000000..ae6842e --- /dev/null +++ b/lib/puppet/provider/mikrotik_ip_firewall_addresslist/mikrotik.rb @@ -0,0 +1,27 @@ +require 'puppet/provider/mikrotik' + +Puppet::Type.type(:mikrotik_ip_firewall_addresslist).provide :mikrotik, :parent => Puppet::Provider::Mikrotik do + + desc "Mikrotik provider for mikrotik_ip_firewall_addresslist." + + mk_resource_methods + + def self.lookup(device, listname) + @parse_cache = {} unless @parse_cache + device.command do |dev| + @parse_cache[:ip_firewall_addresslists] = dev.parse_firewall_addresslists('ip') || {} + end unless @parse_cache[:ip_firewall_addresslists] + @parse_cache[:ip_firewall_addresslists][listname] + end + + def initialize(device, *args) + super + end + + def flush + device.command do |dev| + dev.update_firewall_addresslist('ip', resource[:listname], former_properties, properties) + end + super + end +end diff --git a/lib/puppet/provider/mikrotik_ip_route/mikrotik.rb b/lib/puppet/provider/mikrotik_ip_route/mikrotik.rb new file mode 100644 index 0000000..506488e --- /dev/null +++ b/lib/puppet/provider/mikrotik_ip_route/mikrotik.rb @@ -0,0 +1,27 @@ +require 'puppet/provider/mikrotik' + +Puppet::Type.type(:mikrotik_ip_route).provide :mikrotik, :parent => Puppet::Provider::Mikrotik do + + desc "Mikrotik provider for mikrotik_ip_route." + + mk_resource_methods + + def self.lookup(device, route) + @parse_cache = {} unless @parse_cache + device.command do |dev| + @parse_cache[:ip_routes] = dev.parse_routes('ip') || {} + end unless @parse_cache[:ip_routes] + @parse_cache[:ip_routes][route] + end + + def initialize(device, *args) + super + end + + def flush + device.command do |dev| + dev.update_route('ip', resource[:route], former_properties, properties) + end + super + end +end diff --git a/lib/puppet/provider/mikrotik_ipv6_address/mikrotik.rb b/lib/puppet/provider/mikrotik_ipv6_address/mikrotik.rb new file mode 100644 index 0000000..158e8ba --- /dev/null +++ b/lib/puppet/provider/mikrotik_ipv6_address/mikrotik.rb @@ -0,0 +1,27 @@ +require 'puppet/provider/mikrotik' + +Puppet::Type.type(:mikrotik_ipv6_address).provide :mikrotik, :parent => Puppet::Provider::Mikrotik do + + desc "Mikrotik provider for mikrotik_ipv6_address." + + mk_resource_methods + + def self.lookup(device, address) + @parse_cache = {} unless @parse_cache + device.command do |dev| + @parse_cache[:ipv6_addresses] = dev.parse_addresses('ipv6') || {} + end unless @parse_cache[:ipv6_addresses] + @parse_cache[:ipv6_addresses][address] + end + + def initialize(device, *args) + super + end + + def flush + device.command do |dev| + dev.update_address('ipv6', resource[:address], former_properties, properties) + end + super + end +end diff --git a/lib/puppet/provider/mikrotik_ipv6_firewall_addresslist/mikrotik.rb b/lib/puppet/provider/mikrotik_ipv6_firewall_addresslist/mikrotik.rb new file mode 100644 index 0000000..afe7acc --- /dev/null +++ b/lib/puppet/provider/mikrotik_ipv6_firewall_addresslist/mikrotik.rb @@ -0,0 +1,27 @@ +require 'puppet/provider/mikrotik' + +Puppet::Type.type(:mikrotik_ipv6_firewall_addresslist).provide :mikrotik, :parent => Puppet::Provider::Mikrotik do + + desc "Mikrotik provider for mikrotik_ipv6_firewall_addresslist." + + mk_resource_methods + + def self.lookup(device, listname) + @parse_cache = {} unless @parse_cache + device.command do |dev| + @parse_cache[:ipv6_firewall_addresslists] = dev.parse_firewall_addresslists('ipv6') || {} + end unless @parse_cache[:ipv6_firewall_addresslists] + @parse_cache[:ipv6_firewall_addresslists][listname] + end + + def initialize(device, *args) + super + end + + def flush + device.command do |dev| + dev.update_firewall_addresslist('ipv6', resource[:listname], former_properties, properties) + end + super + end +end diff --git a/lib/puppet/provider/mikrotik_ipv6_route/mikrotik.rb b/lib/puppet/provider/mikrotik_ipv6_route/mikrotik.rb new file mode 100644 index 0000000..9322611 --- /dev/null +++ b/lib/puppet/provider/mikrotik_ipv6_route/mikrotik.rb @@ -0,0 +1,27 @@ +require 'puppet/provider/mikrotik' + +Puppet::Type.type(:mikrotik_ipv6_route).provide :mikrotik, :parent => Puppet::Provider::Mikrotik do + + desc "Mikrotik provider for mikrotik_ipv6_route." + + mk_resource_methods + + def self.lookup(device, route) + @parse_cache = {} unless @parse_cache + device.command do |dev| + @parse_cache[:ipv6_routes] = dev.parse_routes('ipv6') || {} + end unless @parse_cache[:ipv6_routes] + @parse_cache[:ipv6_routes][route] + end + + def initialize(device, *args) + super + end + + def flush + device.command do |dev| + dev.update_route('ipv6', resource[:route], former_properties, properties) + end + super + end +end diff --git a/lib/puppet/type/mikrotik_interface_6to4.rb b/lib/puppet/type/mikrotik_interface_6to4.rb new file mode 100644 index 0000000..5e11820 --- /dev/null +++ b/lib/puppet/type/mikrotik_interface_6to4.rb @@ -0,0 +1,57 @@ +Puppet::Type.newtype(:mikrotik_interface_6to4) do + @doc = "Manage Mikrotik 6to4 interface creation, modification and deletion." + + apply_to_device + + ensurable + + newparam(:name) do + desc "The the name of the 6to4 interface." + isnamevar + end + + newproperty(:comment) do + desc "Interface comment" + validate do |value| + unless value =~ /^[\w\s\.,()-]+$/ + raise ArgumentError, "'%s' is not a valid comment." % value + end + end + end + + newproperty(:disabled) do + desc "Defines whether interface is ignored or used" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:localaddress) do + desc "Local address" + validate do |value| + unless value =~ /^(\d+\.){3}\d+$/ + raise ArgumentError, "'%s' is not a valid local address." % value + end + end + end + + newproperty(:mtu) do + desc "MTU" + validate do |value| + unless value =~ /^\d+$/ + raise ArgumentError, "'%s' is not a valid MTU." % value + end + unless value.to_i < 65537 + raise ArgumentError, "'%s' is not a valid MTU (0..65536)." % value + end + end + end + + newproperty(:remoteaddress) do + desc "Remote address" + validate do |value| + unless value =~ /^(\d+\.){3}\d+$/ + raise ArgumentError, "'%s' is not a valid remote address." % value + end + end + end +end diff --git a/lib/puppet/type/mikrotik_interface_ovpnclient.rb b/lib/puppet/type/mikrotik_interface_ovpnclient.rb new file mode 100644 index 0000000..27adfc0 --- /dev/null +++ b/lib/puppet/type/mikrotik_interface_ovpnclient.rb @@ -0,0 +1,111 @@ +Puppet::Type.newtype(:mikrotik_interface_ovpnclient) do + @doc = "Manage Mikrotik OpenVPN Client interface creation, modification and deletion." + + apply_to_device + + ensurable + + newparam(:name) do + desc "The the name of the OpenVPN Client interface." + isnamevar + end + + newproperty(:comment) do + desc "Interface comment" + validate do |value| + unless value =~ /^[\w\s\.,()-]+$/ + raise ArgumentError, "'%s' is not a valid comment." % value + end + end + end + + newproperty(:disabled) do + desc "Defines whether interface is ignored or used" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:adddefaultroute) do + desc "Whether to add OVPN remote address as a default route" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:auth) do + desc "Allowed authentication methods" + newvalues(:md5, :sha1, :none) + defaultto(:sha1) + end + + newproperty(:certificate) do + desc "Name of the client certificate imported into certificate list" + newvalues(:none, /.+/) + defaultto(:none) + end + + newproperty(:cipher) do + desc "Allowed ciphers" + newvalues(:aes128, :aes192, :aes256, :blowfish128, :none) + defaultto(:blowfish128) + end + + newproperty(:connectto) do + desc "Remote address of the OVPN server" + validate do |value| + unless value =~ /^(\d+\.){3}\d+$/ + raise ArgumentError, "'%s' is not a valid connect-to value" % value + end + end + end + + newproperty(:macaddress) do + desc "Mac address of OVPN interface." + validate do |value| + unless value =~ /^([a-fA-F0-9]{2}[:\.-]){5}[a-fA-F0-9]{2}$/ + raise ArgumentError, "'%s' is not a valid MAC address" % value + end + end + end + + newproperty(:maxmtu) do + desc "Maximum MTU." + validate do |value| + unless value =~ /^\d+$/ + raise ArgumentError, "'%s' is not a valid MTU." % value + end + unless value.to_i < 65537 + raise ArgumentError, "'%s' is not a valid MTU (0..65536)." % value + end + end + end + + newproperty(:mode) do + desc "Layer3 or layer2 tunnel mode" + newvalues(:ip, :ethernet) + defaultto(:ip) + end + + newproperty(:password) do + desc "Password used for authentication" + end + + newproperty(:port) do + desc "Port to connect to." + validate do |value| + unless value =~ /^\d+$/ + raise ArgumentError, "'%s' is not a valid port." % value + end + unless value.to_i < 65536 + raise ArgumentError, "'%s' is not a valid port (0..65535)." % value + end + end + end + + newproperty(:profile) do + desc "Used PPP profile" + end + + newproperty(:user) do + desc "User name used for authentication" + end +end diff --git a/lib/puppet/type/mikrotik_interface_vlan.rb b/lib/puppet/type/mikrotik_interface_vlan.rb new file mode 100644 index 0000000..966838e --- /dev/null +++ b/lib/puppet/type/mikrotik_interface_vlan.rb @@ -0,0 +1,80 @@ +Puppet::Type.newtype(:mikrotik_interface_vlan) do + @doc = "Manage Mikrotik VLAN interface creation, modification and deletion." + + apply_to_device + + ensurable + + newparam(:name) do + desc "The the name of the VLAN interface." + isnamevar + end + + newproperty(:arp) do + desc "ARP behaviour" + newvalues(:enabled, :disabled, 'proxy-arp', 'reply-only') + defaultto(:enabled) + end + + newproperty(:comment) do + desc "Interface comment" + validate do |value| + unless value =~ /^[\w\s\.,()-]+$/ + raise ArgumentError, "'%s' is not a valid comment." % value + end + end + end + + newproperty(:disabled) do + desc "Defines whether interface is ignored or used" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:interface) do + desc "Physical interface to the network where are VLANs" + end + + newproperty(:l2mtu) do + desc "Layer 2 MTU" + newvalues(/\d+/) + validate do |value| + unless value =~ /^\d+$/ + raise ArgumentError, "'%s' is not a valid Layer 2 MTU." % value + end + unless value.to_i < 65537 + raise ArgumentError, "'%s' is not a valid Layer 2 MTU (0..65536)." % value + end + end + end + + newproperty(:mtu) do + desc "MTU" + validate do |value| + unless value =~ /^\d+$/ + raise ArgumentError, "'%s' is not a valid MTU." % value + end + unless (value.to_i > 67) or (value.to_i < 65536) + raise ArgumentError, "'%s' is not a valid MTU (68..65535)." % value + end + end + end + + newproperty(:useservicetag) do + desc "use-service-tag" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:vlanid) do + desc "VLAN ID" + validate do |value| + unless value =~ /^\d+$/ + raise ArgumentError, "'%s' is not a valid VLAN ID." % value + end + unless (value.to_i > 0) or (value.to_i < 4096) + raise ArgumentError, "'%s' is not a valid VLAN ID (1..4095)." % value + end + end + end +end diff --git a/lib/puppet/type/mikrotik_ip_address.rb b/lib/puppet/type/mikrotik_ip_address.rb new file mode 100644 index 0000000..9efc80a --- /dev/null +++ b/lib/puppet/type/mikrotik_ip_address.rb @@ -0,0 +1,52 @@ +Puppet::Type.newtype(:mikrotik_ip_address) do + @doc = "Manage Mikrotik IP address creation, modification and deletion." + + apply_to_device + + ensurable + + newparam(:address) do + desc "The the address." + isnamevar + validate do |value| + unless value =~ /^(\d+\.){3}\d+(\/(\d|[12]\d|3[0-2]|(\d+\.){3}\d+))?$/ + raise ArgumentError, "'%s' is not a valid address." % value + end + end + end + + newproperty(:broadcast) do + desc "broadcast" + newvalues(/^(\d+\.){3}\d+$/) + end + + newproperty(:comment) do + desc "Address comment" + validate do |value| + unless value =~ /^[\w\s\.,()-]+$/ + raise ArgumentError, "'%s' is not a valid comment." % value + end + end + end + + newproperty(:disabled) do + desc "Defines whether address is ignored or used" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:interface) do + desc "Interface" + end + + newproperty(:netmask) do + desc "netmask" + newvalues(/^(\d+\.){3}\d+$/) + end + + newproperty(:network) do + desc "network" + newvalues(/^(\d+\.){3}\d+$/) + end + +end diff --git a/lib/puppet/type/mikrotik_ip_dhcpserver_lease.rb b/lib/puppet/type/mikrotik_ip_dhcpserver_lease.rb new file mode 100644 index 0000000..479fd83 --- /dev/null +++ b/lib/puppet/type/mikrotik_ip_dhcpserver_lease.rb @@ -0,0 +1,71 @@ +Puppet::Type.newtype(:mikrotik_ip_dhcpserver_lease) do + @doc = "Manage Mikrotik DHCP lease creation, modification and deletion." + + apply_to_device + + ensurable + + newparam(:address) do + desc "The the address/prefix/pool of DHCP lease." + isnamevar + end + + newproperty(:comment) do + desc "Interface comment" + validate do |value| + unless value =~ /^[\w\s\.,()-]+$/ + raise ArgumentError, "'%s' is not a valid comment." % value + end + end + end + + newproperty(:disabled) do + desc "Defines whether address is ignored or used" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:addresslist) do + desc "address-list" + end + + newproperty(:alwaysbroadcast) do + desc "Send all replies as broadcast" + newvalues(:no, :yes) + end + + newproperty(:blockaccess) do + desc "Block access for this client" + newvalues(:no, :yes) + end + + newproperty(:clientid) do + desc "Client identifier" + end + + newproperty(:leasetime) do + desc "Lease time" + end + + newproperty(:macaddress) do + desc "MAC address" + validate do |value| + unless value =~ /^([0-9a-fA-F]{2}[:\.-]){5}[0-9a-fA-F]{2}+$/ + raise ArgumentError, "'%s' is not a valid MAC address." % value + end + end + end + + newproperty(:ratelimit) do + desc "Bit rate limit for the client" + end + + newproperty(:server) do + desc "Server name which serves this client" + end + + newproperty(:usesrcmac) do + desc "Use source mac address instead" + newvalues(:no, :yes) + end +end diff --git a/lib/puppet/type/mikrotik_ip_firewall_addresslist.rb b/lib/puppet/type/mikrotik_ip_firewall_addresslist.rb new file mode 100644 index 0000000..b01c1e1 --- /dev/null +++ b/lib/puppet/type/mikrotik_ip_firewall_addresslist.rb @@ -0,0 +1,48 @@ +Puppet::Type.newtype(:mikrotik_ip_firewall_addresslist) do + @doc = "Manage Mikrotik firewall address-list creation, modification and deletion." + + apply_to_device + + ensurable + + newparam(:listname) do + desc "The address-list name." + isnamevar + validate do |value| + unless value =~ /^[\w\.-]+$/ + raise ArgumentError, "%s is not a valid address-list name." % value + end + end + end + + newproperty(:comment) do + desc "Address-list comment" + validate do |value| + unless value =~ /^[\w\s\.,()-]+$/ + raise ArgumentError, "%s is not a valid comment." % value + end + end + end + + newproperty(:disabled) do + desc "Defines whether address-list is ignored or used" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:address, :array_matching => :all) do + desc "IP address (A.B.C.D[-A.B.C.D |/0..32 |/A.B.C.D ])" + + def insync?(is) + is.flatten.sort == should.flatten.sort + end + + validate do |values| + [values].flatten.each do |value| + unless value =~ /^(\d+\.){3}\d+(-(\d+\.){3}\d+|\/(\d|[12]\d|3[012]|(\d+\.){3}\d+))?$/ + raise ArgumentError, "#{value} is not a valid address." + end + end + end + end +end diff --git a/lib/puppet/type/mikrotik_ip_route.rb b/lib/puppet/type/mikrotik_ip_route.rb new file mode 100644 index 0000000..21edc9c --- /dev/null +++ b/lib/puppet/type/mikrotik_ip_route.rb @@ -0,0 +1,133 @@ +Puppet::Type.newtype(:mikrotik_ip_route) do + @doc = "Manage Mikrotik route creation, modification and deletion." + + apply_to_device + + ensurable + + newparam(:route) do + desc "The the route prefix." + isnamevar + validate do |value| + unless value =~ /^(?:\d+\.){3}\d+(\/(\d|[12]\d|3[012]))?$/ + raise ArgumentError, "'%s' is not a valid route." % value + end + end + end + + newproperty(:prefsrc) do + desc "The the preferred source address for the route." + validate do |value| + unless value =~ /^(\d+\.){3}\d+$/ + raise ArgumentError, "'%s' is not a valid preferred source address." % value + end + end + end + + newproperty(:gateway, :array_matching => :all) do + desc "Nexthop gateway(s)" + validate do |values| + [values].flatten.each do |value| + unless value =~ /^((\d+\.){3}\d+(%[^ ]+)?|[^ ]+)$/ + raise ArgumentError, "'%s' is not a valid gateway." % value + end + end + end + end + + newproperty(:comment) do + desc "Route comment" + validate do |value| + unless value =~ /^[\w\s\.,()-]+$/ + raise ArgumentError, "'%s' is not a valid comment." % value + end + end + end + + newproperty(:disabled) do + desc "Defines whether route is ignored or used" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:type) do + desc "Route type" + newvalues(:unicast, :unreachable, :prohibit, :blackhole) + defaultto(:unicast) + end + + newproperty(:distance) do + desc "Route distance" + newvalues(/(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])/) + end + + newproperty(:checkgateway) do + desc "Route check-gateway" + newvalues(:ping, :arp) + end + + newproperty(:targetscope) do + desc "Route target-scope" + newvalues(/(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])/) + end + + newproperty(:scope) do + desc "Route scope" + newvalues(/(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])/) + end + + newproperty(:routetag) do + desc "Route tag" + newvalues(/\d+/) + end + + newproperty(:routingmark) do + desc "Routing mark" + newvalues(/\S+/) + end + + newproperty(:vrfinterface) do + desc "VRF interface" + end + + newproperty(:bgpprepend) do + desc "Route bgp-prepend" + newvalues(/\d|1[0-6]/) + end + + newproperty(:bgporigin) do + desc "Route bgp-origin" + newvalues(:igp,:egp,:incomplete) + end + + newproperty(:bgpmed) do + desc "Route bgp-med" + newvalues(/\d+/) + end + + newproperty(:bgplocalpref) do + desc "Route bgp-local-pref" + newvalues(/\d+/) + end + + newproperty(:bgpcommunities, :array_matching => :all) do + desc "Route bgp-communities" + validate do |values| + [values].flatten.each do |value| + unless value =~ /^(\d+:\d+|no-advertise|no-export|local-as)$/ + raise ArgumentError, "%s is not a valid bgp-community" % value + end + end + end + end + + newproperty(:bgpatomicaggregate) do + desc "Route bgp-atomic-aggregate" + newvalues(:yes, :no) + end + + newproperty(:bgpaspath) do + desc "Route bgp-as-path" + end + +end diff --git a/lib/puppet/type/mikrotik_ipv6_address.rb b/lib/puppet/type/mikrotik_ipv6_address.rb new file mode 100644 index 0000000..857fd88 --- /dev/null +++ b/lib/puppet/type/mikrotik_ipv6_address.rb @@ -0,0 +1,53 @@ +Puppet::Type.newtype(:mikrotik_ipv6_address) do + @doc = "Manage Mikrotik IPv6 address creation, modification and deletion." + + apply_to_device + + ensurable + + newparam(:address) do + desc "The the address." + isnamevar + validate do |value| + unless value =~ /^[a-f0-9:]+(\/(\d|[1-9]\d|1[01]\d|12[0-8]))?$/ + raise ArgumentError, "'%s' is not a valid address." % value + end + end + end + + newproperty(:advertise) do + desc "Defines whether prefix is advertised via SLAAC" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:comment) do + desc "Address comment" + validate do |value| + unless value =~ /^[\w\s\.,()-]+$/ + raise ArgumentError, "'%s' is not a valid comment." % value + end + end + end + + newproperty(:disabled) do + desc "Defines whether addresslist is ignored or used" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:eui64) do + desc "Defines whether to calculate an EUI-64 address" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:frompool) do + desc "From-Pool" + end + + newproperty(:interface) do + desc "Interface" + end + +end diff --git a/lib/puppet/type/mikrotik_ipv6_firewall_addresslist.rb b/lib/puppet/type/mikrotik_ipv6_firewall_addresslist.rb new file mode 100644 index 0000000..60b3e62 --- /dev/null +++ b/lib/puppet/type/mikrotik_ipv6_firewall_addresslist.rb @@ -0,0 +1,48 @@ +Puppet::Type.newtype(:mikrotik_ipv6_firewall_addresslist) do + @doc = "Manage Mikrotik ipv6 firewall address-list creation, modification and deletion." + + apply_to_device + + ensurable + + newparam(:listname) do + desc "The address-list name." + isnamevar + validate do |value| + unless value =~ /^[\w\.-]+$/ + raise ArgumentError, "%s is not a valid address-list name." % value + end + end + end + + newproperty(:comment) do + desc "Address-list comment" + validate do |value| + unless value =~ /^[\w\s\.,()-]+$/ + raise ArgumentError, "%s is not a valid comment." % value + end + end + end + + newproperty(:disabled) do + desc "Defines whether address-list is ignored or used" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:address, :array_matching => :all) do + desc "IPv6 prefix" + + def insync?(is) + is.flatten.sort == should.flatten.sort + end + + validate do |values| + [values].flatten.each do |value| + unless value =~ /^[0-9a-f:]+(\/(\d|\d\d|1[01]\d|12[0-8]))?$/ + raise ArgumentError, "#{value} is not a valid IPv6 prefix." + end + end + end + end +end diff --git a/lib/puppet/type/mikrotik_ipv6_route.rb b/lib/puppet/type/mikrotik_ipv6_route.rb new file mode 100644 index 0000000..36af054 --- /dev/null +++ b/lib/puppet/type/mikrotik_ipv6_route.rb @@ -0,0 +1,115 @@ +Puppet::Type.newtype(:mikrotik_ipv6_route) do + @doc = "Manage Mikrotik IPv6 route creation, modification and deletion." + + apply_to_device + + ensurable + + newparam(:route) do + desc "The the route prefix." + isnamevar + validate do |value| + unless value =~ /^[a-f0-9:]+(\/(\d|[1-9]\d|1[01]\d|12[0-8]))?$/ + raise ArgumentError, "'%s' is not a valid route." % value + end + end + end + + newproperty(:gateway, :array_matching => :all) do + desc "Nexthop gateway(s)" + validate do |values| + [values].flatten.each do |value| + unless value =~ /^([a-f0-9:]+(%[^ ]+)?|[^ ]+)$/ + raise ArgumentError, "'%s' is not a valid gateway." % value + end + end + end + end + + newproperty(:comment) do + desc "Route comment" + validate do |value| + unless value =~ /^[\w\s\.,()-]+$/ + raise ArgumentError, "'%s' is not a valid comment." % value + end + end + end + + newproperty(:disabled) do + desc "Defines whether route is ignored or used" + newvalues(:no, :yes) + defaultto(:no) + end + + newproperty(:type) do + desc "Route type" + newvalues(:unicast, :unreachable) + defaultto(:unicast) + end + + newproperty(:distance) do + desc "Route distance" + newvalues(/(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])/) + end + + newproperty(:checkgateway) do + desc "Route check-gateway" + newvalues(:ping, :arp) + end + + newproperty(:targetscope) do + desc "Route target-scope" + newvalues(/(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])/) + end + + newproperty(:scope) do + desc "Route scope" + newvalues(/(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])/) + end + + newproperty(:routetag) do + desc "Route tag" + newvalues(/\d+/) + end + + newproperty(:bgpprepend) do + desc "Route bgp-prepend" + newvalues(/\d|1[0-6]/) + end + + newproperty(:bgporigin) do + desc "Route bgp-origin" + newvalues(:igp,:egp,:incomplete) + end + + newproperty(:bgpmed) do + desc "Route bgp-med" + newvalues(/\d+/) + end + + newproperty(:bgplocalpref) do + desc "Route bgp-local-pref" + newvalues(/\d+/) + end + + newproperty(:bgpcommunities, :array_matching => :all) do + desc "Route bgp-communities" + validate do |values| + [values].flatten.each do |value| + unless value =~ /^(\d+:\d+|internet|no-advertise|no-export|local-as)$/ + raise ArgumentError, "%s is not a valid bgp-community" % value + end + end + end + end + + newproperty(:bgpatomicaggregate) do + desc "Route bgp-atomic-aggregate" + newvalues(:yes, :no) + end + + newproperty(:bgpaspath) do + desc "Route bgp-as-path" + end + +end diff --git a/lib/puppet/util/network_device/mikrotik.rb b/lib/puppet/util/network_device/mikrotik.rb new file mode 100644 index 0000000..e4ecb3e --- /dev/null +++ b/lib/puppet/util/network_device/mikrotik.rb @@ -0,0 +1,4 @@ + +module Puppet::Util::NetworkDevice::Mikrotik + +end diff --git a/lib/puppet/util/network_device/mikrotik/device.rb b/lib/puppet/util/network_device/mikrotik/device.rb new file mode 100644 index 0000000..bf6ff84 --- /dev/null +++ b/lib/puppet/util/network_device/mikrotik/device.rb @@ -0,0 +1,399 @@ +require 'puppet/util/network_device/base' +require 'puppet/util/network_device/mikrotik/facts' + +class Puppet::Util::NetworkDevice::Mikrotik::Device < Puppet::Util::NetworkDevice::Base + + def initialize(url) + Puppet.debug("Puppet::Util::NetDevice::Mikrotik::Device:initialize: #{url}") + super(url) + transport.default_prompt = /\[[^@\[\]]+@[^@\[\]]+\]\s>\s\z/n + ObjectSpace.define_finalizer(self, self.class.method(:disconnect).to_proc) + end + + def connect + transport.connect unless @transport_connected + @transport_connected = true + end + + def self.disconnect + transport.close + end + + def command(cmd = nil) + connect + out = execute(cmd) if cmd + yield self if block_given? + #connect + out + end + + def execute(cmd) + transport.command(cmd) + end + + def facts + @facts ||= Puppet::Util::NetworkDevice::Mikrotik::Facts.new(transport) + facts = {} + command do |ng| + facts = @facts.retrieve + end + facts + end + + def parse_firewall_addresslists(family) + lists = {} + lines = [] + pos = '' + flag = '' + comment = '' + execute("/#{family} firewall address-list print detail without-paging\r").split(/[\n\r]+/).each do |l| + case l + when /^\s*(\d+)\s([X\s])\s;;;\s(.*)\s*$/ + pos = $1 + flag = $2 + comment = $3 + when /^\s*list=(\S+)\saddress=([^ ]+)\s*$/ + lines << "#{pos} #{flag} comment=#{comment} list=#{$1} address=#{$2}" + when /.*/ + lines << l + end + end + lines.each do |l| + case l + when /^\s*(\d+)\s([X\s])\slist=(\S+)\saddress=([^ ]+)\s*$/ + name = $3 + lists[name] = {:listname => name} unless lists[name] + lists[name]['pos'] = {} unless lists[name]['pos'] + lists[name]['pos'][$1] = $4 + newdis = ($2 == 'X') ? 'yes' : 'no' + lists[name][:disabled] = (lists[name][:disabled] and (newdis != lists[name][:disabled])) ? 'maybe' : newdis + (lists[name][:address] ||= []) << $4 + lists[name][:address].sort! + when /^\s*(\d+)\s([X\s])\scomment=(.*)\slist=(\S+)\saddress=([^ ]+)\s*$/ + name = $4 + lists[name] = {:listname => name} unless lists[name] + lists[name]['pos'] = {} unless lists[name]['pos'] + lists[name]['pos'][$1] = $5 + newdis = ($2 == 'X') ? 'yes' : 'no' + lists[name][:disabled] = (lists[name][:disabled] and (newdis != lists[name][:disabled])) ? 'maybe' : newdis + lists[name][:comment] = $3 + (lists[name][:address] ||= []) << $5 + lists[name][:address].sort! + end + end + lists + end + + def update_firewall_addresslist(family, listname, is = {}, should = {}) + lists = parse_firewall_addresslists(family) || {} + if should[:ensure] == :absent + Puppet.info "Removing address list #{listname}" + cmd = "/#{family} firewall address-list remove " + cmd += lists[listname]['pos'].keys.sort_by(&:to_i).reverse.join(',') + Puppet.debug("update_#{family}_firewall_addresslist: #{cmd}") + execute("#{cmd}\r") + return + end + + addr_is = [is[:address]].flatten.sort + addr_should = [should[:address]].flatten.sort + + if lists[listname] + Puppet.info "Updating address list #{listname} (#{addr_should.join(',')})" + if (is[:comment] != should[:comment]) or (is[:disabled] != should[:disabled]) + cmd = "/#{family} firewall address-list set" + cmd += " comment=\"#{should[:comment]}\"" unless is[:comment] == should[:comment] + cmd += " disabled=#{should[:disabled]}" unless is[:disabled] == should[:disabled] + cmd += " numbers=#{lists[listname]['pos'].keys.join(',')}" + Puppet.debug("update_#{family}_firewall_addresslist: #{cmd}") + execute("#{cmd}\r") + end + if !(addr_is == addr_should) + (addr_should - addr_is).each do |address| + cmd = "/#{family} firewall address-list add list=#{listname}" + cmd += " disabled=#{should[:disabled]}" if should[:disabled] + cmd += " comment=\"#{should[:comment]}\"" if should[:comment] + cmd += " address=#{address}" + Puppet.debug("update_#{family}_firewall_addresslist: #{cmd}") + execute("#{cmd}\r") + end + + if (addr_is - addr_should).size > 0 + cmd = "/#{family} firewall address-list remove " + cmd += lists[listname]['pos'].select{|k,v| (addr_is - addr_should).include? v}.collect{|x| x.first}.sort_by(&:to_i).reverse.join(',') + Puppet.debug("update_#{family}_firewall_addresslist: #{cmd}") + execute("#{cmd}\r") + end + end + else + Puppet.info "Creating address list #{listname} (#{addr_should.join(',')})" + addr_should.each do |address| + cmd = "/#{family} firewall address-list add list=#{listname}" + cmd += " disabled=#{should[:disabled]}" if should[:disabled] + cmd += " comment=\"#{should[:comment]}\"" if should[:comment] + cmd += " address=#{address}" + Puppet.debug("update_#{family}_firewall_addresslist: #{cmd}") + execute("#{cmd}\r") + end + end + end + + + def parse_items(cmd, flags_regex, prop_mapping, name_property=:name, array_properties=[]) + items = {} + + lines = [] + lastline = '' + execute("#{cmd}\r").split(/[\n\r]+/).each do |l| + case l + when /^\s*(\d+)\s(#{flags_regex})\s;;;\s(.*)\s*$/ + lines << lastline + lastline = "#{$1} #{$2} comment=\"#{$3}\"" + when /^\s*(\d+)\s(#{flags_regex})\s(.*)\s*$/ + lines << lastline + lastline = "#{$1} #{$2} #{$3}" + when /\[[^@\[\]]+@[^@\[\]]+\]\s>\s/ + #transport.default_prompt + # ignore the prompt + lines << lastline + lastline = '' + when /.*/ + lastline = "#{lastline} #{l}" + end + end + lines << lastline + + lines.each do |l| + case l + when /^\s*(\d+)\s(#{flags_regex})\s+(.*?)\s*$/ + item = {'pos' => $1} + flags = $2 + properties = $3 + + # parse_flags with custom code, item is skipped if code does not return anything + o = yield(flags) if block_given? + next unless o or !block_given? + item.merge!(o) if o + + until properties == '' do + break unless properties + case properties + when /^([a-z0-9-]+)="([^"]*)"\s*(.*?)\s*$/ + propkey=$1 + propval=$2 + properties = $3 + when /^([a-z0-9-]+)=([^ ]*)\s*(.*?)\s*$/ + propkey=$1 + propval=$2 + properties = $3 + when /^\s*$/ + properties = '' + when /^[^=]+?(?:\s+(.*?))?\s*$/ + properties = $1 + end + + next unless prop_mapping[propkey] + if array_properties.include? propkey + item[prop_mapping[propkey]] = propval.split(',') + else + item[prop_mapping[propkey]] = propval + end + end + + next unless item[name_property] + items[item[name_property]] = item + end + end + + items + end + + def update_item(label, items, cmd_prefix, prop_mapping, name, is={}, should={}, name_property=:name) + if should[:ensure] == :absent + Puppet.info "Removing #{label} #{name}" + cmd = "#{cmd_prefix} remove #{items[name]['pos']}" + Puppet.debug("update_item(#{label}): #{cmd}") + execute("#{cmd}\r") + return + end + + if items[name] + Puppet.info "Updating #{label} #{name}" + cmd = "#{cmd_prefix} set numbers=#{items[name]['pos']}" + else + Puppet.info "Creating #{label} #{name}" + cmd = "#{cmd_prefix} add" + end + should[name_property] = name unless should[name_property] # make sure we always have a name (defaults to name) + prop_mapping.each do |l,k| + next unless should[k] + next unless should[k] != is[k] + val = [should[k]].flatten.join(',') + val = "\"#{val}\"" if val =~/[\s=]/ + cmd += " #{l}=#{val}" + end + Puppet.debug("update_item(#{label}): #{cmd}") + execute("#{cmd}\r") + end + + + VLAN_PROPERTIES = { + 'name' => :name, + 'arp' => :arp, + 'comment' => :comment, + 'disabled' => :disabled, + 'interface' => :interface, + 'l2mtu' => :l2mtu, + 'mtu' => :mtu, + 'use-service-tag' => :useservicetag, + 'vlan-id' => :vlanid, + } + + def parse_interface_vlans + parse_items('/interface vlan print detail without-paging', /[\sXRS]{2}/, VLAN_PROPERTIES) do |flags| + { :disabled => (flags =~ /X/) ? 'yes' : 'no' } + end + end + + def update_interface_vlan(name, is = {}, should = {}) + update_item('VLAN', parse_interface_vlans(), '/interface vlan', VLAN_PROPERTIES, name, is, should) + end + + + ADDRESS_PROPERTIES = { + 'address' => :address, + 'advertise' => :advertise, + 'comment' => :comment, + 'disabled' => :disabled, + 'eui-64' => :eui64, + 'from-pool' => :frompool, + 'interface' => :interface, + 'network' => :network, + 'netmask' => :netmask, + 'broadcast' => :broadcast, + } + + def parse_addresses(family) + parse_items("/#{family} address print detail without-paging", /[\sXID][GL]?/, ADDRESS_PROPERTIES, :address) do |flags| + { :disabled => (flags =~ /X/) ? 'yes' : 'no' } unless flags =~ /D/ # ignore dynamic addresses + end + end + + def update_address(family, address, is={}, should={}) + update_item("#{family} address", parse_addresses(family), "/#{family} address", ADDRESS_PROPERTIES, address, is, should, :address) + end + + + ROUTE_PROPERTIES = { + 'bgp-as-path' => :bgpaspath, + 'bgp-atomic-aggregate' => :bgpatomicaggregate, + 'bgp-communities' => :bgpcommunities, + 'bgp-local-pref' => :bgplocalpref, + 'bgp-med' => :bgpmed, + 'bgp-origin' => :bgporigin, + 'bgp-prepend' => :bgpprepend, + 'check-gateway' => :checkgateway, + 'comment' => :comment, + 'disabled' => :disabled, + 'distance' => :distance, + 'dst-address' => :route, + 'gateway' => :gateway, + 'route-tag' => :routetag, + 'scope' => :scope, + 'target-scope' => :targetscope, + 'type' => :type, + 'pref-src' => :prefsrc, + 'routing-mark' => :routingmark, + 'vrf-interface' => :vrfinterface, + } + + def parse_routes(family) + parse_items("/#{family} route print detail without-paging", /[\sXADCSrobmPUB]{4}/, ROUTE_PROPERTIES, :route, ['gateway','bgp-communities']) do |flags| + { + :disabled => (flags =~ /X/) ? 'yes' : 'no', + :type => (flags =~ /U/) ? 'unreachable' : + ((flags =~ /P/) ? 'prohibit' : + ((flags =~ /B/) ? 'blackhole' : 'unicast')), + } unless flags =~ /[DC]/ # ignore dynamic & connected routes + end + end + + def update_route(family, route, is={}, should={}) + update_item("#{family} route", parse_routes(family), "/#{family} route", ROUTE_PROPERTIES, route, is, should, :route) + end + + + TUNNEL_PROPERTIES = { + 'name' => :name, + 'comment' => :comment, + 'disabled' => :disabled, + 'local-address' => :localaddress, + 'mtu' => :mtu, + 'remote-address' => :remoteaddress, + } + + def parse_interface_6to4s + parse_items('/interface 6to4 print detail without-paging', /[\sXR]{2}/, TUNNEL_PROPERTIES) do |flags| + { :disabled => (flags =~ /X/) ? 'yes' : 'no' } + end + end + + def update_interface_6to4(name, is = {}, should = {}) + update_item('6to4 tunnel', parse_interface_6to4s(), '/interface 6to4', TUNNEL_PROPERTIES, name, is, should) + end + + + LEASE_PROPERTIES = { + 'address' => :address, + 'comment' => :comment, + 'disabled' => :disabled, + 'address-list' => :addresslist, + 'always-broadcast' => :alwaysbroadcast, + 'block-access' => :blockaccess, + 'client-id' => :clientid, + 'lease-time' => :leasetime, + 'mac-address' => :macaddress, + 'rate-limit' => :ratelimit, + 'server' => :server, + 'use-src-mac' => :usesrcmac, + } + + def parse_ip_dhcpserver_leases + parse_items('/ip dhcp-server lease print detail without-paging', /[\sXRDB]/, LEASE_PROPERTIES, :address) do |flags| + { :disabled => (flags =~ /X/) ? 'yes' : 'no' } unless flags =~ /D/ # ignore dynamic leases + end + end + + def update_ip_dhcpserver_lease(address, is = {}, should = {}) + update_item('DHCP lease', parse_ip_dhcpserver_leases(), '/ip dhcp-server lease', LEASE_PROPERTIES, address, is, should, :address) + end + + OVPNCLIENT_PROPERTIES = { + 'name' => :name, + 'comment' => :comment, + 'disabled' => :disabled, + 'add-default-route' => :adddefaultroute, + 'auth' => :auth, + 'certificate' => :certificate, + 'cipher' => :cipher, + 'connect-to' => :connectto, + 'mac-address' => :macaddress, + 'max-mtu' => :maxmtu, + 'mode' => :mode, + 'password' => :password, + 'port' => :port, + 'profile' => :profile, + 'user' => :user, + } + + def parse_interface_ovpnclients + parse_items('/interface ovpn-client print detail without-paging', /[\sXR]{2}/, OVPNCLIENT_PROPERTIES, :name) do |flags| + { :disabled => (flags =~ /X/) ? 'yes' : 'no' } + end + end + + def update_interface_ovpnclient(name, is = {}, should = {}) + update_item('OVPN client', parse_interface_ovpnclients(), '/interface ovpn-client', OVPNCLIENT_PROPERTIES, name, is, should, :name) + end + +end diff --git a/lib/puppet/util/network_device/mikrotik/facts.rb b/lib/puppet/util/network_device/mikrotik/facts.rb new file mode 100644 index 0000000..1a5dcdb --- /dev/null +++ b/lib/puppet/util/network_device/mikrotik/facts.rb @@ -0,0 +1,150 @@ +require 'puppet/util/network_device/mikrotik' +require 'puppet/util/network_device/ipcalc' + +class Puppet::Util::NetworkDevice::Mikrotik::Facts + + include Puppet::Util::NetworkDevice::IPCalc + + attr_reader :transport + + def initialize(transport) + @transport = transport + end + + def retrieve + facts = {} + facts.merge!(parse_resource_print) + facts.merge!(parse_routerboard_print) + facts.merge!(parse_identity_print) + facts.merge!(parse_license_print) + facts.merge!(parse_addresses) + facts + end + + def parse_addresses + facts = {} + interfaces = [] + + lines = [] + lastline = '' + [ @transport.command("/ip address print terse\r").split(/[\n\r]+/), + @transport.command("/ipv6 address print terse\r").split(/[\n\r]+/) + ].flatten.each do |l| + case l + when /^\s*\d+\s.[GL]?\s/ + lines << lastline + lastline = l + when /\[[^@\[\]]+@[^@\[\]]+\]\s>\s/ + #transport.default_prompt + # ignore the prompt + lines << lastline + lastline = '' + when /.*/ + lastline = "#{lastline}#{l}" + end + end + lines << lastline + + lines.each do |l| + case l + when /\saddress=(#{IP})\/(\d+).*?\snetwork=(#{IP})\s.*?interface=([^ ]+)/ + facts["ipaddress_#{$4}"] = $1 + facts["netmask_#{$4}"] = netmask(Socket::AF_INET,$2.to_i).to_s + facts["network_#{$4}"] = $3 + interfaces << $4 + when /^\s*\d+\s.G\s.*address=(#{IP})\/\d+.*?\sinterface=([^ ]+)/ + # only consider Global addresses + facts["ipaddress6_#{$2}"] = $1 + interfaces << $2 + end + end + + facts ['interfaces'] = interfaces.sort.uniq.join(',') + facts + end + + def parse_license_print + facts = {} + @transport.command("/system license print\r").split(/[\n\r]+/).each do |l| + case l + when /^\s*software-id:\s(.+)/ + facts['software-id'] = $1 + when /^\s*upgradable-to:\s(.+)/ + facts['upgradable-to'] = $1 + when /^\s*nlevel:\s(.+)/ + facts['nlevel'] = $1 + when /^\s*features:\s(.*)/ + facts['features'] = $1 + end + end + facts + end + + def parse_identity_print + facts = {} + @transport.command("/system identity print\r").split(/[\n\r]+/).each do |l| + case l + when /^\s*name:\s(.+)/ + facts['hostname'] = $1 + end + end + facts + end + + def parse_routerboard_print + facts = {} + @transport.command("/system routerboard print\r").split(/[\n\r]+/).each do |l| + case l + when /^\s*routerboard:\s(.+)/ + facts['routerboard'] = $1 + when /^\s*model:\s(.+)/ + facts['productname'] = $1 + when /^\s*serial-number:\s(.+)/ + facts['serialnumber'] = $1 + when /^\s*current-firmware:\s(.+)/ + facts['currentfirmware'] = $1 + when /^\s*upgrade-firmware:\s(.+)/ + facts['upgradefirmware'] = $1 + end + end + facts + end + + def parse_resource_print + facts = {} + @transport.command("/system resource print\r").split(/[\n\r]+/).each do |l| + case l + when /^\s*uptime:\s(\S+)/ + facts['uptime_seconds'] = uptime_to_seconds($1) + facts['uptime_hours'] = facts['uptime_seconds'].to_i / (60 * 60) + facts['uptime_days'] = facts['uptime_hours'].to_i / 24 + facts['uptime'] = "#{String(facts['uptime_days'])} days" + when /^\s*version:\s(.*)/ + facts['operatingsystemrelease'] = $1 + when /^\s*platform:\s(.*)/ + facts['operatingsystem'] = $1 + when /^\s*architecture-name:\s(.*)/ + facts['architecture'] = $1 + when /^\s*cpu-count:\s(.*)/ + facts['processorcount'] = $1.to_i + when /^\s*cpu:\s(.*)/ + facts['processor0'] = $1 + when /^\s*board-name:\s(.*)/ + facts['boardproductname'] = $1 + when /^\s*free-memory:\s(.*)/ + facts['memoryfree'] = $1 + when /^\s*total-memory:\s(.*)/ + facts['memorytotal'] = $1 + facts['memorysize'] = $1 + end + end + facts + end + + def uptime_to_seconds(uptime) + captures = (uptime.match /^(?:(\d+)w)?(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?(\d+)s/).captures + captures.zip([7*24*60*60, 24*60*60, 60*60, 60, 1]).inject(0) do |total, (x,y)| + total + (x.nil? ? 0 : x.to_i * y) + end + end +end diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..71a24da --- /dev/null +++ b/metadata.json @@ -0,0 +1,13 @@ +{ + "name": "xway-mikrotik", + "version": "0.0.1", + "author": "Andreas Jaggi ", + "license": "Apache 2.0", + "source": "https://github.com/x-way/puppet-mikrotik", + "project_page": "https://github.com/x-way/puppet-mikrotik", + "issues_url": "https://github.com/x-way/puppet-mikrotik/issues", + "tags": ["mikrotik","routeros","networkdevice","device","networking"], + "description": "Mikrotik Networkdevice Module", + "summary": "Network device extensions for Mikrotik", + "dependencies": [] +}