Skip to content

Commit 49bcdbc

Browse files
committed
Merge pull request softlayer#715 from camporter/add_ticket_attach_detach_support
Add ability to attach/detach devices to tickets.
2 parents c1779c2 + 59d3614 commit 49bcdbc

8 files changed

Lines changed: 327 additions & 10 deletions

File tree

SoftLayer/CLI/routes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@
188188
('ticket:update', 'SoftLayer.CLI.ticket.update:cli'),
189189
('ticket:subjects', 'SoftLayer.CLI.ticket.subjects:cli'),
190190
('ticket:summary', 'SoftLayer.CLI.ticket.summary:cli'),
191+
('ticket:attach', 'SoftLayer.CLI.ticket.attach:cli'),
192+
('ticket:detach', 'SoftLayer.CLI.ticket.detach:cli'),
191193

192194
('vlan', 'SoftLayer.CLI.vlan'),
193195
('vlan:detail', 'SoftLayer.CLI.vlan.detail:cli'),

SoftLayer/CLI/ticket/attach.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Attach devices to a ticket."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
import SoftLayer
7+
from SoftLayer.CLI import environment
8+
from SoftLayer.CLI import exceptions
9+
from SoftLayer.CLI import helpers
10+
11+
12+
@click.command()
13+
@click.argument('identifier', type=int)
14+
@click.option('--hardware',
15+
'hardware_identifier',
16+
help="The identifier for hardware to attach")
17+
@click.option('--virtual',
18+
'virtual_identifier',
19+
help="The identifier for a virtual server to attach")
20+
@environment.pass_env
21+
def cli(env, identifier, hardware_identifier, virtual_identifier):
22+
"""Attach devices to a ticket."""
23+
ticket_mgr = SoftLayer.TicketManager(env.client)
24+
25+
if hardware_identifier and virtual_identifier:
26+
raise exceptions.ArgumentError(
27+
"Cannot attach hardware and a virtual server at the same time")
28+
elif hardware_identifier:
29+
hardware_mgr = SoftLayer.HardwareManager(env.client)
30+
hardware_id = helpers.resolve_id(hardware_mgr.resolve_ids,
31+
hardware_identifier,
32+
'hardware')
33+
ticket_mgr.attach_hardware(identifier, hardware_id)
34+
elif virtual_identifier:
35+
vs_mgr = SoftLayer.VSManager(env.client)
36+
vs_id = helpers.resolve_id(vs_mgr.resolve_ids,
37+
virtual_identifier,
38+
'VS')
39+
ticket_mgr.attach_virtual_server(identifier, vs_id)
40+
else:
41+
raise exceptions.ArgumentError(
42+
"Must have a hardware or virtual server identifier to attach")

SoftLayer/CLI/ticket/create.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,49 @@
55

66
import SoftLayer
77
from SoftLayer.CLI import environment
8+
from SoftLayer.CLI import helpers
89
from SoftLayer.CLI import ticket
910

1011

1112
@click.command()
1213
@click.option('--title', required=True, help="The title of the ticket")
1314
@click.option('--subject-id',
15+
type=int,
1416
required=True,
1517
help="""The subject id to use for the ticket,
1618
issue 'slcli ticket subjects' to get the list""")
1719
@click.option('--body', help="The ticket body")
20+
@click.option('--hardware',
21+
'hardware_identifier',
22+
help="The identifier for hardware to attach")
23+
@click.option('--virtual',
24+
'virtual_identifier',
25+
help="The identifier for a virtual server to attach")
1826
@environment.pass_env
19-
def cli(env, title, subject_id, body):
27+
def cli(env, title, subject_id, body, hardware_identifier, virtual_identifier):
2028
"""Create a support ticket."""
21-
mgr = SoftLayer.TicketManager(env.client)
29+
ticket_mgr = SoftLayer.TicketManager(env.client)
2230

2331
if body is None:
2432
body = click.edit('\n\n' + ticket.TEMPLATE_MSG)
2533

26-
created_ticket = mgr.create_ticket(title=title,
27-
body=body,
28-
subject=subject_id)
29-
env.fout(ticket.get_ticket_results(mgr, created_ticket['id']))
34+
created_ticket = ticket_mgr.create_ticket(
35+
title=title,
36+
body=body,
37+
subject=subject_id)
38+
39+
if hardware_identifier:
40+
hardware_mgr = SoftLayer.HardwareManager(env.client)
41+
hardware_id = helpers.resolve_id(hardware_mgr.resolve_ids,
42+
hardware_identifier,
43+
'hardware')
44+
ticket_mgr.attach_hardware(created_ticket['id'], hardware_id)
45+
46+
if virtual_identifier:
47+
vs_mgr = SoftLayer.VSManager(env.client)
48+
vs_id = helpers.resolve_id(vs_mgr.resolve_ids,
49+
virtual_identifier,
50+
'VS')
51+
ticket_mgr.attach_virtual_server(created_ticket['id'], vs_id)
52+
53+
env.fout(ticket.get_ticket_results(ticket_mgr, created_ticket['id']))

SoftLayer/CLI/ticket/detach.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Detach devices from a ticket."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
import SoftLayer
7+
from SoftLayer.CLI import environment
8+
from SoftLayer.CLI import exceptions
9+
from SoftLayer.CLI import helpers
10+
11+
12+
@click.command()
13+
@click.argument('identifier', type=int)
14+
@click.option('--hardware',
15+
'hardware_identifier',
16+
help="The identifier for hardware to detach")
17+
@click.option('--virtual',
18+
'virtual_identifier',
19+
help="The identifier for a virtual server to detach")
20+
@environment.pass_env
21+
def cli(env, identifier, hardware_identifier, virtual_identifier):
22+
"""Detach devices from a ticket."""
23+
ticket_mgr = SoftLayer.TicketManager(env.client)
24+
25+
if hardware_identifier and virtual_identifier:
26+
raise exceptions.ArgumentError(
27+
"Cannot detach hardware and a virtual server at the same time")
28+
elif hardware_identifier:
29+
hardware_mgr = SoftLayer.HardwareManager(env.client)
30+
hardware_id = helpers.resolve_id(hardware_mgr.resolve_ids,
31+
hardware_identifier,
32+
'hardware')
33+
ticket_mgr.detach_hardware(identifier, hardware_id)
34+
elif virtual_identifier:
35+
vs_mgr = SoftLayer.VSManager(env.client)
36+
vs_id = helpers.resolve_id(vs_mgr.resolve_ids,
37+
virtual_identifier,
38+
'VS')
39+
ticket_mgr.detach_virtual_server(identifier, vs_id)
40+
else:
41+
raise exceptions.ArgumentError(
42+
"Must have a hardware or virtual server identifier to detach")

SoftLayer/fixtures/SoftLayer_Ticket.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,20 @@
3333
}
3434
edit = True
3535
addUpdate = {}
36+
37+
addAttachedHardware = {
38+
"id": 123,
39+
"createDate": "2013-08-01T14:14:04-07:00",
40+
"hardwareId": 1,
41+
"ticketId": 100
42+
}
43+
44+
addAttachedVirtualGuest = {
45+
"id": 123,
46+
"createDate": "2013-08-01T14:14:04-07:00",
47+
"virtualGuestId": 1,
48+
"ticketId": 100
49+
}
50+
51+
removeAttachedHardware = True
52+
removeAttachedVirtualGuest = True

SoftLayer/managers/ticket.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ def list_tickets(self, open_status=True, closed_status=True):
3939
return self.client.call('Account', call, mask=mask)
4040

4141
def list_subjects(self):
42-
"""List all tickets."""
42+
"""List all ticket subjects."""
4343
return self.client['Ticket_Subject'].getAllObjects()
4444

4545
def get_ticket(self, ticket_id):
4646
"""Get details about a ticket.
4747
48-
:param integer id: the ticket ID
48+
:param integer ticket_id: the ticket ID
4949
:returns: A dictionary containing a large amount of information about
5050
the specified ticket.
5151
@@ -79,3 +79,39 @@ def update_ticket(self, ticket_id=None, body=None):
7979
:param string body: entry to update in the ticket
8080
"""
8181
return self.ticket.addUpdate({'entry': body}, id=ticket_id)
82+
83+
def attach_hardware(self, ticket_id=None, hardware_id=None):
84+
"""Attach hardware to a ticket.
85+
86+
:param integer ticket_id: the id of the ticket to attach to
87+
:param integer hardware_id: the id of the hardware to attach
88+
:returns The new ticket attachment
89+
"""
90+
return self.ticket.addAttachedHardware(hardware_id, id=ticket_id)
91+
92+
def attach_virtual_server(self, ticket_id=None, virtual_id=None):
93+
"""Attach a virtual server to a ticket.
94+
95+
:param integer ticket_id: the id of the ticket to attach to
96+
:param integer virtual_id: the id of the virtual server to attach
97+
:returns The new ticket attachment
98+
"""
99+
return self.ticket.addAttachedVirtualGuest(virtual_id, id=ticket_id)
100+
101+
def detach_hardware(self, ticket_id=None, hardware_id=None):
102+
"""Detach hardware from a ticket.
103+
104+
:param ticket_id: the id of the ticket to detach from
105+
:param hardware_id: the id of the hardware to detach
106+
:return: Whether the detachment was successful
107+
"""
108+
return self.ticket.removeAttachedHardware(hardware_id, id=ticket_id)
109+
110+
def detach_virtual_server(self, ticket_id=None, virtual_id=None):
111+
"""Detach a virtual server from a ticket.
112+
113+
:param ticket_id: the id of the ticket to detach from
114+
:param virtual_id: the id of the virtual server to detach
115+
:return: Whether the detachment was successful
116+
"""
117+
return self.ticket.removeAttachedVirtualGuest(virtual_id, id=ticket_id)

tests/CLI/modules/ticket_tests.py

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
55
:license: MIT, see LICENSE for more details.
66
"""
7-
from SoftLayer import testing
8-
97
import json
8+
import mock
9+
10+
from SoftLayer.CLI import exceptions
11+
from SoftLayer import testing
1012

1113

1214
class TicketTests(testing.TestCase):
@@ -38,3 +40,130 @@ def test_detail(self):
3840
}
3941
self.assertEqual(result.exit_code, 0)
4042
self.assertEqual(json.loads(result.output), expected)
43+
44+
def test_create(self):
45+
result = self.run_command(['ticket', 'create', '--title=Test',
46+
'--subject-id=1000',
47+
'--body=ticket body'])
48+
49+
self.assertEqual(result.exit_code, 0)
50+
51+
args = ({'subjectId': 1000,
52+
'contents': 'ticket body',
53+
'assignedUserId': 12345,
54+
'title': 'Test'}, 'ticket body')
55+
56+
self.assert_called_with('SoftLayer_Ticket', 'createStandardTicket',
57+
args=args)
58+
59+
def test_create_and_attach(self):
60+
result = self.run_command(['ticket', 'create', '--title=Test',
61+
'--subject-id=1000',
62+
'--body=ticket body',
63+
'--hardware=234',
64+
'--virtual=567'])
65+
66+
self.assertEqual(result.exit_code, 0)
67+
68+
args = ({'subjectId': 1000,
69+
'contents': 'ticket body',
70+
'assignedUserId': 12345,
71+
'title': 'Test'}, 'ticket body')
72+
73+
self.assert_called_with('SoftLayer_Ticket', 'createStandardTicket',
74+
args=args)
75+
self.assert_called_with('SoftLayer_Ticket', 'addAttachedHardware',
76+
args=(234,),
77+
identifier=100)
78+
self.assert_called_with('SoftLayer_Ticket', 'addAttachedVirtualGuest',
79+
args=(567,),
80+
identifier=100)
81+
82+
@mock.patch('click.edit')
83+
def test_create_no_body(self, edit_mock):
84+
edit_mock.return_value = 'ticket body'
85+
result = self.run_command(['ticket', 'create', '--title=Test',
86+
'--subject-id=1000'])
87+
self.assertEqual(result.exit_code, 0)
88+
89+
args = ({'subjectId': 1000,
90+
'contents': 'ticket body',
91+
'assignedUserId': 12345,
92+
'title': 'Test'}, 'ticket body')
93+
94+
self.assert_called_with('SoftLayer_Ticket', 'createStandardTicket',
95+
args=args)
96+
97+
def test_subjects(self):
98+
list_expected_ids = [1001, 1002, 1003, 1004, 1005]
99+
result = self.run_command(['ticket', 'subjects'])
100+
101+
self.assertEqual(result.exit_code, 0)
102+
results = json.loads(result.output)
103+
for result in results:
104+
self.assertIn(result['id'], list_expected_ids)
105+
106+
def test_attach_no_identifier(self):
107+
result = self.run_command(['ticket', 'attach', '1'])
108+
109+
self.assertEqual(result.exit_code, 2)
110+
self.assertIsInstance(result.exception, exceptions.ArgumentError)
111+
112+
def test_attach_two_identifiers(self):
113+
result = self.run_command(['ticket',
114+
'attach',
115+
'1',
116+
'--hardware=100',
117+
'--virtual=100'])
118+
119+
self.assertEqual(result.exit_code, 2)
120+
self.assertIsInstance(result.exception, exceptions.ArgumentError)
121+
122+
def test_ticket_attach_hardware(self):
123+
result = self.run_command(['ticket', 'attach', '1', '--hardware=100'])
124+
125+
self.assertEqual(result.exit_code, 0)
126+
self.assert_called_with('SoftLayer_Ticket', 'addAttachedHardware',
127+
args=(100,),
128+
identifier=1)
129+
130+
def test_ticket_attach_virtual_server(self):
131+
result = self.run_command(['ticket', 'attach', '1', '--virtual=100'])
132+
133+
self.assertEqual(result.exit_code, 0)
134+
self.assert_called_with('SoftLayer_Ticket', 'addAttachedVirtualGuest',
135+
args=(100,),
136+
identifier=1)
137+
138+
def test_detach_no_identifier(self):
139+
result = self.run_command(['ticket', 'detach', '1'])
140+
141+
self.assertEqual(result.exit_code, 2)
142+
self.assertIsInstance(result.exception, exceptions.ArgumentError)
143+
144+
def test_detach_two_identifiers(self):
145+
result = self.run_command(['ticket',
146+
'detach',
147+
'1',
148+
'--hardware=100',
149+
'--virtual=100'])
150+
self.assertEqual(result.exit_code, 2)
151+
self.assertIsInstance(result.exception, exceptions.ArgumentError)
152+
153+
def test_ticket_detach_hardware(self):
154+
result = self.run_command(['ticket', 'detach', '1', '--hardware=100'])
155+
156+
self.assertEqual(result.exit_code, 0)
157+
self.assert_called_with('SoftLayer_Ticket',
158+
'removeAttachedHardware',
159+
args=(100,),
160+
identifier=1)
161+
162+
def test_ticket_detach_virtual_server(self):
163+
result = self.run_command(['ticket', 'detach', '1', '--virtual=100'])
164+
165+
self.assertEqual(result.exit_code, 0)
166+
self.assert_called_with('SoftLayer_Ticket',
167+
'removeAttachedVirtualGuest',
168+
args=(100,),
169+
identifier=1)

0 commit comments

Comments
 (0)