Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / cyclades / __init__.py @ 65a8b1da

History | View | Annotate | Download (15.6 kB)

1 24851aa5 Stavros Sachtouris
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 a1c50326 Giorgos Verigakis
#
3 a1c50326 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 a1c50326 Giorgos Verigakis
# without modification, are permitted provided that the following
5 a1c50326 Giorgos Verigakis
# conditions are met:
6 a1c50326 Giorgos Verigakis
#
7 a1c50326 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 a1c50326 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 a1c50326 Giorgos Verigakis
#      disclaimer.
10 a1c50326 Giorgos Verigakis
#
11 a1c50326 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 a1c50326 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 a1c50326 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 a1c50326 Giorgos Verigakis
#      provided with the distribution.
15 a1c50326 Giorgos Verigakis
#
16 a1c50326 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 a1c50326 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 a1c50326 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 a1c50326 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 a1c50326 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 a1c50326 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 a1c50326 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 a1c50326 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 a1c50326 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 a1c50326 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 a1c50326 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 a1c50326 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 a1c50326 Giorgos Verigakis
#
29 a1c50326 Giorgos Verigakis
# The views and conclusions contained in the software and
30 a1c50326 Giorgos Verigakis
# documentation are those of the authors and should not be
31 a1c50326 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 a1c50326 Giorgos Verigakis
# or implied, of GRNET S.A.
33 a1c50326 Giorgos Verigakis
34 68fd1bda Stavros Sachtouris
from sys import stdout
35 02846a75 Stavros Sachtouris
from time import sleep
36 02846a75 Stavros Sachtouris
37 55faa0bc Stavros Sachtouris
from kamaki.clients.cyclades.rest_api import CycladesRestClient
38 29685b9b Stavros Sachtouris
from kamaki.clients import ClientError
39 a1c50326 Giorgos Verigakis
40 3dabe5d2 Stavros Sachtouris
41 55faa0bc Stavros Sachtouris
class CycladesClient(CycladesRestClient):
42 76e7661e Stavros Sachtouris
    """Synnefo Cyclades Compute API client"""
43 2f749e6e Stavros Sachtouris
44 dbcbf446 Stavros Sachtouris
    def create_server(
45 dbcbf446 Stavros Sachtouris
            self, name, flavor_id, image_id,
46 dbcbf446 Stavros Sachtouris
            metadata=None, personality=None):
47 dbcbf446 Stavros Sachtouris
        """Submit request to create a new server
48 dbcbf446 Stavros Sachtouris

49 dbcbf446 Stavros Sachtouris
        :param name: (str)
50 dbcbf446 Stavros Sachtouris

51 dbcbf446 Stavros Sachtouris
        :param flavor_id: integer id denoting a preset hardware configuration
52 dbcbf446 Stavros Sachtouris

53 dbcbf446 Stavros Sachtouris
        :param image_id: (str) id denoting the OS image to run on the VM
54 dbcbf446 Stavros Sachtouris

55 dbcbf446 Stavros Sachtouris
        :param metadata: (dict) vm metadata updated by os/users image metadata
56 dbcbf446 Stavros Sachtouris

57 dbcbf446 Stavros Sachtouris
        :param personality: a list of (file path, file contents) tuples,
58 dbcbf446 Stavros Sachtouris
            describing files to be injected into VM upon creation.
59 dbcbf446 Stavros Sachtouris

60 dbcbf446 Stavros Sachtouris
        :returns: a dict with the new VMs details
61 dbcbf446 Stavros Sachtouris

62 dbcbf446 Stavros Sachtouris
        :raises ClientError: wraps request errors
63 dbcbf446 Stavros Sachtouris
        """
64 dbcbf446 Stavros Sachtouris
        image = self.get_image_details(image_id)
65 dbcbf446 Stavros Sachtouris
        metadata = metadata or dict()
66 dbcbf446 Stavros Sachtouris
        for key in ('os', 'users'):
67 dbcbf446 Stavros Sachtouris
            try:
68 dbcbf446 Stavros Sachtouris
                metadata[key] = image['metadata'][key]
69 dbcbf446 Stavros Sachtouris
            except KeyError:
70 dbcbf446 Stavros Sachtouris
                pass
71 dbcbf446 Stavros Sachtouris
72 65a8b1da Stavros Sachtouris
        return super(CycladesClient, self).create_server(
73 65a8b1da Stavros Sachtouris
            name, flavor_id, image_id,
74 65a8b1da Stavros Sachtouris
            metadata=metadata, personality=personality)
75 dbcbf446 Stavros Sachtouris
76 a1c50326 Giorgos Verigakis
    def start_server(self, server_id):
77 f5eac743 Stavros Sachtouris
        """Submit a startup request
78 f5eac743 Stavros Sachtouris

79 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
80 cd295a1d Stavros Sachtouris

81 cd295a1d Stavros Sachtouris
        :returns: (dict) response headers
82 f5eac743 Stavros Sachtouris
        """
83 6a0b1658 Giorgos Verigakis
        req = {'start': {}}
84 cd295a1d Stavros Sachtouris
        r = self.servers_post(server_id, 'action', json_data=req, success=202)
85 cd295a1d Stavros Sachtouris
        return r.headers
86 6f1ec797 Stavros Sachtouris
87 a1c50326 Giorgos Verigakis
    def shutdown_server(self, server_id):
88 f5eac743 Stavros Sachtouris
        """Submit a shutdown request
89 f5eac743 Stavros Sachtouris

90 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
91 cd295a1d Stavros Sachtouris

92 cd295a1d Stavros Sachtouris
        :returns: (dict) response headers
93 f5eac743 Stavros Sachtouris
        """
94 6a0b1658 Giorgos Verigakis
        req = {'shutdown': {}}
95 cd295a1d Stavros Sachtouris
        r = self.servers_post(server_id, 'action', json_data=req, success=202)
96 cd295a1d Stavros Sachtouris
        return r.headers
97 3dabe5d2 Stavros Sachtouris
98 a1c50326 Giorgos Verigakis
    def get_server_console(self, server_id):
99 f5eac743 Stavros Sachtouris
        """
100 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
101 f5eac743 Stavros Sachtouris

102 f5eac743 Stavros Sachtouris
        :returns: (dict) info to set a VNC connection to VM
103 f5eac743 Stavros Sachtouris
        """
104 6a0b1658 Giorgos Verigakis
        req = {'console': {'type': 'vnc'}}
105 6f1ec797 Stavros Sachtouris
        r = self.servers_post(server_id, 'action', json_data=req, success=200)
106 6a0b1658 Giorgos Verigakis
        return r.json['console']
107 2d67ecbb Stavros Sachtouris
108 2d67ecbb Stavros Sachtouris
    def get_firewall_profile(self, server_id):
109 f5eac743 Stavros Sachtouris
        """
110 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
111 f5eac743 Stavros Sachtouris

112 f5eac743 Stavros Sachtouris
        :returns: (str) ENABLED | DISABLED | PROTECTED
113 f5eac743 Stavros Sachtouris

114 f5eac743 Stavros Sachtouris
        :raises ClientError: 520 No Firewall Profile
115 f5eac743 Stavros Sachtouris
        """
116 2d67ecbb Stavros Sachtouris
        r = self.get_server_details(server_id)
117 2d67ecbb Stavros Sachtouris
        try:
118 fab9b17f Stavros Sachtouris
            return r['attachments'][0]['firewallProfile']
119 2d67ecbb Stavros Sachtouris
        except KeyError:
120 24ff0a35 Stavros Sachtouris
            raise ClientError(
121 7d768bc6 Stavros Sachtouris
                'No Firewall Profile',
122 3dabe5d2 Stavros Sachtouris
                details='Server %s is missing a firewall profile' % server_id)
123 2d67ecbb Stavros Sachtouris
124 a1c50326 Giorgos Verigakis
    def set_firewall_profile(self, server_id, profile):
125 a1c50326 Giorgos Verigakis
        """Set the firewall profile for the public interface of a server
126 f5eac743 Stavros Sachtouris

127 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
128 f5eac743 Stavros Sachtouris

129 f5eac743 Stavros Sachtouris
        :param profile: (str) ENABLED | DISABLED | PROTECTED
130 cd295a1d Stavros Sachtouris

131 cd295a1d Stavros Sachtouris
        :returns: (dict) response headers
132 a1c50326 Giorgos Verigakis
        """
133 6a0b1658 Giorgos Verigakis
        req = {'firewallProfile': {'profile': profile}}
134 cd295a1d Stavros Sachtouris
        r = self.servers_post(server_id, 'action', json_data=req, success=202)
135 cd295a1d Stavros Sachtouris
        return r.headers
136 3dabe5d2 Stavros Sachtouris
137 a382ea56 Stavros Sachtouris
    def list_servers(self, detail=False, changes_since=None):
138 a382ea56 Stavros Sachtouris
        """
139 a382ea56 Stavros Sachtouris
        :param detail: (bool) append full server details to each item if true
140 a382ea56 Stavros Sachtouris

141 a382ea56 Stavros Sachtouris
        :param changes_since: (date)
142 a382ea56 Stavros Sachtouris

143 a382ea56 Stavros Sachtouris
        :returns: list of server ids and names
144 a382ea56 Stavros Sachtouris
        """
145 65a8b1da Stavros Sachtouris
        r = self.servers_get(detail=bool(detail), changes_since=changes_since)
146 fab9b17f Stavros Sachtouris
        return r.json['servers']
147 a382ea56 Stavros Sachtouris
148 c7083665 Stavros Sachtouris
    def list_server_nics(self, server_id):
149 f5eac743 Stavros Sachtouris
        """
150 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
151 f5eac743 Stavros Sachtouris

152 f5eac743 Stavros Sachtouris
        :returns: (dict) network interface connections
153 f5eac743 Stavros Sachtouris
        """
154 6f1ec797 Stavros Sachtouris
        r = self.servers_get(server_id, 'ips')
155 9a70c511 Stavros Sachtouris
        return r.json['attachments']
156 9a70c511 Stavros Sachtouris
        #return r.json['addresses']
157 1a85b14f Stavros Sachtouris
158 a1c50326 Giorgos Verigakis
    def get_server_stats(self, server_id):
159 f5eac743 Stavros Sachtouris
        """
160 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
161 f5eac743 Stavros Sachtouris

162 f5eac743 Stavros Sachtouris
        :returns: (dict) auto-generated graphs of statistics (urls)
163 f5eac743 Stavros Sachtouris
        """
164 6f1ec797 Stavros Sachtouris
        r = self.servers_get(server_id, 'stats')
165 6a0b1658 Giorgos Verigakis
        return r.json['stats']
166 3dabe5d2 Stavros Sachtouris
167 a1c50326 Giorgos Verigakis
    def list_networks(self, detail=False):
168 f5eac743 Stavros Sachtouris
        """
169 f5eac743 Stavros Sachtouris
        :param detail: (bool)
170 f5eac743 Stavros Sachtouris

171 f5eac743 Stavros Sachtouris
        :returns: (list) id,name if not detail else full info per network
172 f5eac743 Stavros Sachtouris
        """
173 6f1ec797 Stavros Sachtouris
        detail = 'detail' if detail else ''
174 6f1ec797 Stavros Sachtouris
        r = self.networks_get(command=detail)
175 fab9b17f Stavros Sachtouris
        return r.json['networks']
176 a1c50326 Giorgos Verigakis
177 a34888b4 Stavros Sachtouris
    def list_network_nics(self, network_id):
178 f5eac743 Stavros Sachtouris
        """
179 f5eac743 Stavros Sachtouris
        :param network_id: integer (str or int)
180 f5eac743 Stavros Sachtouris

181 f5eac743 Stavros Sachtouris
        :returns: (list)
182 f5eac743 Stavros Sachtouris
        """
183 a34888b4 Stavros Sachtouris
        r = self.networks_get(network_id=network_id)
184 fab9b17f Stavros Sachtouris
        return r.json['network']['attachments']
185 a34888b4 Stavros Sachtouris
186 24ff0a35 Stavros Sachtouris
    def create_network(
187 24ff0a35 Stavros Sachtouris
            self, name,
188 9d1db11e Stavros Sachtouris
            cidr=None, gateway=None, type=None, dhcp=False):
189 f5eac743 Stavros Sachtouris
        """
190 f5eac743 Stavros Sachtouris
        :param name: (str)
191 f5eac743 Stavros Sachtouris

192 f5eac743 Stavros Sachtouris
        :param cidr: (str)
193 f5eac743 Stavros Sachtouris

194 f5eac743 Stavros Sachtouris
        :param geteway: (str)
195 f5eac743 Stavros Sachtouris

196 f6f81cd3 Stavros Sachtouris
        :param type: (str) if None, will use MAC_FILTERED as default
197 f6f81cd3 Stavros Sachtouris
            Valid values: CUSTOM, IP_LESS_ROUTED, MAC_FILTERED, PHYSICAL_VLAN
198 f5eac743 Stavros Sachtouris

199 9d1db11e Stavros Sachtouris
        :param dhcp: (bool)
200 f5eac743 Stavros Sachtouris

201 f5eac743 Stavros Sachtouris
        :returns: (dict) network detailed info
202 e52840fa Stavros Sachtouris
        """
203 e52840fa Stavros Sachtouris
        net = dict(name=name)
204 e52840fa Stavros Sachtouris
        if cidr:
205 3dabe5d2 Stavros Sachtouris
            net['cidr'] = cidr
206 e52840fa Stavros Sachtouris
        if gateway:
207 3dabe5d2 Stavros Sachtouris
            net['gateway'] = gateway
208 f6f81cd3 Stavros Sachtouris
        net['type'] = type or 'MAC_FILTERED'
209 9d1db11e Stavros Sachtouris
        net['dhcp'] = True if dhcp else False
210 e52840fa Stavros Sachtouris
        req = dict(network=net)
211 6f1ec797 Stavros Sachtouris
        r = self.networks_post(json_data=req, success=202)
212 6a0b1658 Giorgos Verigakis
        return r.json['network']
213 a1c50326 Giorgos Verigakis
214 a1c50326 Giorgos Verigakis
    def get_network_details(self, network_id):
215 f5eac743 Stavros Sachtouris
        """
216 f5eac743 Stavros Sachtouris
        :param network_id: integer (str or int)
217 f5eac743 Stavros Sachtouris

218 f5eac743 Stavros Sachtouris
        :returns: (dict)
219 f5eac743 Stavros Sachtouris
        """
220 6f1ec797 Stavros Sachtouris
        r = self.networks_get(network_id=network_id)
221 6a0b1658 Giorgos Verigakis
        return r.json['network']
222 a1c50326 Giorgos Verigakis
223 a1c50326 Giorgos Verigakis
    def update_network_name(self, network_id, new_name):
224 f5eac743 Stavros Sachtouris
        """
225 f5eac743 Stavros Sachtouris
        :param network_id: integer (str or int)
226 f5eac743 Stavros Sachtouris

227 f5eac743 Stavros Sachtouris
        :param new_name: (str)
228 1b73b4c1 Stavros Sachtouris

229 1b73b4c1 Stavros Sachtouris
        :returns: (dict) response headers
230 f5eac743 Stavros Sachtouris
        """
231 6a0b1658 Giorgos Verigakis
        req = {'network': {'name': new_name}}
232 1b73b4c1 Stavros Sachtouris
        r = self.networks_put(network_id=network_id, json_data=req)
233 1b73b4c1 Stavros Sachtouris
        return r.headers
234 a1c50326 Giorgos Verigakis
235 a1c50326 Giorgos Verigakis
    def delete_network(self, network_id):
236 f5eac743 Stavros Sachtouris
        """
237 f5eac743 Stavros Sachtouris
        :param network_id: integer (str or int)
238 f5eac743 Stavros Sachtouris

239 1b73b4c1 Stavros Sachtouris
        :returns: (dict) response headers
240 1b73b4c1 Stavros Sachtouris

241 f5eac743 Stavros Sachtouris
        :raises ClientError: 421 Network in use
242 f5eac743 Stavros Sachtouris
        """
243 a34888b4 Stavros Sachtouris
        try:
244 1b73b4c1 Stavros Sachtouris
            r = self.networks_delete(network_id)
245 1b73b4c1 Stavros Sachtouris
            return r.headers
246 a34888b4 Stavros Sachtouris
        except ClientError as err:
247 a34888b4 Stavros Sachtouris
            if err.status == 421:
248 ec51b97c Stavros Sachtouris
                err.details = [
249 24ff0a35 Stavros Sachtouris
                    'Network may be still connected to at least one server']
250 08aad6db Stavros Sachtouris
            raise
251 a1c50326 Giorgos Verigakis
252 a1c50326 Giorgos Verigakis
    def connect_server(self, server_id, network_id):
253 f5eac743 Stavros Sachtouris
        """ Connect a server to a network
254 f5eac743 Stavros Sachtouris

255 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
256 f5eac743 Stavros Sachtouris

257 f5eac743 Stavros Sachtouris
        :param network_id: integer (str or int)
258 1b73b4c1 Stavros Sachtouris

259 1b73b4c1 Stavros Sachtouris
        :returns: (dict) response headers
260 f5eac743 Stavros Sachtouris
        """
261 6a0b1658 Giorgos Verigakis
        req = {'add': {'serverRef': server_id}}
262 1b73b4c1 Stavros Sachtouris
        r = self.networks_post(network_id, 'action', json_data=req)
263 1b73b4c1 Stavros Sachtouris
        return r.headers
264 a1c50326 Giorgos Verigakis
265 c7083665 Stavros Sachtouris
    def disconnect_server(self, server_id, nic_id):
266 f5eac743 Stavros Sachtouris
        """
267 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
268 f5eac743 Stavros Sachtouris

269 f5eac743 Stavros Sachtouris
        :param nic_id: (str)
270 b87ed277 Stavros Sachtouris

271 b87ed277 Stavros Sachtouris
        :returns: (int) the number of nics disconnected
272 f5eac743 Stavros Sachtouris
        """
273 2005b18e Stavros Sachtouris
        vm_nets = self.list_server_nics(server_id)
274 0e806947 Stavros Sachtouris
        num_of_disconnections = 0
275 24ff0a35 Stavros Sachtouris
        for (nic_id, network_id) in [(
276 2005b18e Stavros Sachtouris
                net['id'],
277 2005b18e Stavros Sachtouris
                net['network_id']) for net in vm_nets if nic_id == net['id']]:
278 a517ff50 Stavros Sachtouris
            req = {'remove': {'attachment': '%s' % nic_id}}
279 c2b5da2f Stavros Sachtouris
            self.networks_post(network_id, 'action', json_data=req)
280 0e806947 Stavros Sachtouris
            num_of_disconnections += 1
281 0e806947 Stavros Sachtouris
        return num_of_disconnections
282 a34888b4 Stavros Sachtouris
283 a34888b4 Stavros Sachtouris
    def disconnect_network_nics(self, netid):
284 f5eac743 Stavros Sachtouris
        """
285 f5eac743 Stavros Sachtouris
        :param netid: integer (str or int)
286 f5eac743 Stavros Sachtouris
        """
287 f5eac743 Stavros Sachtouris
        for nic in self.list_network_nics(netid):
288 a34888b4 Stavros Sachtouris
            req = dict(remove=dict(attachment=nic))
289 c2b5da2f Stavros Sachtouris
            self.networks_post(netid, 'action', json_data=req)
290 fd1f1d96 Stavros Sachtouris
291 7b2e4bf1 Stavros Sachtouris
    def _wait(
292 7b2e4bf1 Stavros Sachtouris
            self, item_id, current_status, get_status,
293 7b2e4bf1 Stavros Sachtouris
            delay=1, max_wait=100, wait_cb=None):
294 7b2e4bf1 Stavros Sachtouris
        """Wait for item while its status is current_status
295 f5eac743 Stavros Sachtouris

296 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
297 f5eac743 Stavros Sachtouris

298 7b2e4bf1 Stavros Sachtouris
        :param current_status: (str)
299 7b2e4bf1 Stavros Sachtouris

300 7b2e4bf1 Stavros Sachtouris
        :param get_status: (method(self, item_id)) if called, returns
301 7b2e4bf1 Stavros Sachtouris
            (status, progress %) If no way to tell progress, return None
302 f5eac743 Stavros Sachtouris

303 f5eac743 Stavros Sachtouris
        :param delay: time interval between retries
304 f5eac743 Stavros Sachtouris

305 7b2e4bf1 Stavros Sachtouris
        :param wait_cb: if set a progress bar is used to show progress
306 f5eac743 Stavros Sachtouris

307 7b2e4bf1 Stavros Sachtouris
        :returns: (str) the new mode if successful, (bool) False if timed out
308 fd1f1d96 Stavros Sachtouris
        """
309 7b2e4bf1 Stavros Sachtouris
        status, progress = get_status(self, item_id)
310 7b2e4bf1 Stavros Sachtouris
        if status != current_status:
311 7b2e4bf1 Stavros Sachtouris
            return status
312 c59aef27 Stavros Sachtouris
        old_wait = total_wait = 0
313 fd1f1d96 Stavros Sachtouris
314 7b2e4bf1 Stavros Sachtouris
        if wait_cb:
315 fd1f1d96 Stavros Sachtouris
            wait_gen = wait_cb(1 + max_wait // delay)
316 c59aef27 Stavros Sachtouris
            wait_gen.next()
317 fd1f1d96 Stavros Sachtouris
318 7b2e4bf1 Stavros Sachtouris
        while status == current_status and total_wait <= max_wait:
319 7b2e4bf1 Stavros Sachtouris
            if wait_cb:
320 7b2e4bf1 Stavros Sachtouris
                try:
321 7b2e4bf1 Stavros Sachtouris
                    for i in range(total_wait - old_wait):
322 fd1f1d96 Stavros Sachtouris
                        wait_gen.next()
323 7b2e4bf1 Stavros Sachtouris
                except Exception:
324 7b2e4bf1 Stavros Sachtouris
                    break
325 fd1f1d96 Stavros Sachtouris
            else:
326 7b2e4bf1 Stavros Sachtouris
                stdout.write('.')
327 7b2e4bf1 Stavros Sachtouris
                stdout.flush()
328 7b2e4bf1 Stavros Sachtouris
            old_wait = total_wait
329 7b2e4bf1 Stavros Sachtouris
            total_wait = progress or (total_wait + 1)
330 fd1f1d96 Stavros Sachtouris
            sleep(delay)
331 7b2e4bf1 Stavros Sachtouris
            status, progress = get_status(self, item_id)
332 fd1f1d96 Stavros Sachtouris
333 7b2e4bf1 Stavros Sachtouris
        if total_wait < max_wait:
334 c59aef27 Stavros Sachtouris
            if wait_cb:
335 c59aef27 Stavros Sachtouris
                try:
336 7b2e4bf1 Stavros Sachtouris
                    for i in range(max_wait):
337 c59aef27 Stavros Sachtouris
                        wait_gen.next()
338 c59aef27 Stavros Sachtouris
                except:
339 c59aef27 Stavros Sachtouris
                    pass
340 7b2e4bf1 Stavros Sachtouris
        return status if status != current_status else False
341 7b2e4bf1 Stavros Sachtouris
342 7b2e4bf1 Stavros Sachtouris
    def wait_server(
343 7b2e4bf1 Stavros Sachtouris
            self, server_id,
344 7b2e4bf1 Stavros Sachtouris
            current_status='BUILD',
345 7b2e4bf1 Stavros Sachtouris
            delay=1, max_wait=100, wait_cb=None):
346 7b2e4bf1 Stavros Sachtouris
        """Wait for server while its status is current_status
347 7b2e4bf1 Stavros Sachtouris

348 7b2e4bf1 Stavros Sachtouris
        :param server_id: integer (str or int)
349 7b2e4bf1 Stavros Sachtouris

350 7b2e4bf1 Stavros Sachtouris
        :param current_status: (str) BUILD|ACTIVE|STOPPED|DELETED|REBOOT
351 7b2e4bf1 Stavros Sachtouris

352 7b2e4bf1 Stavros Sachtouris
        :param delay: time interval between retries
353 7b2e4bf1 Stavros Sachtouris

354 7b2e4bf1 Stavros Sachtouris
        :param wait_cb: if set a progressbar is used to show progress
355 7b2e4bf1 Stavros Sachtouris

356 7b2e4bf1 Stavros Sachtouris
        :returns: (str) the new mode if succesfull, (bool) False if timed out
357 7b2e4bf1 Stavros Sachtouris
        """
358 7b2e4bf1 Stavros Sachtouris
359 7b2e4bf1 Stavros Sachtouris
        def get_status(self, server_id):
360 7b2e4bf1 Stavros Sachtouris
            r = self.get_server_details(server_id)
361 7b2e4bf1 Stavros Sachtouris
            return r['status'], (r.get('progress', None) if (
362 7b2e4bf1 Stavros Sachtouris
                            current_status in ('BUILD', )) else None)
363 7b2e4bf1 Stavros Sachtouris
364 7b2e4bf1 Stavros Sachtouris
        return self._wait(
365 7b2e4bf1 Stavros Sachtouris
            server_id, current_status, get_status, delay, max_wait, wait_cb)
366 7b2e4bf1 Stavros Sachtouris
367 7b2e4bf1 Stavros Sachtouris
    def wait_network(
368 7b2e4bf1 Stavros Sachtouris
            self, net_id,
369 7b2e4bf1 Stavros Sachtouris
            current_status='LALA', delay=1, max_wait=100, wait_cb=None):
370 7b2e4bf1 Stavros Sachtouris
        """Wait for network while its status is current_status
371 7b2e4bf1 Stavros Sachtouris

372 7b2e4bf1 Stavros Sachtouris
        :param net_id: integer (str or int)
373 7b2e4bf1 Stavros Sachtouris

374 7b2e4bf1 Stavros Sachtouris
        :param current_status: (str) PENDING | ACTIVE | DELETED
375 7b2e4bf1 Stavros Sachtouris

376 7b2e4bf1 Stavros Sachtouris
        :param delay: time interval between retries
377 7b2e4bf1 Stavros Sachtouris

378 7b2e4bf1 Stavros Sachtouris
        :param wait_cb: if set a progressbar is used to show progress
379 7b2e4bf1 Stavros Sachtouris

380 7b2e4bf1 Stavros Sachtouris
        :returns: (str) the new mode if succesfull, (bool) False if timed out
381 7b2e4bf1 Stavros Sachtouris
        """
382 7b2e4bf1 Stavros Sachtouris
383 7b2e4bf1 Stavros Sachtouris
        def get_status(self, net_id):
384 7b2e4bf1 Stavros Sachtouris
            r = self.get_network_details(net_id)
385 7b2e4bf1 Stavros Sachtouris
            return r['status'], None
386 7b2e4bf1 Stavros Sachtouris
387 7b2e4bf1 Stavros Sachtouris
        return self._wait(
388 7b2e4bf1 Stavros Sachtouris
            net_id, current_status, get_status, delay, max_wait, wait_cb)
389 03033b54 Stavros Sachtouris
390 03033b54 Stavros Sachtouris
    def get_floating_ip_pools(self):
391 03033b54 Stavros Sachtouris
        """
392 03033b54 Stavros Sachtouris
        :returns: (dict) {floating_ip_pools:[{name: ...}, ...]}
393 03033b54 Stavros Sachtouris
        """
394 03033b54 Stavros Sachtouris
        r = self.floating_ip_pools_get()
395 03033b54 Stavros Sachtouris
        return r.json
396 03033b54 Stavros Sachtouris
397 03033b54 Stavros Sachtouris
    def get_floating_ips(self):
398 03033b54 Stavros Sachtouris
        """
399 03033b54 Stavros Sachtouris
        :returns: (dict) {floating_ips:[
400 03033b54 Stavros Sachtouris
            {fixed_ip: ..., id: ..., instance_id: ..., ip: ..., pool: ...},
401 03033b54 Stavros Sachtouris
            ... ]}
402 03033b54 Stavros Sachtouris
        """
403 03033b54 Stavros Sachtouris
        r = self.floating_ips_get()
404 03033b54 Stavros Sachtouris
        return r.json
405 03033b54 Stavros Sachtouris
406 03033b54 Stavros Sachtouris
    def alloc_floating_ip(self, pool=None, address=None):
407 03033b54 Stavros Sachtouris
        """
408 03033b54 Stavros Sachtouris
        :param pool: (str) pool of ips to allocate from
409 03033b54 Stavros Sachtouris

410 03033b54 Stavros Sachtouris
        :param address: (str) ip address to request
411 03033b54 Stavros Sachtouris

412 03033b54 Stavros Sachtouris
        :returns: (dict) {
413 03033b54 Stavros Sachtouris
                fixed_ip: ..., id: ..., instance_id: ..., ip: ..., pool: ...
414 03033b54 Stavros Sachtouris
            }
415 03033b54 Stavros Sachtouris
        """
416 03033b54 Stavros Sachtouris
        json_data = dict()
417 03033b54 Stavros Sachtouris
        if pool:
418 03033b54 Stavros Sachtouris
            json_data['pool'] = pool
419 03033b54 Stavros Sachtouris
            if address:
420 03033b54 Stavros Sachtouris
                json_data['address'] = address
421 03033b54 Stavros Sachtouris
        r = self.floating_ips_post(json_data)
422 03033b54 Stavros Sachtouris
        return r.json['floating_ip']
423 03033b54 Stavros Sachtouris
424 03033b54 Stavros Sachtouris
    def get_floating_ip(self, fip_id):
425 03033b54 Stavros Sachtouris
        """
426 03033b54 Stavros Sachtouris
        :param fip_id: (str) floating ip id
427 03033b54 Stavros Sachtouris

428 03033b54 Stavros Sachtouris
        :returns: (dict)
429 03033b54 Stavros Sachtouris
            {fixed_ip: ..., id: ..., instance_id: ..., ip: ..., pool: ...},
430 03033b54 Stavros Sachtouris

431 03033b54 Stavros Sachtouris
        :raises AssertionError: if fip_id is emtpy
432 03033b54 Stavros Sachtouris
        """
433 03033b54 Stavros Sachtouris
        assert fip_id, 'floating ip id is needed for get_floating_ip'
434 03033b54 Stavros Sachtouris
        r = self.floating_ips_get(fip_id)
435 03033b54 Stavros Sachtouris
        return r.json['floating_ip']
436 03033b54 Stavros Sachtouris
437 03033b54 Stavros Sachtouris
    def delete_floating_ip(self, fip_id=None):
438 03033b54 Stavros Sachtouris
        """
439 03033b54 Stavros Sachtouris
        :param fip_id: (str) floating ip id (if None, all ips are deleted)
440 03033b54 Stavros Sachtouris

441 03033b54 Stavros Sachtouris
        :returns: (dict) request headers
442 03033b54 Stavros Sachtouris

443 03033b54 Stavros Sachtouris
        :raises AssertionError: if fip_id is emtpy
444 03033b54 Stavros Sachtouris
        """
445 03033b54 Stavros Sachtouris
        assert fip_id, 'floating ip id is needed for delete_floating_ip'
446 03033b54 Stavros Sachtouris
        r = self.floating_ips_delete(fip_id)
447 03033b54 Stavros Sachtouris
        return r.headers
448 03033b54 Stavros Sachtouris
449 9b47150e Stavros Sachtouris
    def attach_floating_ip(self, server_id, address):
450 03033b54 Stavros Sachtouris
        """Associate the address ip to server with server_id
451 03033b54 Stavros Sachtouris

452 03033b54 Stavros Sachtouris
        :param server_id: (int)
453 03033b54 Stavros Sachtouris

454 03033b54 Stavros Sachtouris
        :param address: (str) the ip address to assign to server (vm)
455 03033b54 Stavros Sachtouris

456 03033b54 Stavros Sachtouris
        :returns: (dict) request headers
457 03033b54 Stavros Sachtouris

458 03033b54 Stavros Sachtouris
        :raises ValueError: if server_id cannot be converted to int
459 03033b54 Stavros Sachtouris

460 03033b54 Stavros Sachtouris
        :raises ValueError: if server_id is not of a int-convertable type
461 03033b54 Stavros Sachtouris

462 03033b54 Stavros Sachtouris
        :raises AssertionError: if address is emtpy
463 03033b54 Stavros Sachtouris
        """
464 03033b54 Stavros Sachtouris
        server_id = int(server_id)
465 9b47150e Stavros Sachtouris
        assert address, 'address is needed for attach_floating_ip'
466 03033b54 Stavros Sachtouris
        r = self.servers_post(
467 03033b54 Stavros Sachtouris
            server_id, 'action',
468 03033b54 Stavros Sachtouris
            json_data=dict(addFloatingIp=dict(address=address)))
469 03033b54 Stavros Sachtouris
        return r.headers
470 03033b54 Stavros Sachtouris
471 9b47150e Stavros Sachtouris
    def detach_floating_ip(self, server_id, address):
472 03033b54 Stavros Sachtouris
        """Disassociate an address ip from the server with server_id
473 03033b54 Stavros Sachtouris

474 03033b54 Stavros Sachtouris
        :param server_id: (int)
475 03033b54 Stavros Sachtouris

476 03033b54 Stavros Sachtouris
        :param address: (str) the ip address to assign to server (vm)
477 03033b54 Stavros Sachtouris

478 03033b54 Stavros Sachtouris
        :returns: (dict) request headers
479 03033b54 Stavros Sachtouris

480 03033b54 Stavros Sachtouris
        :raises ValueError: if server_id cannot be converted to int
481 03033b54 Stavros Sachtouris

482 03033b54 Stavros Sachtouris
        :raises ValueError: if server_id is not of a int-convertable type
483 03033b54 Stavros Sachtouris

484 03033b54 Stavros Sachtouris
        :raises AssertionError: if address is emtpy
485 03033b54 Stavros Sachtouris
        """
486 03033b54 Stavros Sachtouris
        server_id = int(server_id)
487 9b47150e Stavros Sachtouris
        assert address, 'address is needed for detach_floating_ip'
488 03033b54 Stavros Sachtouris
        r = self.servers_post(
489 03033b54 Stavros Sachtouris
            server_id, 'action',
490 03033b54 Stavros Sachtouris
            json_data=dict(removeFloatingIp=dict(address=address)))
491 03033b54 Stavros Sachtouris
        return r.headers