Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions SoftLayer/CLI/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@
('tags:set', 'SoftLayer.CLI.tags.set:cli'),
('tags:details', 'SoftLayer.CLI.tags.details:cli'),
('tags:delete', 'SoftLayer.CLI.tags.delete:cli'),
('tags:taggable', 'SoftLayer.CLI.tags.taggable:cli'),

('ticket', 'SoftLayer.CLI.ticket'),
('ticket:create', 'SoftLayer.CLI.ticket.create:cli'),
Expand Down
37 changes: 19 additions & 18 deletions SoftLayer/CLI/tags/delete.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
"""List Tags."""
"""Delete Tags."""
# :license: MIT, see LICENSE for more details.

import click

from SoftLayer.exceptions import SoftLayerAPIError
from SoftLayer.CLI.exceptions import ArgumentError
from SoftLayer.managers.tags import TagManager
from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer import utils

# pylint: disable=unnecessary-lambda

from pprint import pprint as pp


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

tag_manager = TagManager(env.client)

if not name and id is not None:
tag_name = tag_manager.get_tag(id)
tag_manager.delete_tag(tag_name['name'])
if name and id is None:
tag_manager.delete_tag(name)
tag_name = identifier
# If the identifier is a int, and user didn't tell us it was a name.
if str.isdigit(identifier) and not name:
tag = tag_manager.get_tag(tag_id)
tag_name = tag.get('name', None)


result = tag_manager.delete_tag(tag_name)
if result:
click.secho("Tag {} has been removed".format(tag_name), fg='green')
else:
click.secho("Failed to remove tag {}".format(tag_name), fg='red')
9 changes: 6 additions & 3 deletions SoftLayer/CLI/tags/details.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@

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

tag_manager = TagManager(env.client)

if str.isdigit(identifier):
# If the identifier is a int, and user didn't tell us it was a name.
if str.isdigit(identifier) and not name:
tags = [tag_manager.get_tag(identifier)]
else:
tags = tag_manager.get_tag_by_name(identifier)
Expand Down
6 changes: 4 additions & 2 deletions SoftLayer/CLI/tags/set.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@


@click.command()
@click.option('--tags', '-t', type=click.STRING, required=True, help='List of tags e.g. "tag1, tag2"')
@click.option('--key-name', '-k', type=click.STRING, required=True, help="Key name of a tag type e.g. GUEST, HARDWARE")
@click.option('--tags', '-t', type=click.STRING, required=True,
help='Comma seperated list of tags, enclosed in quotes. "tag1, tag2"')
@click.option('--key-name', '-k', type=click.STRING, required=True,
help="Key name of a tag type e.g. GUEST, HARDWARE. See slcli tags taggable output.")
@click.option('--resource-id', '-r', type=click.INT, required=True, help="ID of the object being tagged")
@environment.pass_env
def cli(env, tags, key_name, resource_id):
Expand Down
44 changes: 44 additions & 0 deletions SoftLayer/CLI/tags/taggable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""List everything that could be tagged."""
# :license: MIT, see LICENSE for more details.

import click

from SoftLayer.CLI.exceptions import ArgumentError
from SoftLayer.CLI import formatting
from SoftLayer.managers.tags import TagManager
from SoftLayer.CLI import environment

from pprint import pprint as pp
@click.command()
@environment.pass_env
def cli(env):
"""List everything that could be tagged."""

tag_manager = TagManager(env.client)
tag_types = tag_manager.get_all_tag_types()
for tag_type in tag_types:
title = "{} ({})".format(tag_type['description'], tag_type['keyName'])
table = formatting.Table(['Id', 'Name'], title=title)
resources = tag_manager.taggable_by_type(tag_type['keyName'])
for resource in resources:
table.add_row([
resource['resource']['id'],
get_resource_name(resource['resource'], tag_type['keyName'])
])
env.fout(table)


def get_resource_name(resource, tag_type):
"""Returns a string that names a resource"""
if tag_type == 'NETWORK_VLAN_FIREWALL':
return resource.get('primaryIpAddress')
elif tag_type == 'NETWORK_VLAN':
return "{} ({})".format(resource.get('vlanNumber'), resource.get('name'))
elif tag_type == 'IMAGE_TEMPLATE' or tag_type == 'APPLICATION_DELIVERY_CONTROLLER':
return resource.get('name')
elif tag_type == 'TICKET':
return resource.get('subjet')
elif tag_type == 'NETWORK_SUBNET':
return resource.get('networkIdentifier')
else:
return resource.get('fullyQualifiedDomainName')
113 changes: 98 additions & 15 deletions SoftLayer/managers/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,34 +96,117 @@ def reference_lookup(self, resource_table_id, tag_type):
|Vlan |NETWORK_VLAN|
|Dedicated Host |DEDICATED_HOST|
"""
service = self.type_to_service(tag_type)
if service is None:
raise SoftLayerAPIError(404, "Unable to lookup {} types".format(tag_type))
# return {}
return self.client.call(service, 'getObject', id=resource_table_id)

def delete_tag(self, name):
"""Calls SoftLayer_Tag::deleteTag

:param string name: tag name to delete
"""
return self.client.call('SoftLayer_Tag', 'deleteTag', name)

def set_tags(self, tags, key_name, resource_id):
"""Calls SoftLayer_Tag::setTags()

:param string tags: List of tags.
:param string key_name: Key name of a tag type.
:param int resource_id: ID of the object being tagged.
"""
return self.client.call('SoftLayer_Tag', 'setTags', tags, key_name, resource_id)

def get_all_tag_types(self):
"""Calls SoftLayer_Tag::getAllTagTypes()"""
types = self.client.call('SoftLayer_Tag', 'getAllTagTypes')
useable_types = []
for tag_type in types:
service = self.type_to_service(tag_type['keyName'])
# Mostly just to remove the types that are not user taggable.
if service is not None:
temp_type = tag_type
temp_type['service'] = service
useable_types.append(temp_type)
return useable_types

def taggable_by_type(self, tag_type):
"""Returns a list of resources that can be tagged, that are of the given type

:param string tag_type: Key name of a tag type. See SoftLayer_Tag::getAllTagTypes
"""
service = self.type_to_service(tag_type)
search_term = "_objectType:SoftLayer_{}".format(service)
if tag_type == 'TICKET':
search_term = "{} status.name: open".format(search_term)
elif tag_type == 'IMAGE_TEMPLATE':
mask = "mask[id,accountId,name,globalIdentifier,parentId,publicFlag,flexImageFlag,imageType]"
resources = self.client.call('SoftLayer_Account', 'getPrivateBlockDeviceTemplateGroups',
mask=mask, iter=True)
to_return = []
# Fake search result output
for resource in resources:
to_return.append({'resourceType':service, 'resource':resource})
return to_return
elif tag_type == 'NETWORK_SUBNET':
resources = self.client.call('SoftLayer_Account', 'getSubnets', iter=True)
to_return = []
# Fake search result output
for resource in resources:
to_return.append({'resourceType':service, 'resource':resource})
return to_return
resources = self.client.call('SoftLayer_Search', 'advancedSearch', search_term, iter=True)
return resources

@staticmethod
def type_to_service(tag_type):
"""Returns the SoftLayer service for the given tag_type"""
service = None
if tag_type in ['ACCOUNT_DOCUMENT', 'CONTRACT']:
raise SoftLayerAPIError(404, "Unable to lookup {} types".format(tag_type))
return None

if tag_type == 'APPLICATION_DELIVERY_CONTROLLER':
service = 'Network_Application_Delivery_Controller'
elif tag_type == 'GUEST':
service = 'Virtual_Guest'
elif tag_type == 'DEDICATED_HOST':
service = 'Virtual_DedicatedHost'
elif tag_type == 'IMAGE_TEMPLATE':
service = 'Virtual_Guest_Block_Device_Template_Group'
else:

tag_type = tag_type.lower()
# Sets the First letter, and any letter preceeded by a '_' to uppercase
# HARDWARE -> Hardware, NETWORK_VLAN -> Network_Vlan for example.
service = re.sub(r'(^[a-z]|\_[a-z])', lambda x: x.group().upper(), tag_type)
return service

# @staticmethod
# def type_to_datatype(tag_type):
# """Returns the SoftLayer datatye for the given tag_type"""
# datatye = None
# if tag_type in ['ACCOUNT_DOCUMENT', 'CONTRACT']:
# return None

# if tag_type == 'APPLICATION_DELIVERY_CONTROLLER':
# datatye = 'adcLoadBalancers'
# elif tag_type == 'GUEST':
# datatye = 'virtualGuests'
# elif tag_type == 'DEDICATED_HOST':
# datatye = 'dedicatedHosts'
# elif tag_type == 'HARDWARE':
# datatye = 'hardware'
# elif tag_type == 'TICKET':
# datatye = 'openTickets'
# elif tag_type == 'NETWORK_SUBNET':
# datatye = 'subnets'
# elif tag_type == 'NETWORK_VLAN':
# datatye = 'networkVlans'
# elif tag_type == 'NETWORK_VLAN_FIREWALL':
# datatye = 'networkVlans'
# elif tag_type == 'IMAGE_TEMPLATE':
# datatye = 'blockDeviceTemplateGroups'

# return datatye

# return {}
return self.client.call(service, 'getObject', id=resource_table_id)

def delete_tag(self, name):
return self.client.call('SoftLayer_Tag', 'deleteTag', name)

def set_tags(self, tags, key_name, resource_id):
"""Calls SoftLayer_Tag::setTags()

:param string tags: List of tags.
:param string key_name: Key name of a tag type.
:param int resource_id: ID of the object being tagged.
"""
return self.client.call('SoftLayer_Tag', 'setTags', tags, key_name, resource_id)