Skip to main content

Overview

NMIS provides comprehensive device (node) management capabilities for organizing and configuring your monitored network infrastructure. Devices can be grouped, tagged, and configured with custom properties to match your operational needs.

Node Configuration

Configure device properties, SNMP settings, and polling behavior

Groups & Tags

Organize devices using logical groups and custom tags

Bulk Operations

Manage multiple devices simultaneously with bulk actions

Node Lifecycle

Create, update, rename, activate, and delete nodes

Node Object Model

Every device in NMIS is represented as a Node object with these core attributes:
# From Node.pm:75-89
sub new {
    my ( $class, %args ) = @_;
    
    return if ( !$args{nmisng} );
    return if ( !$args{uuid} );  # UUID is required
    
    my $self = {
        _dirty             => {},
        _nmisng            => $args{nmisng},
        _id                => $args{_id} // $args{id} // undef,
        uuid               => $args{uuid},
        collection         => $args{nmisng}->nodes_collection(),
        encryption_enabled => NMISNG::Util::getbool($args{nmisng}->config->{'global_enable_password_encryption'})
    };
    bless( $self, $class );
}
UUID: Each node has a unique identifier (UUID) that remains constant even if the node is renamed. This ensures data continuity and relationship integrity.

Node Properties

Core Properties

name
string
required
Node name (unique identifier, can be hostname or descriptive name)
host
string
required
Management IP address or resolvable hostname
group
string
required
Logical group assignment (e.g., Branches, Core, Distribution)
active
boolean
default:"true"
Whether node is actively monitored
collect
boolean
default:"true"
Enable data collection (SNMP polling)
ping
boolean
default:"true"
Enable ICMP ping monitoring

Device Classification

nodeType
string
Device type: router, switch, server, firewall, wireless, etc.
nodeModel
string
Model file defining collection behavior (e.g., Model-CiscoRouter, Model-Generic)
nodeVendor
string
Device vendor/manufacturer
roleType
string
Network role: core, distribution, access, edge

Organizational Properties

location
string
Physical location or site identifier
businessService
string
Associated business service or application
customer
string
Customer or department name
comments
array
User comments and notes about the device

Managing Nodes with CLI

Creating Nodes

# Add a new router
nmis-cli act=create node=router1 \
  host=192.168.1.1 \
  group=Core \
  community=public

# Add with full configuration
nmis-cli act=create node=switch1 \
  host=10.0.0.10 \
  group=Distribution \
  community=private \
  location="Building A" \
  customer="IT Department" \
  roleType=distribution \
  nodeType=switch

# Add SNMPv3 device
nmis-cli act=create node=fw1 \
  host=172.16.0.1 \
  group=Security \
  version=snmpv3 \
  username=nmisuser \
  authpassword=auth123 \
  privpassword=priv456

Updating Node Properties

# Update single property
nmis-cli act=set node=router1 location="Data Center 1"

# Update multiple properties
nmis-cli act=set node=switch1 \
  group=Access \
  roleType=access \
  customer="Sales Department"

# Update SNMP community
nmis-cli act=set node=router1 community=newcommunity

# Change management IP
nmis-cli act=set node=device1 host=10.0.0.20

Viewing Node Configuration

# Show all node properties
nmis-cli act=show node=router1

# Show specific property
nmis-cli act=show node=router1 property=group

# List all nodes
nmis-cli act=list-nodes

# List nodes in group
nmis-cli act=list-nodes group=Core

# Export node configuration
nmis-cli act=export node=router1 > router1-config.json

Node Lifecycle Management

Activation and Deactivation

# From Node.pm:516-527
sub activated {
    my ($self, $newstate) = @_;
    if (ref($newstate) eq "HASH") {
        $self->_dirty(1, "activated");
        $self->{_activated} = $newstate;
        # Propagate to old-style active flag for compat
        $self->{_configuration}->{active} = $newstate->{NMIS}? 1:0;
    }
    return Clone::clone($self->{_activated});
}
# Activate a node
nmis-cli act=set node=router1 active=true

# Deactivate (stop monitoring)
nmis-cli act=set node=router1 active=false

# Enable collection only
nmis-cli act=set node=router1 collect=true ping=false

Renaming Nodes

# From Node.pm:1431-1460
sub rename {
    my ($self, %args) = @_;
    
    my $newname = $args{new_name};
    my $old = $self->name;
    
    return (0, "Invalid new_name argument") if (!$newname);
    
    # '/' is forbidden in node names
    return (0, "new_name contains forbidden character '/'") 
        if ($newname =~ m!/!);
    
    my $nodenamerule = $self->nmisng->config->{node_name_rule} || qr/^[a-zA-Z0-9_. -]+$/;
    return (0, "new node name does not match 'node_name_rule' regex")
        if ($newname !~ $nodenamerule);
    
    return (1, "new_name same as current, nothing to do")
        if ($newname eq $old);
    
    my $clash = $self->nmisng->get_nodes_model(name => $newname);
    return (0, "A node named \"$newname\" already exists!")
        if ($clash->count);
}
# Rename a node (preserves all data via UUID)
nmis-cli act=rename node=oldname new_name=newname

# Rename with confirmation
nmis-cli act=rename node=router-old new_name=router-new confirm=true
Renaming nodes updates the name but preserves all historical data through the UUID. However, this operation:
  • Relocates RRD files to new path
  • Updates all database references
  • Removes all events (cannot be renamed sensibly)
  • May take time for nodes with extensive data

Deleting Nodes

# From Node.pm:614-774
sub delete {
    my ($self,%args) = @_;
    my $keeprrd = NMISNG::Util::getbool($args{keep_rrd});
    
    return (1, "Node already deleted") if ($self->{_deleted});
    return (1, "Node has never been saved") if ($self->is_new);
    
    # Deactivate first
    my $curcfg = $self->configuration;
    if ($curcfg->{activated}->{NMIS}) {
        $curcfg->{activated}->{NMIS} = $curcfg->{active} = 0;
        $self->configuration($curcfg);
        $self->save;
    }
    
    # Remove queued jobs
    # Delete all inventory instances
    # Clean up RRD files (unless keep_rrd)
    # Delete all events
    # Remove opstatus entries
}
# Delete node and all data
nmis-cli act=delete node=router1 confirm=yes

# Delete but keep RRD files
nmis-cli act=delete node=switch1 keep_rrd=true confirm=yes

# Delete multiple nodes
nmis-cli act=delete-nodes nodes=router1,router2,router3 confirm=yes

Grouping and Organization

Groups

Groups are the primary organizational unit in NMIS:
# Create group structure
nmis-cli act=create-group name="Core Network"
nmis-cli act=create-group name="Branch Offices"
nmis-cli act=create-group name="Data Centers"

# Assign nodes to groups
nmis-cli act=set node=router1 group="Core Network"
nmis-cli act=set node=switch1 group="Branch Offices"

# List nodes by group
nmis-cli act=list-nodes group="Core Network"

# Bulk update group membership
nmis-cli act=bulk-update location="DC1" group="Data Centers"

Tagging

Tags provide flexible, multi-dimensional categorization:
# From Node.pm:597-611
sub enterprise_service_tags {
    my ($self, $newaliases) = @_;
    if (ref($newaliases) eq "ARRAY") {
        $self->{_enterprise_service_tags}  = $newaliases;
        $self->_dirty(1, "enterprise_service_tags");
    }
    return Clone::clone($self->{_enterprise_service_tags} // []);
}
# Add service tags
nmis-cli act=set node=router1 \
  tags="production,critical,monitored-24x7"

# Search by tags
nmis-cli act=list-nodes tags="critical"

# Bulk tag assignment
nmis-cli act=bulk-update group="Core" tags="production,critical"

Node Properties and Comments

Adding Comments

# From Node.pm:533-543
sub comments {
    my ($self, $newcomments) = @_;
    if (ref($newcomments) eq "ARRAY") {
        $self->{_comments}  = $newcomments;
        $self->_dirty(1, "comments");
    }
    return Clone::clone($self->{_comments} // []);
}
# Add comment to node
nmis-cli act=add-comment node=router1 \
  comment="Upgraded to IOS 15.2 on 2024-03-04"

# View node comments
nmis-cli act=show node=router1 property=comments

# Add comment with metadata
nmis-cli act=add-comment node=switch1 \
  comment="Changed VLAN configuration" \
  user="admin" \
  date="2024-03-04"

Custom Addresses and Aliases

# From Node.pm:465-495
sub aliases {
    my ($self, $newaliases) = @_;
    if (ref($newaliases) eq "ARRAY") {
        $self->{_aliases}  = $newaliases;
        $self->_dirty(1, "aliases");
    }
    return Clone::clone($self->{_aliases} // []);
}

sub addresses {
    my ($self, $newaddys) = @_;
    if (ref($newaddys) eq "ARRAY") {
        $self->{_addresses}  = $newaddys;
        $self->_dirty(1, "addresses");
    }
    return Clone::clone($self->{_addresses} // []);
}

Bulk Operations

Import Nodes from CSV

# Import from CSV file
/usr/local/nmis9/admin/import_nodes.pl file=nodes.csv

# Sample CSV format:
name,host,group,community,location,customer
router1,192.168.1.1,Core,public,DC1,IT
switch1,192.168.1.10,Distribution,public,DC1,IT
router2,10.0.0.1,Branch,private,Site-A,Operations

Bulk Updates

# Update all nodes in group
nmis-cli act=bulk-update group=Test community=newcommunity

# Update by location
nmis-cli act=bulk-update location="Remote" timeout=10

# Update by nodeType
nmis-cli act=bulk-update nodeType=router collect=true ping=true

Export and Backup

# Export single node
nmis-cli act=export node=router1 > router1.json

# Export all nodes
nmis-cli act=export-nodes > all-nodes.json

# Export group
nmis-cli act=export-nodes group=Core > core-nodes.json

# Backup node configurations
nmis-cli act=backup-nodes dir=/backup/nmis/

Node Status

NMIS tracks node operational status:
# From Node.pm:1212-1284
sub coarse_status {
    my ($self, %args) = @_;
    
    # 1 for reachable
    # 0 for unreachable
    # -1 for degraded
    my $status = 1;
    
    # Check for Node Down event
    if (my $erec = $self->eventExist($node_down)) {
        $status = 0;
    }
    # Pingable but dead SNMP/WMI -> degraded
    elsif (NMISNG::Util::getbool($catchall_data->{collect}) and
           ($self->eventExist($snmp_down) or 
            $self->eventExist($wmi_down_event))) {
        $status = -1;
    }
    
    return $status;
}
# Check node status
nmis-cli act=status node=router1

# List node states
nmis-cli act=list-nodes status=down
nmis-cli act=list-nodes status=degraded
nmis-cli act=list-nodes status=up

Advanced Configuration

Polling Policies

# Assign polling policy
nmis-cli act=set node=router1 polling_policy=HighPriority

# Create custom policy
nmis-cli act=create-policy name=Critical \
  collect_interval=60 \
  update_interval=300

Overrides

Override model-defined values on a per-node basis:
# Override specific model values
nmis-cli act=set-override node=router1 \
  override="{ifHighSpeed: 1000000}"

# Clear overrides
nmis-cli act=clear-overrides node=router1

Best Practices

  1. Naming Convention: Use consistent, descriptive names (e.g., site-type-number)
  2. Group Structure: Design logical group hierarchy before adding nodes
  3. Regular Audits: Periodically review and clean up inactive nodes
  4. Document Changes: Use comments to track configuration changes
  5. Backup Regularly: Export node configurations before major changes
  6. Test Before Production: Use test groups for new configurations
  7. Use Tags: Leverage tags for cross-cutting concerns (criticality, applications)

Troubleshooting

Node Not Collecting Data

# Check node status
nmis-cli act=show node=router1 property=active,collect

# Verify SNMP connectivity
nmis-cli act=test-snmp node=router1

# Check last update time
nmis-cli act=show node=router1 property=lastupdate

# Force update
nmis-cli act=update node=router1

Node Rename Issues

# Check for name conflicts
nmis-cli act=list-nodes | grep newname

# Verify name follows rules
# Default rule: ^[a-zA-Z0-9_. -]+$

# Check rename logs
tail -f /usr/local/nmis9/logs/nmis.log | grep rename

Next Steps

Network Discovery

Automatically discover and add devices to NMIS

Performance Data

Configure data collection and storage for managed nodes

Build docs developers (and LLMs) love