Skip to content

Commit 5254920

Browse files
finishing off user detail features, added some docs
1 parent a52f106 commit 5254920

File tree

8 files changed

+220
-16
lines changed

8 files changed

+220
-16
lines changed

SoftLayer/CLI/formatting.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import os
1313

1414
import click
15-
import prettytable
15+
from prettytable import prettytable
1616

1717
from SoftLayer.CLI import exceptions
1818
from SoftLayer import utils
@@ -255,7 +255,7 @@ class Table(object):
255255
256256
:param list columns: a list of column names
257257
"""
258-
def __init__(self, columns):
258+
def __init__(self, columns, title=None):
259259
duplicated_cols = [col for col, count
260260
in collections.Counter(columns).items()
261261
if count > 1]
@@ -267,6 +267,7 @@ def __init__(self, columns):
267267
self.rows = []
268268
self.align = {}
269269
self.sortby = None
270+
self.title = title
270271

271272
def add_row(self, row):
272273
"""Add a row to the table.
@@ -287,6 +288,7 @@ def to_python(self):
287288
def prettytable(self):
288289
"""Returns a new prettytable instance."""
289290
table = prettytable.PrettyTable(self.columns)
291+
290292
if self.sortby:
291293
if self.sortby in self.columns:
292294
table.sortby = self.sortby
@@ -296,6 +298,8 @@ def prettytable(self):
296298
for a_col, alignment in self.align.items():
297299
table.align[a_col] = alignment
298300

301+
if self.title:
302+
table.title = self.title
299303
# Adding rows
300304
for row in self.rows:
301305
table.add_row(row)

SoftLayer/CLI/user/detail.py

Lines changed: 87 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,22 @@
1111

1212
from pprint import pprint as pp
1313

14-
15-
16-
17-
1814
@click.command()
1915
@click.argument('identifier')
20-
@click.option('--keys', is_flag=True, default=False)
16+
@click.option('--keys', is_flag=True, default=False,
17+
help="Show the users API key.")
18+
@click.option('--permissions', '-p', is_flag=True, default=False,
19+
help="Display permissions assigned to this user. Master users will show no permissions")
20+
@click.option('--hardware', '-h', is_flag=True, default=False,
21+
help="Display hardware this user has access to.")
22+
@click.option('--virtual', '-v', is_flag=True, default=False,
23+
help="Display virtual guests this user has access to.")
24+
@click.option('--logins', '-l', is_flag=True, default=False,
25+
help="Show login history of this user for the last 30 days")
26+
@click.option('--events', '-e', is_flag=True, default=False,
27+
help="Show audit log for this user.")
2128
@environment.pass_env
22-
def cli(env, identifier, keys):
29+
def cli(env, identifier, keys, permissions, hardware, virtual, logins, events):
2330
"""User details."""
2431

2532
mgr = SoftLayer.UserManager(env.client)
@@ -30,6 +37,27 @@ def cli(env, identifier, keys):
3037
user = mgr.get_user(user_id, object_mask)
3138
env.fout(basic_info(user, keys))
3239

40+
if permissions:
41+
perms = mgr.get_user_permissions(user_id)
42+
env.fout(print_permissions(perms))
43+
if hardware:
44+
mask = "id, hardware, dedicatedHosts"
45+
access = mgr.get_user(user_id, mask)
46+
env.fout(print_dedicated_access(access['dedicatedHosts']))
47+
env.fout(print_access(access['hardware'], 'Hardware'))
48+
if virtual:
49+
mask = "id, virtualGuests"
50+
access = mgr.get_user(user_id, mask)
51+
env.fout(print_access(access['virtualGuests'], 'Virtual Guests'))
52+
if logins:
53+
mask = "id, unsuccessfulLogins, successfulLogins"
54+
login_log = mgr.get_logins(user_id)
55+
env.fout(print_logins(login_log))
56+
if events:
57+
event_log = mgr.get_events(user_id)
58+
env.fout(print_events(event_log))
59+
60+
3361

3462
def basic_info(user, keys):
3563
"""Prints a table of basic user information"""
@@ -69,3 +97,56 @@ def basic_info(user, keys):
6997

7098
return table
7199

100+
def print_permissions(permissions):
101+
"""Prints out a users permissions"""
102+
103+
table = formatting.Table(['keyName', 'Description'])
104+
for perm in permissions:
105+
table.add_row([perm['keyName'], perm['name']])
106+
return table
107+
108+
def print_access(access, title):
109+
"""Prints out the hardware or virtual guests a user can access"""
110+
111+
columns = ['id', 'hostname', 'Primary Public IP', 'Primary Private IP', 'Created']
112+
table = formatting.Table(columns, title)
113+
114+
for host in access:
115+
host_id = host.get('id')
116+
host_fqdn = host.get('fullyQualifiedDomainName', '-')
117+
host_primary = host.get('primaryIpAddress')
118+
host_private = host.get('primaryBackendIpAddress')
119+
host_created = host.get('provisionDate')
120+
table.add_row([host_id, host_fqdn, host_primary, host_private, host_created])
121+
return table
122+
123+
def print_dedicated_access(access):
124+
"""Prints out the dedicated hosts a user can access"""
125+
126+
table = formatting.Table(['id', 'Name', 'Cpus', 'Memory', 'Disk', 'Created'], 'Dedicated Access')
127+
for host in access:
128+
host_id = host.get('id')
129+
host_fqdn = host.get('name')
130+
host_cpu = host.get('cpuCount')
131+
host_mem = host.get('memoryCapacity')
132+
host_disk = host.get('diskCapacity')
133+
host_created = host.get('createDate')
134+
table.add_row([host_id, host_fqdn, host_cpu, host_mem, host_disk, host_created])
135+
return table
136+
137+
def print_logins(logins):
138+
"""Prints out the login history for a user"""
139+
table = formatting.Table(['Date', 'IP Address', 'Successufl Login?'])
140+
for login in logins:
141+
table.add_row([login.get('createDate'), login.get('ipAddress'), login.get('successFlag')])
142+
return table
143+
144+
def print_events(events):
145+
"""Prints out the event log for a user"""
146+
columns = ['Date', 'Type', 'IP Address', 'label', 'username']
147+
table = formatting.Table(columns)
148+
for event in events:
149+
table.add_row([event.get('eventCreateDate'), event.get('eventName'),
150+
event.get('ipAddress'), event.get('label'), event.get('username')])
151+
return table
152+

SoftLayer/CLI/user/edit_permissions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
help="Permission keyName to set, multiple instances allowed.")
2121
@environment.pass_env
2222
def cli(env, identifier, enable, permission):
23-
"""Enable or Disable specific permissions for a user"""
23+
"""Enable or Disable specific permissions."""
2424

2525
mgr = SoftLayer.UserManager(env.client)
2626
user_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'username')

SoftLayer/CLI/user/list.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""List images."""
1+
"""List Users."""
22
# :license: MIT, see LICENSE for more details.
33

44
import click
@@ -29,21 +29,19 @@
2929
'virtualGuestCount'
3030
]
3131
@click.command()
32-
@click.option('--name', default=None, help='Filter on user name')
32+
@click.option('--name', default=None, help='Filter on username')
3333
@click.option('--columns',
3434
callback=column_helper.get_formatter(COLUMNS),
3535
help='Columns to display. [options: %s]' % ', '.join(column.name for column in COLUMNS),
3636
default=','.join(DEFAULT_COLUMNS),
3737
show_default=True)
3838
@environment.pass_env
3939
def cli(env, name, columns):
40-
"""List images."""
40+
"""List Users."""
4141

4242
mgr = SoftLayer.UserManager(env.client)
4343
users = mgr.list_users()
4444

45-
46-
# pp(users)
4745
table = formatting.Table(columns.columns)
4846
for user in users:
4947
table.add_row([value or formatting.blank()

SoftLayer/CLI/user/permissions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
@click.argument('identifier')
1212
@environment.pass_env
1313
def cli(env, identifier):
14-
"""User Permissions."""
14+
"""User Permissions. TODO change to list all permissions, and which users have them"""
1515

1616
mgr = SoftLayer.UserManager(env.client)
1717
user_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'username')

SoftLayer/managers/user.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from SoftLayer import exceptions
99
from SoftLayer import utils
1010

11+
import datetime
1112
from operator import itemgetter
1213

1314

@@ -66,6 +67,60 @@ def remove_permissions(self, user_id, permissions):
6667
pretty_permissions = format_permission_object(permissions)
6768
return self.userService.removeBulkPortalPermission(pretty_permissions, id=user_id)
6869

70+
def get_user_permissions(self, user_id):
71+
"""Returns a sorted list of a users permissions"""
72+
permissions = self.userService.getPermissions(id=user_id)
73+
return sorted(permissions, key=itemgetter('keyName'))
74+
75+
def get_logins(self, user_id, start_date=None):
76+
"""Gets the login history for a user, default start_date is 30 days ago
77+
78+
:param int id: User id to get
79+
:param string start_date: "%m/%d/%Y %H:%M:%s" formatted string.
80+
:returns: list https://softlayer.github.io/reference/datatypes/SoftLayer_User_Customer_Access_Authentication/
81+
Example::
82+
get_logins(123, '04/08/2018 0:0:0')
83+
"""
84+
85+
if start_date is None:
86+
date_object = datetime.date.today() - datetime.timedelta(days=30)
87+
start_date = date_object.strftime("%m/%d/%Y 0:0:0")
88+
89+
date_filter = {
90+
'loginAttempts': {
91+
'createDate': {
92+
'operation': 'greaterThanDate',
93+
'options': [{'name': 'date', 'value': [start_date]}]
94+
}
95+
}
96+
}
97+
login_log = self.userService.getLoginAttempts(id=user_id, filter=date_filter)
98+
return login_log
99+
100+
def get_events(self, user_id, start_date=None):
101+
"""Gets the event log for a specific user, default start_date is 30 days ago
102+
103+
:param int id: User id to view
104+
:param string start_date: "%Y-%m-%dT%H:%M:%s.0000-06:00" formatted string. Anything else wont work
105+
:returns: https://softlayer.github.io/reference/datatypes/SoftLayer_Event_Log/
106+
"""
107+
108+
if start_date is None:
109+
date_object = datetime.date.today() - datetime.timedelta(days=30)
110+
start_date = date_object.strftime("%Y-%m-%dT00:00:00.0000-06:00")
111+
112+
object_filter = {
113+
'userId': {
114+
'operation': user_id
115+
},
116+
'eventCreateDate': {
117+
'operation': 'greaterThanDate',
118+
'options': [{'name': 'date', 'value': [start_date]}]
119+
}
120+
}
121+
122+
return self.client.call('Event_Log', 'getAllObjects', filter=object_filter)
123+
69124
def _get_id_from_username(self, username):
70125
_mask = "mask[id, username]"
71126
_filter = {'users' : {'username': utils.query_filter(username)}}

docs/cli/users.rst

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
.. _cli_user:
2+
3+
Users
4+
=============
5+
Version 5.6.0 introduces the ability to interact with user accounts from the cli.
6+
7+
.. _cli_user_list:
8+
9+
user list
10+
----------
11+
This command will list all Active users on the account that your user has access to view.
12+
There is the option to also filter by username
13+
14+
15+
.. _cli_user_detail:
16+
17+
user detail <user>
18+
-------------------
19+
Gives a variety of details about a specific user. <user> can be a user id, or username. Will always print a basic set of information about the user, but there are a few extra flags to pull in more detailed information.
20+
21+
user detail <user> -p, --permissions
22+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23+
Will list the permissions the user has. To see a list of all possible permissions, or to change a users permissions, see :ref:`cli_user_permissions`
24+
25+
user detail <user> -h, --hardware
26+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27+
Will list the Hardware and Dedicated Hosts the user is able to access.
28+
29+
30+
user detail <user> -v, --virtual
31+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32+
Will list the Virtual Guests the user has access to.
33+
34+
user detail <user> -l, --logins
35+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
36+
Show login history of this user for the last 30 days. IBMId Users will show logins properly, but may not show failed logins.
37+
38+
user detail <user> -e, --events
39+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40+
Shows things that are logged in the Event_Log service. Logins, reboots, reloads, and other such actions will show up here.
41+
42+
.. _cli_user_permissions:
43+
44+
user permissions
45+
----------------
46+
47+
Will list off all permission keyNames, along with wich usernames have that permissions.
48+
49+
user permissions <user>
50+
^^^^^^^^^^^^^^^^^^^^^^^
51+
Will list off all permission keyNames, along with which are assigned to that specific user.
52+
53+
.. _cli_user_permissions_edit:
54+
55+
user edit-permissions
56+
---------------------
57+
Enable or Disable specific permissions. It is possible to set multiple permissions in one command as well.
58+
59+
::
60+
61+
$ slcli user edit-permissions USERID --enable -p TICKET_EDIT -p TICKET_ADD -p TICKET_SEARCH
62+
63+
Will enable TICKET_EDIT, TICKET_ADD, and TICKET_SEARCH permissions for the USERID
64+
65+
66+

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
},
3232
install_requires=[
3333
'six >= 1.7.0',
34-
'prettytable >= 0.7.0',
34+
'ptable >= 0.9.2',
3535
'click >= 5',
3636
'requests >= 2.18.4',
3737
'prompt_toolkit >= 0.53',

0 commit comments

Comments
 (0)