Skip to content

Commit 29c7fff

Browse files
author
Elias Nygren
committed
get_servers by tags, refactor server reset and creation with a factory
1 parent 53c4abf commit 29c7fff

File tree

3 files changed

+101
-30
lines changed

3 files changed

+101
-30
lines changed

test/test_server_creation.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,43 @@ def test_create_server(self, manager):
119119
assert server1.core_number == "2"
120120
assert server1.memory_amount == "1024"
121121

122+
# assert ips and storages have correct types
123+
assert type(server1.storage_devices[0]).__name__ == "Storage"
124+
assert type(server1.ip_addresses[0]).__name__ == "IP_address"
125+
126+
# assert new data was populated
127+
assert server1.video_model == "cirrus"
128+
assert server1.vnc == "off"
129+
assert server1.vnc_password == "aabbccdd"
130+
131+
@responses.activate
132+
def test_create_server_with_dict(self, manager):
133+
responses.add(
134+
responses.POST,
135+
Mock.base_url + "/server",
136+
body = Mock.read_from_file("server_create.json"),
137+
status = 202,
138+
content_type='application/json'
139+
)
140+
141+
server1 = {
142+
'core_number': 2, 'memory_amount': 1024, 'hostname': "my.example.com", 'zone': ZONE.Chicago,
143+
'storage_devices': [
144+
{ 'os': "Ubuntu 14.04", 'size': 10 },
145+
{ 'size': 100, 'title': "storage disk 1" },
146+
]}
147+
148+
server1 = manager.create_server(server1)
149+
150+
# assert correct values in response
151+
assert type(server1).__name__ == "Server"
152+
assert server1.core_number == "2"
153+
assert server1.memory_amount == "1024"
154+
155+
# assert ips and storages have correct types
156+
assert type(server1.storage_devices[0]).__name__ == "Storage"
157+
assert type(server1.ip_addresses[0]).__name__ == "IP_address"
158+
122159
# assert new data was populated
123160
assert server1.video_model == "cirrus"
124161
assert server1.vnc == "off"

upcloud_api/cloud_manager/server_mixin.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,38 @@ class ServerManager(object):
1515
Functions for managing IP-addresses. Intended to be used as a mixin for CloudManager.
1616
"""
1717

18-
def get_servers(self, populate=False):
18+
def get_servers(self, populate=False, tags_has_one=None, tags_has_all=None):
1919
"""
2020
Returns a list of (populated or unpopulated) Server instances.
21-
Populate = False (default) => 1 API request, returns unpopulated Server instances.
22-
Populate = True => Does 1 + n API requests (n = # of servers), returns populated Server instances.
21+
- populate = False (default) => 1 API request, returns unpopulated Server instances.
22+
- populate = True => Does 1 + n API requests (n = # of servers), returns populated Server instances.
23+
24+
New in 0.3.0: the list can be filtered with tags:
25+
- tags_has_one: returns servers that have at least one of the given tags
26+
- tags_has_all: returns servers that have all of the tags
2327
"""
2428

25-
servers = self.get_request("/server")["servers"]["server"]
29+
if tags_has_all and tags_has_one:
30+
raise Exception("only one of (tags_has_all, tags_has_one) is allowed.")
31+
32+
request = "/server"
33+
if tags_has_all:
34+
taglist = tags_has_all.join(":")
35+
request = "/server/tag/" + taglist
36+
37+
if tags_has_one:
38+
taglist = tags_has_all.join(",")
39+
request = "/server/tag/" + taglist
40+
41+
servers = self.get_request(request)["servers"]["server"]
2642

2743
server_list = list()
2844
for server in servers:
2945
# remove the extra "tag" dict to simplify accessing tags
3046
server['tags'] = server['tags']['tag']
3147
server_list.append( Server(server, cloud_manager = self) )
3248

33-
if( populate ):
49+
if populate:
3450
for server_instance in server_list:
3551
server_instance.populate()
3652

@@ -86,32 +102,17 @@ def create_server(self, server):
86102
if isinstance(server, Server):
87103
body = server.prepare_post_body()
88104
else:
89-
ip_data = server.pop("ip_addresses", None)
90-
storage_data = server.pop("storage_devices", None)
91-
92-
server_dict = dict()
93-
server_dict['cloud_manager'] = self
94-
if ip_data: server_dict['ip_addresses'] = IP_address._create_ip_address_objs( ip_data, cloud_manager = self )
95-
if storage_data: server_dict['storage_devices'] = Storage._create_storage_objs( storage_data, cloud_manager = self )
96-
97-
server_from_dict = Server(server, **server_dict)
98-
body = server_from_dict.prepare_post_body()
99-
105+
server = Server._create_server_obj(server, cloud_manager=self)
106+
body = server.prepare_post_body()
100107

101108
res = self.post_request("/server", body)
102109

103-
# Populate subobjects
104-
IP_addresses = IP_address._create_ip_address_objs( res["server"].pop("ip_addresses"), cloud_manager = self )
105-
storages = Storage._create_storage_objs( res["server"].pop("storage_devices"), cloud_manager = self )
106-
107110
if isinstance(server, Server):
108111
server_to_return = server
109112
else:
110113
server_to_return = server_from_dict
111114

112115
server_to_return._reset( res["server"],
113-
ip_addresses = IP_addresses,
114-
storage_devices = storages,
115116
cloud_manager = self,
116117
populated = True)
117118
return server_to_return

upcloud_api/server.py

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
standard_library.install_aliases()
99

1010
from upcloud_api.base import BaseAPI
11+
from upcloud import Storage, IP_address
1112

1213
from time import sleep
1314

@@ -28,9 +29,9 @@ class Server(BaseAPI):
2829
"nic_model", "title", "timezone", "video_model", "vnc", "vnc_password" ]
2930

3031

31-
def __init__(self, *initial_data, **kwargs):
32+
def __init__(self, server=None, **kwargs):
3233
object.__setattr__(self, "populated", False)
33-
self._reset(*initial_data, **kwargs)
34+
self._reset(server, **kwargs)
3435

3536
if not hasattr(self, "title"):
3637
self.title = self.hostname
@@ -44,14 +45,21 @@ def __setattr__(self, name, value):
4445
else:
4546
object.__setattr__(self, name, value)
4647

47-
def _reset(self, *initial_data, **kwargs):
48+
def _reset(self, server, **kwargs):
4849
"""
49-
Reset all given attributes.
50-
May also be given
50+
Resets the server object with new values given as params.
51+
- server: a dict representing the server. e.g the API response.
52+
- kwargs: any meta fields such as cloud_manager and populated.
53+
54+
Note: storage_devices and ip_addresses may be given in server as dicts or
55+
in kwargs as lists containing Storage and IP_address objects.
5156
"""
52-
for dictionary in initial_data:
53-
for key in dictionary:
54-
object.__setattr__(self, key, dictionary[key])
57+
if server:
58+
# handle storage and ip_address dicts
59+
Server._handle_server_subobjs(server, kwargs.get('cloud_manager'))
60+
61+
for key in server:
62+
object.__setattr__(self, key, server[key])
5563

5664
for key in kwargs:
5765
object.__setattr__(self, key, kwargs[key])
@@ -379,3 +387,28 @@ def destroy_storages():
379387
else:
380388
# something went wrong, fail explicitly
381389
raise Exception('unknown server state: ' + self.state)
390+
391+
392+
@classmethod
393+
def _handle_server_subobjs(cls, server, cloud_manager):
394+
ip_data = server.pop("ip_addresses", None)
395+
storage_data = server.pop("storage_devices", None)
396+
397+
if ip_data:
398+
ip_addresses = IP_address._create_ip_address_objs(ip_data, cloud_manager = cloud_manager)
399+
server['ip_addresses'] = ip_addresses
400+
401+
if storage_data:
402+
storages = Storage._create_storage_objs(storage_data, cloud_manager = cloud_manager)
403+
server['storage_devices'] = storages
404+
405+
@classmethod
406+
def _create_server_obj(cls, server, cloud_manager):
407+
408+
cls._handle_server_subobjs(server, cloud_manager)
409+
410+
server_dict = dict()
411+
server_dict.update(server)
412+
server_dict['cloud_manager'] = cloud_manager
413+
414+
return Server(**server_dict)

0 commit comments

Comments
 (0)