Managing Users
In this section, you will configure Kanoa's security model with different users, roles, and permissions, so the system can support different types of users such as operators, supervisors, engineers, and administrators.
- Navigate to Configuration → Users.
- On the Roles tab, create one custom role with Role Name
Scheduler.
- Grant each role the functions shown in the table.
| Role | Configure Security | Configure Assets | Configure Items | Operate Assets | Edit Operations | Schedule Shifts | Schedule Operations | Configure Lots | Configure Quality | Enter Checks | Approve Checks |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Administrator | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Operator | ✓ | ✓ | ✓ | ||||||||
| Scheduler | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |||||
| Supervisor | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
- On the Users tab, create the following users. A first and last name is required for each user.
| User | First Name | Last Name | Password |
|---|---|---|---|
| johnDoe | John | Doe | xxYYzz12345! |
| marcoDiaz | Marco | Diaz | xxYYzz12345! |
| hanaKim | Hana | Kim | xxYYzz12345! |
You don't have to use these passwords, just remember that Ignition 8.3 requires complex passwords. You'll want to make a note of your passwords.
For each assignment in the table below:
- Double-click the user in the table and select the role tab.
- Select the asset or assets where the role applies.
- Save the configuration.
| User | Role | Assets |
|---|---|---|
| johnDoe | Operator | Finishing |
| marcoDiaz | Operator | Philadelphia |
| hanaKim | Scheduler | Philadelphia |
Because role assignments are scoped to assets, John Doe can only operate Manual Pack 1, while Marco Diaz can operate every asset at the Philadelphia site.
Hana Kim can schedule across all assets at the Philadelphia site.
Copy this script into the Ignition Designer Script Console (Tools → Script Console) and run it. It checks that the Scheduler role exists, that each role has the functions in the table, that each user exists with the right name, and that each user has the right role on the right asset (and no wider). Each check prints PASS or FAIL with what to fix. It doesn't change anything.
Show the check script
# Kanoa Ops Training - check "Managing Users"
#
# Run in the Ignition Designer Script Console (Tools > Script Console), in the
# project that inherits KANOA_SCRIPTS. It only reads; it changes nothing.
# Every check prints PASS or FAIL with what to fix, then a summary.
FUNCTIONS = ['Configure Security', 'Configure Assets', 'Configure Items', 'Operate Assets', 'Edit Operations',
'Schedule Shifts', 'Schedule Operations', 'Configure Lots', 'Configure Quality', 'Enter Checks', 'Approve Checks']
ROLES = {
'Administrator': FUNCTIONS,
'Operator': ['Operate Assets', 'Edit Operations', 'Enter Checks'],
'Scheduler': ['Configure Assets', 'Configure Items', 'Operate Assets', 'Edit Operations', 'Schedule Shifts', 'Schedule Operations'],
'Supervisor': ['Configure Security', 'Operate Assets', 'Edit Operations', 'Schedule Shifts', 'Schedule Operations', 'Enter Checks', 'Approve Checks'],
}
SITE = 'CoreForge\\Philadelphia'
USERS = [
# user name, first name, last name, role, asset the role applies to
('johnDoe', 'John', 'Doe', 'Operator', SITE + '\\Finishing'),
('marcoDiaz', 'Marco', 'Diaz', 'Operator', SITE),
('hanaKim', 'Hana', 'Kim', 'Scheduler', SITE),
]
results = []
def check(ok, what, fix=None):
results.append(bool(ok))
if ok:
print 'PASS %s' % what
else:
print 'FAIL %s' % what
if fix:
print ' -> %s' % fix
def field(row, *names):
for n in names:
if n in row and row[n] is not None:
return row[n]
return None
def text(v):
return '' if v is None else unicode(v).strip()
def key(v):
# 'Configure Security', 'configureSecurity' and 'configure_security' all match
return ''.join(ch for ch in text(v).lower() if ch.isalnum())
def norm(path):
return text(path).replace('/', '\\').strip('\\')
def truthy(v):
return str(v).lower() in ('true', '1', 'yes')
def rows(data):
# Kanoa returns a dataset, a list of dictionaries, or None
if data is None:
return []
if hasattr(data, 'getRowCount'):
cols = list(data.getColumnNames())
return [dict((c, data.getValueAt(i, c)) for c in cols) for i in range(data.getRowCount())]
return [dict(r) for r in data]
def showColumns(label, data, *keys):
if data and not any(k in data[0] for k in keys):
print 'NOTE %s has none of %s. Columns: %s' % (label, ', '.join(keys), ', '.join(sorted(data[0].keys())))
print '=' * 70
print 'Kanoa Ops Training - Managing Users check'
print '=' * 70
# 1. Roles and their functions
print '\n-- Roles and functions'
roleNames = dict((key(field(r, 'roleName')), text(field(r, 'roleName'))) for r in rows(system.kanoa.security.getRoles({})))
tracked = dict((key(f), f) for f in FUNCTIONS)
for role, expected in sorted(ROLES.items()):
if key(role) not in roleNames:
check(False, 'Role %s exists' % role, 'In Configuration > Users, on the Roles tab, add a role named %s.' % role)
continue
if role == 'Scheduler':
check(roleNames[key(role)] == role, 'Role %s exists' % role,
"Found '%s'. Rename it to %s." % (roleNames[key(role)], role))
granted = rows(system.kanoa.security.getRoleFunctions({'roleName': roleNames[key(role)]}))
showColumns('getRoleFunctions', granted, 'label', 'functionName')
have = set()
for r in granted:
# some versions list every function with a flag; others list only granted ones
flag = field(r, 'enabled', 'hasFunction', 'granted', 'selected')
if flag is not None and not truthy(flag):
continue
for name in (field(r, 'label'), field(r, 'functionName')):
if key(name) in tracked:
have.add(tracked[key(name)])
missing = [f for f in expected if f not in have]
extra = [f for f in FUNCTIONS if f in have and f not in expected]
check(not missing and not extra, '%s has the right functions' % role,
'On the Roles tab, edit %s.%s%s' % (role,
(' Add: %s.' % ', '.join(missing)) if missing else '',
(' Remove: %s.' % ', '.join(extra)) if extra else ''))
# 2. Users and their role assignments
print '\n-- Users'
for userName, first, last, role, assetPath in USERS:
found = rows(system.kanoa.security.getUsers({'userName': userName}))
found = [u for u in found if key(field(u, 'userName')) in ('', key(userName))]
if not found:
check(False, 'User %s exists' % userName,
'In Configuration > Users, on the Users tab, add %s (%s %s).' % (userName, first, last))
continue
user = found[0]
check(True, 'User %s exists' % userName)
gotName = (text(field(user, 'firstName')), text(field(user, 'lastName')))
check(gotName == (first, last), '%s is named %s %s' % (userName, first, last),
"It's '%s %s'. Edit the user and set the first and last name." % gotName)
assignments = rows(system.kanoa.security.getUserAssetRoles({'userId': field(user, 'userId', 'id')}))
showColumns('getUserAssetRoles', assignments, 'roleName')
where = {}
for a in assignments:
if key(field(a, 'roleName')) == key(role):
where[norm(field(a, 'assetPath', 'assetName'))] = True
asset = assetPath.split('\\')[-1]
ok = assetPath in where or any(p.split('\\')[-1] == asset for p in where)
check(ok, '%s is %s on %s' % (userName, role, asset),
'Double-click %s, open the Roles tab, select %s and give it the %s role.%s'
% (userName, asset, role, (' It currently has %s on: %s.' % (role, ', '.join(sorted(where)))) if where else ''))
wider = [p for p in where if p != assetPath and assetPath.startswith(p + '\\')]
if wider:
check(False, "%s's %s role isn't wider than %s" % (userName, role, asset),
'It also has %s on %s, which covers more than %s. Remove that assignment.' % (role, ', '.join(sorted(wider)), asset))
passed = results.count(True)
print '\n' + '=' * 70
print 'Result: %d of %d checks passed' % (passed, len(results))
if passed == len(results):
print 'All good. Your users and roles are set up.'
else:
print 'Fix the FAIL items above, then run this again.'
print '=' * 70





