Skip to content

Commit b4cff42

Browse files
#1230 added a taggable command, to list all things that are able to be tagged
1 parent 64bce81 commit b4cff42

File tree

6 files changed

+172
-38
lines changed

6 files changed

+172
-38
lines changed

SoftLayer/CLI/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@
295295
('tags:set', 'SoftLayer.CLI.tags.set:cli'),
296296
('tags:details', 'SoftLayer.CLI.tags.details:cli'),
297297
('tags:delete', 'SoftLayer.CLI.tags.delete:cli'),
298+
('tags:taggable', 'SoftLayer.CLI.tags.taggable:cli'),
298299

299300
('ticket', 'SoftLayer.CLI.ticket'),
300301
('ticket:create', 'SoftLayer.CLI.ticket.create:cli'),

SoftLayer/CLI/tags/delete.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
1-
"""List Tags."""
1+
"""Delete Tags."""
22
# :license: MIT, see LICENSE for more details.
33

44
import click
55

6-
from SoftLayer.exceptions import SoftLayerAPIError
6+
from SoftLayer.CLI.exceptions import ArgumentError
77
from SoftLayer.managers.tags import TagManager
88
from SoftLayer.CLI import environment
9-
from SoftLayer.CLI import formatting
10-
from SoftLayer import utils
11-
12-
# pylint: disable=unnecessary-lambda
13-
14-
from pprint import pprint as pp
159

1610

1711
@click.command()
18-
@click.option('-id', required=False, show_default=False, type=int, help='identifier')
19-
@click.option('--name', required=False, default=False, type=str, show_default=False, help='tag name')
12+
@click.argument('identifier')
13+
@click.option('--name', required=False, default=False, is_flag=True, show_default=False,
14+
help='Assume identifier is a tag name. Useful if your tag name is a number.')
2015
@environment.pass_env
21-
def cli(env, id, name):
22-
"""delete Tag."""
16+
def cli(env, identifier, name):
17+
"""Delete a Tag. Tag names that contain spaces need to be encased in quotes"""
2318

2419
tag_manager = TagManager(env.client)
25-
26-
if not name and id is not None:
27-
tag_name = tag_manager.get_tag(id)
28-
tag_manager.delete_tag(tag_name['name'])
29-
if name and id is None:
30-
tag_manager.delete_tag(name)
20+
tag_name = identifier
21+
# If the identifier is a int, and user didn't tell us it was a name.
22+
if str.isdigit(identifier) and not name:
23+
tag = tag_manager.get_tag(tag_id)
24+
tag_name = tag.get('name', None)
25+
26+
27+
result = tag_manager.delete_tag(tag_name)
28+
if result:
29+
click.secho("Tag {} has been removed".format(tag_name), fg='green')
30+
else:
31+
click.secho("Failed to remove tag {}".format(tag_name), fg='red')

SoftLayer/CLI/tags/details.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@
1010

1111
@click.command()
1212
@click.argument('identifier')
13+
@click.option('--name', required=False, default=False, is_flag=True, show_default=False,
14+
help='Assume identifier is a tag name. Useful if your tag name is a number.')
1315
@environment.pass_env
14-
def cli(env, identifier):
15-
"""Get details for a Tag."""
16+
def cli(env, identifier, name):
17+
"""Get details for a Tag. Identifier can be either a name or tag-id"""
1618

1719
tag_manager = TagManager(env.client)
1820

19-
if str.isdigit(identifier):
21+
# If the identifier is a int, and user didn't tell us it was a name.
22+
if str.isdigit(identifier) and not name:
2023
tags = [tag_manager.get_tag(identifier)]
2124
else:
2225
tags = tag_manager.get_tag_by_name(identifier)

SoftLayer/CLI/tags/set.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99

1010
@click.command()
11-
@click.option('--tags', '-t', type=click.STRING, required=True, help='List of tags e.g. "tag1, tag2"')
12-
@click.option('--key-name', '-k', type=click.STRING, required=True, help="Key name of a tag type e.g. GUEST, HARDWARE")
11+
@click.option('--tags', '-t', type=click.STRING, required=True,
12+
help='Comma seperated list of tags, enclosed in quotes. "tag1, tag2"')
13+
@click.option('--key-name', '-k', type=click.STRING, required=True,
14+
help="Key name of a tag type e.g. GUEST, HARDWARE. See slcli tags taggable output.")
1315
@click.option('--resource-id', '-r', type=click.INT, required=True, help="ID of the object being tagged")
1416
@environment.pass_env
1517
def cli(env, tags, key_name, resource_id):

SoftLayer/CLI/tags/taggable.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""List everything that could be tagged."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
from SoftLayer.CLI.exceptions import ArgumentError
7+
from SoftLayer.CLI import formatting
8+
from SoftLayer.managers.tags import TagManager
9+
from SoftLayer.CLI import environment
10+
11+
from pprint import pprint as pp
12+
@click.command()
13+
@environment.pass_env
14+
def cli(env):
15+
"""List everything that could be tagged."""
16+
17+
tag_manager = TagManager(env.client)
18+
tag_types = tag_manager.get_all_tag_types()
19+
for tag_type in tag_types:
20+
title = "{} ({})".format(tag_type['description'], tag_type['keyName'])
21+
table = formatting.Table(['Id', 'Name'], title=title)
22+
resources = tag_manager.taggable_by_type(tag_type['keyName'])
23+
for resource in resources:
24+
table.add_row([
25+
resource['resource']['id'],
26+
get_resource_name(resource['resource'], tag_type['keyName'])
27+
])
28+
env.fout(table)
29+
30+
31+
def get_resource_name(resource, tag_type):
32+
"""Returns a string that names a resource"""
33+
if tag_type == 'NETWORK_VLAN_FIREWALL':
34+
return resource.get('primaryIpAddress')
35+
elif tag_type == 'NETWORK_VLAN':
36+
return "{} ({})".format(resource.get('vlanNumber'), resource.get('name'))
37+
elif tag_type == 'IMAGE_TEMPLATE' or tag_type == 'APPLICATION_DELIVERY_CONTROLLER':
38+
return resource.get('name')
39+
elif tag_type == 'TICKET':
40+
return resource.get('subjet')
41+
elif tag_type == 'NETWORK_SUBNET':
42+
return resource.get('networkIdentifier')
43+
else:
44+
return resource.get('fullyQualifiedDomainName')

SoftLayer/managers/tags.py

Lines changed: 98 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -96,34 +96,117 @@ def reference_lookup(self, resource_table_id, tag_type):
9696
|Vlan |NETWORK_VLAN|
9797
|Dedicated Host |DEDICATED_HOST|
9898
"""
99+
service = self.type_to_service(tag_type)
100+
if service is None:
101+
raise SoftLayerAPIError(404, "Unable to lookup {} types".format(tag_type))
102+
# return {}
103+
return self.client.call(service, 'getObject', id=resource_table_id)
104+
105+
def delete_tag(self, name):
106+
"""Calls SoftLayer_Tag::deleteTag
107+
108+
:param string name: tag name to delete
109+
"""
110+
return self.client.call('SoftLayer_Tag', 'deleteTag', name)
111+
112+
def set_tags(self, tags, key_name, resource_id):
113+
"""Calls SoftLayer_Tag::setTags()
114+
115+
:param string tags: List of tags.
116+
:param string key_name: Key name of a tag type.
117+
:param int resource_id: ID of the object being tagged.
118+
"""
119+
return self.client.call('SoftLayer_Tag', 'setTags', tags, key_name, resource_id)
99120

121+
def get_all_tag_types(self):
122+
"""Calls SoftLayer_Tag::getAllTagTypes()"""
123+
types = self.client.call('SoftLayer_Tag', 'getAllTagTypes')
124+
useable_types = []
125+
for tag_type in types:
126+
service = self.type_to_service(tag_type['keyName'])
127+
# Mostly just to remove the types that are not user taggable.
128+
if service is not None:
129+
temp_type = tag_type
130+
temp_type['service'] = service
131+
useable_types.append(temp_type)
132+
return useable_types
133+
134+
def taggable_by_type(self, tag_type):
135+
"""Returns a list of resources that can be tagged, that are of the given type
136+
137+
:param string tag_type: Key name of a tag type. See SoftLayer_Tag::getAllTagTypes
138+
"""
139+
service = self.type_to_service(tag_type)
140+
search_term = "_objectType:SoftLayer_{}".format(service)
141+
if tag_type == 'TICKET':
142+
search_term = "{} status.name: open".format(search_term)
143+
elif tag_type == 'IMAGE_TEMPLATE':
144+
mask = "mask[id,accountId,name,globalIdentifier,parentId,publicFlag,flexImageFlag,imageType]"
145+
resources = self.client.call('SoftLayer_Account', 'getPrivateBlockDeviceTemplateGroups',
146+
mask=mask, iter=True)
147+
to_return = []
148+
# Fake search result output
149+
for resource in resources:
150+
to_return.append({'resourceType':service, 'resource':resource})
151+
return to_return
152+
elif tag_type == 'NETWORK_SUBNET':
153+
resources = self.client.call('SoftLayer_Account', 'getSubnets', iter=True)
154+
to_return = []
155+
# Fake search result output
156+
for resource in resources:
157+
to_return.append({'resourceType':service, 'resource':resource})
158+
return to_return
159+
resources = self.client.call('SoftLayer_Search', 'advancedSearch', search_term, iter=True)
160+
return resources
161+
162+
@staticmethod
163+
def type_to_service(tag_type):
164+
"""Returns the SoftLayer service for the given tag_type"""
165+
service = None
100166
if tag_type in ['ACCOUNT_DOCUMENT', 'CONTRACT']:
101-
raise SoftLayerAPIError(404, "Unable to lookup {} types".format(tag_type))
167+
return None
102168

103169
if tag_type == 'APPLICATION_DELIVERY_CONTROLLER':
104170
service = 'Network_Application_Delivery_Controller'
105171
elif tag_type == 'GUEST':
106172
service = 'Virtual_Guest'
107173
elif tag_type == 'DEDICATED_HOST':
108174
service = 'Virtual_DedicatedHost'
175+
elif tag_type == 'IMAGE_TEMPLATE':
176+
service = 'Virtual_Guest_Block_Device_Template_Group'
109177
else:
110178

111179
tag_type = tag_type.lower()
112180
# Sets the First letter, and any letter preceeded by a '_' to uppercase
113181
# HARDWARE -> Hardware, NETWORK_VLAN -> Network_Vlan for example.
114182
service = re.sub(r'(^[a-z]|\_[a-z])', lambda x: x.group().upper(), tag_type)
183+
return service
184+
185+
# @staticmethod
186+
# def type_to_datatype(tag_type):
187+
# """Returns the SoftLayer datatye for the given tag_type"""
188+
# datatye = None
189+
# if tag_type in ['ACCOUNT_DOCUMENT', 'CONTRACT']:
190+
# return None
191+
192+
# if tag_type == 'APPLICATION_DELIVERY_CONTROLLER':
193+
# datatye = 'adcLoadBalancers'
194+
# elif tag_type == 'GUEST':
195+
# datatye = 'virtualGuests'
196+
# elif tag_type == 'DEDICATED_HOST':
197+
# datatye = 'dedicatedHosts'
198+
# elif tag_type == 'HARDWARE':
199+
# datatye = 'hardware'
200+
# elif tag_type == 'TICKET':
201+
# datatye = 'openTickets'
202+
# elif tag_type == 'NETWORK_SUBNET':
203+
# datatye = 'subnets'
204+
# elif tag_type == 'NETWORK_VLAN':
205+
# datatye = 'networkVlans'
206+
# elif tag_type == 'NETWORK_VLAN_FIREWALL':
207+
# datatye = 'networkVlans'
208+
# elif tag_type == 'IMAGE_TEMPLATE':
209+
# datatye = 'blockDeviceTemplateGroups'
210+
211+
# return datatye
115212

116-
# return {}
117-
return self.client.call(service, 'getObject', id=resource_table_id)
118-
119-
def delete_tag(self, name):
120-
return self.client.call('SoftLayer_Tag', 'deleteTag', name)
121-
122-
def set_tags(self, tags, key_name, resource_id):
123-
"""Calls SoftLayer_Tag::setTags()
124-
125-
:param string tags: List of tags.
126-
:param string key_name: Key name of a tag type.
127-
:param int resource_id: ID of the object being tagged.
128-
"""
129-
return self.client.call('SoftLayer_Tag', 'setTags', tags, key_name, resource_id)

0 commit comments

Comments
 (0)