class Jamf::NetworkSegment
A Network Segment in the JSS
Constants
- OBJECT_HISTORY_OBJECT_TYPE
the object type for this object in the object history table. See {APIObject#add_object_history_entry}
- RSRC_BASE
the REST resource base
- RSRC_LIST_KEY
the hash key used for the JSON list output of all objects in the
JSS
- RSRC_OBJECT_KEY
The hash key used for the JSON object output. It’s also used in various error messages
Attributes
@return [String] building for this segment. Must be one of the buildings in the JSS
@return [String] department for this segment. Must be one of the depts in the JSS
@return [String] the name of the distribution point to be used from this network segment
@return [IPAddr] ending IP adresss
@return [String] the netboot server for this segment
@return [Boolean] should machines checking in from this segment update their building
@return [Boolean] should machines checking in from this segment update their dept
@return [IPAddr] starting IP adresss
@return [String] the swupdate server for this segment.
@return [String] the mount url for the distribution point
Public Class Methods
Given a starting address & ending address, mask, or cidr, return a Range object of IPAddr
objects.
starting_address
: must be provided, and may be a masked address, in which case nothing else is needed.
If starting_address
: is an unmasked address, then one of ending_address
: cidr: or mask: must be provided.
If given, ending_address
: overrides mask:, cidr:, and a masked starting_address
:
These give the same result:
ip_range
starting_address
: ‘192.168.1.0’, ending_address
: ‘192.168.1.255’ ip_range
starting_address
: ‘192.168.1.0’, mask: ‘255.255.255.0’ ip_range
starting_address
: ‘192.168.1.0’, cidr: 24 ip_range
starting_address
: ‘192.168.1.0/24’ ip_range
starting_address
: ‘192.168.1.0/255.255.255.0’
All the above will produce:
#<IPAddr: IPv4:192.168.1.0/255.255.255.255>..#<IPAddr: IPv4:192.168.1.255/255.255.255.255>
An exception is raised if the starting address is above the ending address.
@param starting_address The starting address, possibly masked
@param ending_address The ending address. If given, it overrides mask:,
cidr: and a masked starting_address:
@param mask The subnet mask to apply to the starting address to get
the ending address
@param cidr[String, Integer] he cidr value to apply to the starting address to get
the ending address
@return [Range<IPAddr>] the valid Range
# File lib/jamf/api/classic/api_objects/network_segment.rb 189 def self.ip_range(starting_address: nil, ending_address: nil, mask: nil, cidr: nil) 190 raise Jamf::MissingDataError, 'starting_address: must be provided' unless starting_address 191 192 starting_address = masked_starting_address(starting_address: starting_address, mask: mask, cidr: cidr) 193 194 if ending_address 195 startip = IPAddr.new starting_address.split('/').first 196 endip = IPAddr.new ending_address.to_s 197 validate_ip_range(startip, endip) 198 else 199 raise ArgumentError, 'Must provide ending_address:, mask:, cidr: or a masked starting_address:' unless starting_address.include? '/' 200 subnet = IPAddr.new starting_address 201 startip = subnet.to_range.first.mask 32 202 endip = subnet.to_range.last.mask 32 203 end 204 205 startip..endip 206 end
given 2 IPAddr
instances, find out how ‘wide’ they are - how many IP addresses exist between them.
# File lib/jamf/api/classic/api_objects/network_segment.rb 308 def self.ip_range_width(ip1, ip2) 309 raise ArgumentError, 'Parameters must be IPAddr objects' unless ip1.is_a?(IPAddr) && ip2.is_a?(IPAddr) 310 311 low, high = [ip1, ip2].sort 312 high.to_i - low.to_i 313 end
If we are given a mask or cidr, append them to the starting_address
@param starting The starting address, possibly masked
@param mask The subnet mask to apply to the starting address to get
the ending address
@param cidr[String, Integer] he cidr value to apply to the starting address to get
the ending address
@return [String] the starting with the mask or cidr appended
# File lib/jamf/api/classic/api_objects/network_segment.rb 220 def self.masked_starting_address(starting_address: nil, mask: nil, cidr: nil) 221 starting_address = "#{starting}/#{mask || cidr}" if mask || cidr 222 starting_address.to_s 223 end
Which network segment is seen as current? According to the Jamf
Pro Admin Guide, the ‘smallest’ one - the one with fewest IP addrs within it. If multiple ones have the same number of IPs, then its the one with the lowest starting address
@param name [Boolean] return the name of the netsegment, not the id
@return [Integer, String
, nil] the id of the current net segment, or nil
# File lib/jamf/api/classic/api_objects/network_segment.rb 341 def self.my_network_segment(refresh = false, name: false, api: nil, cnx: Jamf.cnx) 342 cnx = api if api 343 344 my_ip = Jamf::Client.my_ip_address 345 return nil unless my_ip 346 347 id = network_segment_for_ip(my_ip, refresh: refresh, cnx: cnx) 348 return id unless name 349 350 map_all_ids_to(:name, cnx: cnx)[id] 351 end
Find the current network segment ids for the machine running this code
See my_network_segment
to get the current one according to the server.
@param names [Boolean] the array will contain Network Segment names, not ids
@return [Array<Integer>,Array<String>] the NetworkSegment
ids or names for this machine right now.
# File lib/jamf/api/classic/api_objects/network_segment.rb 323 def self.my_network_segments(refresh = false, names: false, api: nil, cnx: Jamf.cnx) 324 cnx = api if api 325 326 ids = network_segments_for_ip Jamf::Client.my_ip_address, refresh, cnx: cnx 327 return ids unless names 328 329 ids_to_names = map_all_ids_to :name, cnx: cnx 330 ids.map { |id| ids_to_names[id] } 331 end
All NetworkSegments in the given API as ruby Ranges of IPAddr
instances representing the Segment, e.g. with starting = 10.24.9.1 and ending = 10.24.15.254 the range looks like:
<IPAddr: IPv4:10.24.9.1/255.255.255.255> .. <IPAddr: IPv4:10.24.15.254/255.255.255.255>
Using the include?
method on those Ranges is very useful.
Note1: We don’t use the IPAddr#to_range method because that works
best for masked IPAddrs (which are ranges of IPs with widths determined by the mask) and Jamf Network Segments can have arbitrary widths.
Note2: See the network_ranges_as_integers
method below, which is similar
but much faster.
@param refresh should the data be re-queried?
@param cnx [Jamf::Connection] the API to query
@return [Hash{Integer => Range}] the network segments as IPv4 address Ranges
keyed by id
# File lib/jamf/api/classic/api_objects/network_segment.rb 95 def self.network_ranges(refresh = false, api: nil, cnx: Jamf.cnx) 96 cnx = api if api 97 98 @network_ranges = nil if refresh 99 return @network_ranges if @network_ranges 100 101 @network_ranges = {} 102 all(refresh, cnx: cnx).each do |ns| 103 @network_ranges[ns[:id]] = IPAddr.new(ns[:starting_address])..IPAddr.new(ns[:ending_address]) 104 end 105 @network_ranges 106 end
An IPv4 Address is really just a 32-bit integer, displayed as four 8-bit integers. e.g. ‘10.0.69.1’ is really the integer 167789825 The to_i method of IPAddr
objects returns that integer (or the first of them if the IPAddr
is masked).
Using ranges made of those integers is far faster than using ranges if IPAddr
objects, so that’s what this method returns.
See also: the network_ranges
method above
@param refresh should the data be re-queried?
@param cnx [Jamf::Connection] the APIConnection
to query
@return [Hash{Integer => Range}] the network segments as Integer Ranges
keyed by id
# File lib/jamf/api/classic/api_objects/network_segment.rb 125 def self.network_ranges_as_integers(refresh = false, api: nil, cnx: Jamf.cnx) 126 cnx = api if api 127 128 @network_ranges_as_integers = nil if refresh 129 return @network_ranges_as_integers if @network_ranges_as_integers 130 131 @network_ranges_as_integers = {} 132 all(refresh, cnx: cnx).each do |ns| 133 first = IPAddr.new(ns[:starting_address]).to_i 134 last = IPAddr.new(ns[:ending_address]).to_i 135 @network_ranges_as_integers[ns[:id]] = first..last 136 end 137 @network_ranges_as_integers 138 end
Which network segment is seen as current for a given IP addr?
According to the Jamf
Pro Admin Guide, if an IP is in more than one network segment, it uses the ‘smallest’ (narrowest) one - the one with fewest IP addrs within it.
If multiple ones have the same width, then it uses the one of those with the lowest starting address
@return [Integer, nil] the id of the current net segment, or nil
# File lib/jamf/api/classic/api_objects/network_segment.rb 273 def self.network_segment_for_ip(ipaddr, refresh: false, api: nil, cnx: Jamf.cnx) 274 cnx = api if api 275 276 # get the ip as a 32bit interger 277 ip = IPAddr.new(ipaddr.to_s).to_i 278 # a hash of NetSeg ids => Range<Integer> 279 ranges = network_ranges_as_integers(refresh, cnx: cnx).select { |_id, range| range.include? ip } 280 281 # we got nuttin 282 return nil if ranges.empty? 283 284 # if we got only one, its the one 285 return ranges.keys.first if ranges.size == 1 286 287 # got more than one, sort by range size/width, asc. 288 sorted_by_size = ranges.sort_by { |_i, r| r.size }.to_h 289 290 # the first one is the smallest/narrowest. 291 _smallest_range_id, smallest_range = sorted_by_size.first 292 293 smallest_range_size = smallest_range.size 294 295 # select all of them that are the same size 296 all_of_small_size = sorted_by_size.select { |_i, r| r.size == smallest_range_size } 297 298 # sort them by the start of each range (r.first) 299 # and return the lowest start (returned by min_by) 300 my_range_id, _my_range = all_of_small_size.min_by { |_i, r| r.first } 301 302 # and return the id 303 my_range_id 304 end
Find the ids of the network segments that contain a given IP address.
Even tho IPAddr.include? will take a String
or an IPAddr
I convert the ip to an IPAddr
so that an exception will be raised if the ip isn’t a valid ip.
@param ip[String, IPAddr] the IP address to locate
@param refresh should the data be re-queried?
@param cnx [Jamf::Connection] The API connection to query
@return [Array<Integer>] the ids of the NetworkSegments containing the given ip
# File lib/jamf/api/classic/api_objects/network_segment.rb 253 def self.network_segments_for_ip(ipaddr, refresh = false, api: nil, cnx: Jamf.cnx) 254 cnx = api if api 255 256 # get the ip as a 32bit interger 257 ip = IPAddr.new(ipaddr.to_s).to_i 258 # a hash of NetSeg ids => Range<Integer> 259 network_ranges_as_integers(refresh, cnx: cnx).select { |_id, range| range.include? ip }.keys 260 end
Instantiate a NetworkSegment
@see_also Jamf::NetworkSegment.ip_range
for how starting and ending addresses can be provided when using id: :new
Jamf::APIObject::new
# File lib/jamf/api/classic/api_objects/network_segment.rb 391 def initialize(**args) 392 super 393 394 if args[:id] == :new 395 range = self.class.ip_range( 396 starting_address: args[:starting_address], 397 ending_address: args[:ending_address], 398 mask: args[:mask], 399 cidr: args[:cidr] 400 ) 401 @init_data[:starting_address] = range.begin.to_s 402 @init_data[:ending_address] = range.end.to_s 403 end 404 405 @starting_address = IPAddr.new @init_data[:starting_address] 406 @ending_address = IPAddr.new @init_data[:ending_address] 407 408 @building = @init_data[:building] 409 @department = @init_data[:department] 410 @distribution_point = @init_data[:distribution_point] 411 @netboot_server = @init_data[:netboot_server] 412 @override_buildings = @init_data[:override_buildings] 413 @override_departments = @init_data[:override_departments] 414 @swu_server = @init_data[:swu_server] 415 @url = @init_data[:url] 416 end
An alias for {NetworkSegment.network_ranges}
DEPRECATED: This will be going away in a future release.
@see {NetworkSegment::network_ranges}
# File lib/jamf/api/classic/api_objects/network_segment.rb 146 def self.subnets(refresh = false, api: nil, cnx: Jamf.cnx) 147 cnx = api if api 148 149 network_ranges refresh, cnx: cnx 150 end
Raise an exception if a given starting ip is higher than a given ending ip
@param startip The starting ip
@param endip The ending ip
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 233 def self.validate_ip_range(startip, endip) 234 return nil if IPAddr.new(startip.to_s) <= IPAddr.new(endip.to_s) 235 236 raise Jamf::InvalidDataError, "Starting IP #{startip} is higher than ending ip #{endip} " 237 end
Public Instance Methods
Does this network segment equal another? equality means the ranges are equal
@param other_segment the other segment to check
@return [Boolean] Does this segment include the other?
# File lib/jamf/api/classic/api_objects/network_segment.rb 464 def ==(other) 465 raise TypeError, 'Argument must be a Jamf::NetworkSegment' unless \ 466 other.is_a? Jamf::NetworkSegment 467 range == other.range 468 end
Set the building
@param newval[String, Integer] the new building by name or id, must be in the JSS
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 476 def building=(newval) 477 new = 478 if newval.to_s.empty? 479 Jamf::BLANK 480 else 481 id = Jamf::Building.valid_id newval 482 raise Jamf::MissingDataError, "No building matching '#{newval}'" unless id 483 484 Jamf::Building.map_all_ids_to(:name)[id] 485 end 486 487 @building = new 488 @need_to_update = true 489 end
set the ending address by applying a new cidr (e.g. 24) or mask (e.g. 255.255.255.0)
@param newval[String, Integer] the new cidr or mask
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 630 def cidr=(newval) 631 new_end = IPAddr.new("#{@starting_address}/#{newval}").to_range.end.mask 32 632 self.class.validate_ip_range(@starting_address, new_end) 633 @ending_address = new_end 634 @need_to_update = true 635 end
set the department
@param newval[String, Integer] the new dept by name or id, must be in the JSS
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 509 def department=(newval) 510 new = 511 if newval.to_s.empty? 512 Jamf::BLANK 513 else 514 id = Jamf::Department.valid_id newval 515 raise Jamf::MissingDataError , "No department matching '#{newval}' in the JSS" unless id 516 517 Jamf::Department.map_all_ids_to(:name)[id] 518 end 519 @department = new 520 @need_to_update = true 521 end
set the distribution_point
@param newval[String, Integer, nil] the new dist. point by name or id, must be in the JSS
, or nil or blank to unset
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 542 def distribution_point=(newval) 543 new = 544 if newval.to_s.empty? 545 Jamf::BLANK 546 else 547 id = Jamf::DistributionPoint.valid_id newval 548 raise Jamf::MissingDataError, "No distribution_point matching '#{newval}' in the JSS" unless id 549 550 Jamf::DistributionPoint.map_all_ids_to(:name)[id] 551 end 552 553 @distribution_point = new 554 @need_to_update = true 555 end
set the ending address
@param newval[String, IPAddr] the new ending address
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 617 def ending_address=(newval) 618 self.class.validate_ip_range(@starting_address, newval) 619 @ending_address = IPAddr.new newval.to_s 620 @need_to_update = true 621 end
Does this network segment include an address or another segment? Inclusion means the other is completely inside this one.
@param thing[Jamf::NetworkSegment, String
, IPAddr] the other thing to check
@return [Boolean] Does this segment include the other?
# File lib/jamf/api/classic/api_objects/network_segment.rb 447 def include?(thing) 448 if thing.is_a? Jamf::NetworkSegment 449 @starting_address <= thing.range.begin && @ending_address >= thing.range.end 450 else 451 thing = IPAddr.new thing.to_s 452 range.cover? thing 453 end 454 end
set the netboot_server
@param newval[String, Integer] the new netboot server by name or id, must be in the JSS
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 563 def netboot_server=(newval) 564 new = 565 if newval.to_s.empty? 566 Jamf::BLANK 567 else 568 id = Jamf::NetBootServer.valid_id newval 569 raise Jamf::MissingDataError, "No netboot_server matching '#{newval}' in the JSS" unless id 570 571 Jamf::NetbootServer.map_all_ids_to(:name)[id] 572 end 573 574 @netboot_server = new 575 @need_to_update = true 576 end
Does this network segment overlap with another?
@param other_segment the other segment to check
@return [Boolean] Does the other segment overlap this one?
# File lib/jamf/api/classic/api_objects/network_segment.rb 433 def overlap?(other_segment) 434 raise TypeError, 'Argument must be a Jamf::NetworkSegment' unless \ 435 other_segment.is_a? Jamf::NetworkSegment 436 other_range = other_segment.range 437 range.include?(other_range.begin) || range.include?(other_range.end) 438 end
set the override buildings option
@param newval the new override buildings option
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 497 def override_buildings=(newval) 498 raise Jamf::InvalidDataError, 'New value must be boolean true or false' unless Jamf::TRUE_FALSE.include? newval 499 @override_buildings = newval 500 @need_to_update = true 501 end
set the override depts option
@param newval the new setting
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 530 def override_departments=(newval) 531 raise Jamf::InvalidDataError, 'New value must be boolean true or false' unless Jamf::TRUE_FALSE.include? newval 532 @override_departments = newval 533 @need_to_update = true 534 end
a Range built from the start and end addresses. To be used for finding inclusion and overlaps.
@return [Range<IPAddr>] the range of IPAddrs for this segment.
# File lib/jamf/api/classic/api_objects/network_segment.rb 423 def range 424 @starting_address..@ending_address 425 end
set a new starting and ending addr at the same time.
@see_also NetworkSegment.ip_range
for how to specify the starting and ending addresses.
@param starting_address The starting address, possibly masked
@param ending_address The ending address
@param mask The subnet mask to apply to the starting address to get
the ending address
@param cidr[String, Integer] he cidr value to apply to the starting address to get
the ending address
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 654 def set_ip_range(starting_address: nil, ending_address: nil, mask: nil, cidr: nil) 655 range = self.class.ip_range( 656 starting_address: starting_address, 657 ending_address: ending_address, 658 mask: mask, 659 cidr: cidr 660 ) 661 @starting_address = range.first 662 @ending_address = range.last 663 @need_to_update = true 664 end
set the starting address
@param newval[String, IPAddr] the new starting address
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 605 def starting_address=(newval) 606 self.class.validate_ip_range(newval, @ending_address) 607 @starting_address = IPAddr.new newval.to_s 608 @need_to_update = true 609 end
set the sw update server
@param newval[String, Integer] the new server by name or id, must be in the JSS
@return [void]
# File lib/jamf/api/classic/api_objects/network_segment.rb 584 def swu_server=(newval) 585 new = 586 if newval.to_s.empty? 587 Jamf::BLANK 588 else 589 id = Jamf::SoftwareUpdateServer.valid_id newval 590 raise Jamf::MissingDataError, "No swu_server matching '#{newval}' in the JSS" unless id 591 592 Jamf::SoftwareUpdateServer.map_all_ids_to(:name)[id] 593 end 594 595 @swu_server = new 596 @need_to_update = true 597 end
Private Instance Methods
the xml formated data for adding or updating this in the JSS
# File lib/jamf/api/classic/api_objects/network_segment.rb 677 def rest_xml 678 doc = REXML::Document.new Jamf::Connection::XML_HEADER 679 ns = doc.add_element 'network_segment' 680 ns.add_element('building').text = @building 681 ns.add_element('department').text = @department 682 ns.add_element('distribution_point').text = @distribution_point 683 ns.add_element('ending_address').text = @ending_address.to_s 684 ns.add_element('name').text = @name 685 ns.add_element('netboot_server').text = @netboot_server 686 ns.add_element('override_buildings').text = @override_buildings 687 ns.add_element('override_departments').text = @override_departments 688 ns.add_element('starting_address').text = @starting_address.to_s 689 ns.add_element('swu_server').text = @swu_server 690 doc.to_s 691 end