Skip to content

Commit c083884

Browse files
Merge branch 'master' of github.com:softlayer/softlayer-python
2 parents a681815 + 4bb26eb commit c083884

File tree

6 files changed

+185
-4
lines changed

6 files changed

+185
-4
lines changed

SoftLayer/CLI/image/datacenter.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Edit details of an image."""
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 helpers
9+
10+
11+
@click.command()
12+
@click.argument('identifier')
13+
@click.option('--add/--remove', default=True,
14+
help="To add or remove Datacenter")
15+
@click.argument('locations', nargs=-1, required=True)
16+
@environment.pass_env
17+
def cli(env, identifier, add, locations):
18+
"""Add/Remove datacenter of an image."""
19+
20+
image_mgr = SoftLayer.ImageManager(env.client)
21+
image_id = helpers.resolve_id(image_mgr.resolve_ids, identifier, 'image')
22+
23+
if add:
24+
result = image_mgr.add_locations(image_id, locations)
25+
else:
26+
result = image_mgr.remove_locations(image_id, locations)
27+
28+
env.fout(result)

SoftLayer/CLI/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
('image:list', 'SoftLayer.CLI.image.list:cli'),
164164
('image:import', 'SoftLayer.CLI.image.import:cli'),
165165
('image:export', 'SoftLayer.CLI.image.export:cli'),
166+
('image:datacenter', 'SoftLayer.CLI.image.datacenter:cli'),
166167

167168
('ipsec', 'SoftLayer.CLI.vpn.ipsec'),
168169
('ipsec:configure', 'SoftLayer.CLI.vpn.ipsec.configure:cli'),

SoftLayer/fixtures/SoftLayer_Virtual_Guest_Block_Device_Template_Group.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
'name': 'test_image',
88
'parentId': '',
99
'publicFlag': True,
10+
'children': [{
11+
'datacenter': {
12+
'name': 'ams01'
13+
}
14+
}],
1015
}, {
1116
'accountId': 1234,
1217
'blockDevices': [],
@@ -16,24 +21,35 @@
1621
'name': 'test_image2',
1722
'parentId': '',
1823
'publicFlag': True,
24+
'children': [{
25+
'datacenter': {
26+
'name': 'ams01'
27+
}
28+
}],
1929
}]
2030

2131
getObject = IMAGES[0]
2232
getPublicImages = IMAGES
2333
deleteObject = {}
2434
editObject = True
2535
setTags = True
26-
createFromExternalSource = [{
36+
createFromExternalSource = {
2737
'createDate': '2013-12-05T21:53:03-06:00',
2838
'globalIdentifier': '0B5DEAF4-643D-46CA-A695-CECBE8832C9D',
2939
'id': 100,
3040
'name': 'test_image',
31-
}]
32-
createFromIcos = [{
41+
}
42+
createFromIcos = {
3343
'createDate': '2013-12-05T21:53:03-06:00',
3444
'globalIdentifier': '0B5DEAF4-643D-46CA-A695-CECBE8832C9D',
3545
'id': 100,
3646
'name': 'test_image',
37-
}]
47+
}
3848
copyToExternalSource = True
3949
copyToIcos = True
50+
addLocations = True
51+
removeLocations = True
52+
getStorageLocations = [
53+
{'id': 265592, 'longName': 'Amsterdam 1', 'name': 'ams01', 'statusId': 2},
54+
{'id': 814994, 'longName': 'Amsterdam 3', 'name': 'ams03', 'statusId': 2},
55+
]

SoftLayer/managers/image.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
:license: MIT, see LICENSE for more details.
77
"""
88

9+
from SoftLayer import exceptions
910
from SoftLayer import utils
1011

1112
IMAGE_MASK = ('id,accountId,name,globalIdentifier,blockDevices,parentId,'
@@ -187,3 +188,52 @@ def export_image_to_uri(self, image_id, uri, ibm_api_key=None):
187188
}, id=image_id)
188189
else:
189190
return self.vgbdtg.copyToExternalSource({'uri': uri}, id=image_id)
191+
192+
def add_locations(self, image_id, location_names):
193+
"""Add available locations to an archive image template.
194+
195+
:param int image_id: The ID of the image
196+
:param location_names: Locations for the Image.
197+
"""
198+
locations = self.get_locations_list(image_id, location_names)
199+
return self.vgbdtg.addLocations(locations, id=image_id)
200+
201+
def remove_locations(self, image_id, location_names):
202+
"""Remove available locations from an archive image template.
203+
204+
:param int image_id: The ID of the image
205+
:param location_names: Locations for the Image.
206+
"""
207+
locations = self.get_locations_list(image_id, location_names)
208+
return self.vgbdtg.removeLocations(locations, id=image_id)
209+
210+
def get_storage_locations(self, image_id):
211+
"""Get available locations for public image storage.
212+
213+
:param int image_id: The ID of the image
214+
"""
215+
return self.vgbdtg.getStorageLocations(id=image_id)
216+
217+
def get_locations_list(self, image_id, location_names):
218+
"""Converts a list of location names to a list of locations.
219+
220+
:param int image_id: The ID of the image.
221+
:param list location_names: A list of location names strings.
222+
:returns: A list of locations associated with the given location names in the image.
223+
"""
224+
locations = self.get_storage_locations(image_id)
225+
locations_ids = []
226+
matching_location = {}
227+
output_error = "Location {} does not exist for available locations for image {}"
228+
229+
for location_name in location_names:
230+
for location in locations:
231+
if location_name == location.get('name'):
232+
matching_location = location
233+
break
234+
if matching_location.get('id') is None:
235+
raise exceptions.SoftLayerError(output_error.format(location_name, image_id))
236+
237+
locations_ids.append(matching_location)
238+
239+
return locations_ids

tests/CLI/modules/image_tests.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""
2+
SoftLayer.tests.CLI.modules.image_tests
3+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4+
5+
:license: MIT, see LICENSE for more details.
6+
"""
7+
8+
from SoftLayer import testing
9+
10+
11+
class ImageTests(testing.TestCase):
12+
13+
def test_detail(self):
14+
result = self.run_command(['image', 'detail', '100'])
15+
self.assert_no_fail(result)
16+
17+
def test_delete(self):
18+
result = self.run_command(['image', 'delete', '100'])
19+
self.assert_no_fail(result)
20+
21+
def test_edit_note(self):
22+
result = self.run_command(['image', 'edit', '100', '--note=test'])
23+
self.assert_no_fail(result)
24+
25+
def test_edit_name(self):
26+
result = self.run_command(['image', 'edit', '100', '--name=test'])
27+
self.assert_no_fail(result)
28+
29+
def test_edit_tag(self):
30+
result = self.run_command(['image', 'edit', '100', '--tag=test'])
31+
self.assert_no_fail(result)
32+
33+
def test_import(self):
34+
result = self.run_command(['image', 'import', '100', 'swift://test'])
35+
self.assert_no_fail(result)
36+
37+
def test_export(self):
38+
result = self.run_command(['image', 'export', '100', 'swift://test'])
39+
self.assert_no_fail(result)
40+
41+
def test_list(self):
42+
result = self.run_command(['image', 'list'])
43+
self.assert_no_fail(result)
44+
45+
def test_datacenter_add(self):
46+
result = self.run_command(['image', 'datacenter', '100', '--add', 'ams01'])
47+
self.assert_no_fail(result)
48+
49+
def test_datacenter_remove(self):
50+
result = self.run_command(['image', 'datacenter', '100', '--remove', 'ams01'])
51+
self.assert_no_fail(result)
52+
53+
def test_datacenter_remove_fails(self):
54+
result = self.run_command(['image', 'datacenter', '100', '--remove'])
55+
self.assertEqual(2, result.exit_code)

tests/managers/image_tests.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
import SoftLayer
9+
from SoftLayer import exceptions
910
from SoftLayer import testing
1011

1112
IMAGE_SERVICE = 'SoftLayer_Virtual_Guest_Block_Device_Template_Group'
@@ -192,3 +193,33 @@ def test_export_image_cos(self):
192193
'copyToIcos',
193194
args=({'uri': 'cos://someuri', 'ibmApiKey': 'someApiKey'},),
194195
identifier=1234)
196+
197+
def test_add_locations_image(self):
198+
locations = ['ams01']
199+
self.image.add_locations(100, locations)
200+
201+
self.assert_called_with(IMAGE_SERVICE, 'addLocations', identifier=100)
202+
203+
def test_add_locations_fail(self):
204+
locations = ['test']
205+
self.assertRaises(
206+
exceptions.SoftLayerError,
207+
self.image.add_locations,
208+
100,
209+
locations
210+
)
211+
212+
def test_remove_locations_image(self):
213+
locations = ['ams01']
214+
self.image.remove_locations(100, locations)
215+
216+
self.assert_called_with(IMAGE_SERVICE, 'removeLocations', identifier=100)
217+
218+
def test_get_locations_id_fails(self):
219+
locations = ['test']
220+
self.assertRaises(
221+
exceptions.SoftLayerError,
222+
self.image.get_locations_list,
223+
100,
224+
locations
225+
)

0 commit comments

Comments
 (0)