1# Licensed to the Apache Software Foundation (ASF) under one or more 2# contributor license agreements. See the NOTICE file distributed with 3# this work for additional information regarding copyright ownership. 4# The ASF licenses this file to You under the Apache License, Version 2.0 5# (the "License"); you may not use this file except in compliance with 6# the License. You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import unittest 17import sys 18import pytest 19 20from libcloud.common.types import InvalidCredsError 21 22from libcloud.utils.py3 import httplib 23from libcloud.utils.py3 import xmlrpclib 24from libcloud.utils.py3 import next 25 26from libcloud.compute.drivers.softlayer import SoftLayerNodeDriver as SoftLayer 27from libcloud.compute.drivers.softlayer import SoftLayerException, \ 28 NODE_STATE_MAP 29from libcloud.compute.types import NodeState, KeyPairDoesNotExistError 30 31from libcloud.test import unittest 32from libcloud.test import MockHttp # pylint: disable-msg=E0611 33from libcloud.test.file_fixtures import ComputeFileFixtures 34from libcloud.test.secrets import SOFTLAYER_PARAMS 35 36null_fingerprint = '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:' + \ 37 '00:00:00:00:00' 38 39 40class SoftLayerTests(unittest.TestCase): 41 42 def setUp(self): 43 SoftLayer.connectionCls.conn_class = SoftLayerMockHttp 44 SoftLayerMockHttp.type = None 45 self.driver = SoftLayer(*SOFTLAYER_PARAMS) 46 47 def test_list_nodes(self): 48 nodes = self.driver.list_nodes() 49 node = nodes[0] 50 self.assertEqual(node.name, 'libcloud-testing1.example.com') 51 self.assertEqual(node.state, NodeState.RUNNING) 52 self.assertEqual(node.extra['password'], 'L3TJVubf') 53 54 def test_initializing_state(self): 55 nodes = self.driver.list_nodes() 56 node = nodes[1] 57 self.assertEqual(node.state, NODE_STATE_MAP['INITIATING']) 58 59 def test_list_locations(self): 60 locations = self.driver.list_locations() 61 dal = next(l for l in locations if l.id == 'dal05') 62 self.assertEqual(dal.country, 'US') 63 self.assertEqual(dal.id, 'dal05') 64 self.assertEqual(dal.name, 'Dallas - Central U.S.') 65 66 def test_list_images(self): 67 images = self.driver.list_images() 68 image = images[0] 69 self.assertEqual(image.id, 'CENTOS_6_64') 70 71 def test_get_image(self): 72 image = self.driver.get_image('CENTOS_6_64') 73 self.assertEqual(image.id, 'CENTOS_6_64') 74 75 def test_fail_get_image(self): 76 self.assertRaises( 77 SoftLayerException, 78 self.driver.get_image, 79 'NOT_IMAGE') 80 81 def test_list_sizes(self): 82 sizes = self.driver.list_sizes() 83 self.assertEqual(len(sizes), 13) 84 for size in sizes: 85 self.assertTrue(size.price > 0.0) 86 87 def test_create_node(self): 88 node = self.driver.create_node(name="libcloud-testing", 89 location=self.driver.list_locations()[0], 90 size=self.driver.list_sizes()[0], 91 image=self.driver.list_images()[0]) 92 self.assertEqual(node.name, 'libcloud-testing.example.com') 93 self.assertEqual(node.state, NODE_STATE_MAP['RUNNING']) 94 95 def test_create_node_ex_hourly_True(self): 96 SoftLayerMockHttp.type = 'HOURLY_BILLING_TRUE' 97 98 node = self.driver.create_node(name="libcloud-testing", 99 location=self.driver.list_locations()[0], 100 size=self.driver.list_sizes()[0], 101 image=self.driver.list_images()[0], 102 ex_hourly=True) 103 self.assertEqual(node.name, 'libcloud-testing.example.com') 104 self.assertEqual(node.state, NODE_STATE_MAP['RUNNING']) 105 106 SoftLayerMockHttp.type = 'HOURLY_BILLING_FALSE' 107 108 node = self.driver.create_node(name="libcloud-testing", 109 location=self.driver.list_locations()[0], 110 size=self.driver.list_sizes()[0], 111 image=self.driver.list_images()[0], 112 ex_hourly=False) 113 self.assertEqual(node.name, 'libcloud-testing.example.com') 114 self.assertEqual(node.state, NODE_STATE_MAP['RUNNING']) 115 116 117 def test_create_fail(self): 118 SoftLayerMockHttp.type = "SOFTLAYEREXCEPTION" 119 self.assertRaises( 120 SoftLayerException, 121 self.driver.create_node, 122 name="SOFTLAYEREXCEPTION", 123 location=self.driver.list_locations()[0], 124 size=self.driver.list_sizes()[0], 125 image=self.driver.list_images()[0]) 126 127 def test_create_creds_error(self): 128 SoftLayerMockHttp.type = "INVALIDCREDSERROR" 129 self.assertRaises( 130 InvalidCredsError, 131 self.driver.create_node, 132 name="INVALIDCREDSERROR", 133 location=self.driver.list_locations()[0], 134 size=self.driver.list_sizes()[0], 135 image=self.driver.list_images()[0]) 136 137 def test_create_node_no_location(self): 138 self.driver.create_node(name="Test", 139 size=self.driver.list_sizes()[0], 140 image=self.driver.list_images()[0]) 141 142 def test_create_node_no_image(self): 143 self.driver.create_node(name="Test", size=self.driver.list_sizes()[0]) 144 145 def test_create_node_san(self): 146 self.driver.create_node(name="Test", ex_local_disk=False) 147 148 def test_create_node_domain_for_name(self): 149 self.driver.create_node(name="libcloud.org") 150 151 def test_create_node_ex_options(self): 152 self.driver.create_node(name="Test", 153 location=self.driver.list_locations()[0], 154 size=self.driver.list_sizes()[0], 155 image=self.driver.list_images()[0], 156 ex_domain='libcloud.org', 157 ex_cpus=2, 158 ex_ram=2048, 159 ex_disk=100, 160 ex_keyname='test1', 161 ex_bandwidth=10, 162 ex_local_disk=False, 163 ex_datacenter='Dal05', 164 ex_os='UBUNTU_LATEST') 165 166 def test_reboot_node(self): 167 node = self.driver.list_nodes()[0] 168 self.driver.reboot_node(node) 169 170 def test_destroy_node(self): 171 node = self.driver.list_nodes()[0] 172 self.driver.destroy_node(node) 173 174 def test_list_keypairs(self): 175 keypairs = self.driver.list_key_pairs() 176 self.assertEqual(len(keypairs), 2) 177 self.assertEqual(keypairs[0].name, 'test1') 178 self.assertEqual(keypairs[0].fingerprint, null_fingerprint) 179 180 def test_get_key_pair(self): 181 key_pair = self.driver.get_key_pair(name='test1') 182 self.assertEqual(key_pair.name, 'test1') 183 184 def test_get_key_pair_does_not_exist(self): 185 self.assertRaises(KeyPairDoesNotExistError, self.driver.get_key_pair, 186 name='test-key-pair') 187 188 @pytest.mark.skip(reason="no way of currently testing this") 189 def test_create_key_pair(self): 190 key_pair = self.driver.create_key_pair(name='my-key-pair') 191 fingerprint = ('1f:51:ae:28:bf:89:e9:d8:1f:25:5d' 192 ':37:2d:7d:b8:ca:9f:f5:f1:6f') 193 194 self.assertEqual(key_pair.name, 'my-key-pair') 195 self.assertEqual(key_pair.fingerprint, fingerprint) 196 self.assertTrue(key_pair.private_key is not None) 197 198 def test_delete_key_pair(self): 199 success = self.driver.delete_key_pair('test1') 200 self.assertTrue(success) 201 202 203class SoftLayerMockHttp(MockHttp, unittest.TestCase): 204 fixtures = ComputeFileFixtures('softlayer') 205 206 def _get_method_name(self, type, use_param, qs, path): 207 return "_xmlrpc" 208 209 def _xmlrpc(self, method, url, body, headers): 210 params, meth_name = xmlrpclib.loads(body) 211 url = url.replace("/", "_") 212 meth_name = "%s_%s" % (url, meth_name) 213 return getattr(self, meth_name)(method, url, body, headers) 214 215 def _xmlrpc_v3_SoftLayer_Virtual_Guest_getCreateObjectOptions( 216 self, method, url, body, headers): 217 body = self.fixtures.load( 218 'v3__SoftLayer_Virtual_Guest_getCreateObjectOptions.xml') 219 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 220 221 def _xmlrpc_v3_SoftLayer_Account_getVirtualGuests( 222 self, method, url, body, headers): 223 body = self.fixtures.load('v3_SoftLayer_Account_getVirtualGuests.xml') 224 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 225 226 def _xmlrpc_v3_SoftLayer_Location_Datacenter_getDatacenters( 227 self, method, url, body, headers): 228 body = self.fixtures.load( 229 'v3_SoftLayer_Location_Datacenter_getDatacenters.xml') 230 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 231 232 def _xmlrpc_v3_SoftLayer_Virtual_Guest_createObject( 233 self, method, url, body, headers): 234 fixture = { 235 None: 'v3__SoftLayer_Virtual_Guest_createObject.xml', 236 'INVALIDCREDSERROR': 'SoftLayer_Account.xml', 237 'SOFTLAYEREXCEPTION': 'fail.xml', 238 'HOURLY_BILLING_TRUE': 'v3__SoftLayer_Virtual_Guest_createObject.xml', 239 'HOURLY_BILLING_FALSE': 'v3__SoftLayer_Virtual_Guest_createObject.xml', 240 }[self.type] 241 242 if self.type == 'HOURLY_BILLING_TRUE': 243 # Verify parameter is sent as a boolean and not as a string 244 expected_value = """ 245<member> 246<name>hourlyBillingFlag</name> 247<value><boolean>1</boolean></value> 248</member> 249""".strip() 250 251 self.assertTrue(expected_value in body, 'Request body is missing hourlyBillingFlag attribute') 252 elif self.type == 'HOURLY_BILLING_FALSE': 253 # Verify parameter is sent as a boolean and not as a string 254 expected_value = """ 255<member> 256<name>hourlyBillingFlag</name> 257<value><boolean>0</boolean></value> 258</member> 259""".strip() 260 261 self.assertTrue(expected_value in body, 'Request body is missing hourlyBillingFlag attribute') 262 263 264 body = self.fixtures.load(fixture) 265 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 266 267 def _xmlrpc_v3_SoftLayer_Virtual_Guest_getObject( 268 self, method, url, body, headers): 269 body = self.fixtures.load( 270 'v3__SoftLayer_Virtual_Guest_getObject.xml') 271 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 272 273 def _xmlrpc_v3_SoftLayer_Virtual_Guest_rebootSoft( 274 self, method, url, body, headers): 275 body = self.fixtures.load('empty.xml') 276 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 277 278 def _xmlrpc_v3_SoftLayer_Virtual_Guest_deleteObject( 279 self, method, url, body, headers): 280 body = self.fixtures.load('empty.xml') 281 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 282 283 def _xmlrpc_v3_SoftLayer_Account_getSshKeys( 284 self, method, url, body, headers): 285 body = self.fixtures.load('v3__SoftLayer_Account_getSshKeys.xml') 286 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 287 288 def _xmlrpc_v3_SoftLayer_Security_Ssh_Key_getObject( 289 self, method, url, body, headers): 290 body = self.fixtures.load('v3__SoftLayer_Security_Ssh_Key_getObject.xml') 291 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 292 293 def _xmlrpc_v3_SoftLayer_Security_Ssh_Key_createObject( 294 self, method, url, body, headers): 295 body = self.fixtures.load('v3__SoftLayer_Security_Ssh_Key_createObject.xml') 296 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 297 298 def _xmlrpc_v3_SoftLayer_Security_Ssh_Key_deleteObject( 299 self, method, url, body, headers): 300 body = self.fixtures.load('v3__SoftLayer_Security_Ssh_Key_deleteObject.xml') 301 return (httplib.OK, body, {}, httplib.responses[httplib.OK]) 302 303 304if __name__ == '__main__': 305 sys.exit(unittest.main()) 306